Linguagem C - Funções Variádicas

Artigo com o intuito de demonstrar o funcionamento de funções com número variável de argumentos. As famosas funções declaradas como func(int, ...).

[ Hits: 9.007 ]

Por: Enzo de Brito Ferber em 20/04/2016 | Blog: http://www.maximasonorizacao.com.br


Exemplos



Abaixo estão três funções variádicas simples. 'debug' é a única com alguma utilidade prática, mas, como veremos no final, podemos simplificar usando macros.

void foo(int n, ...)
{
   register int i;
   va_list ap;

   va_start(ap, n);

   for(i = 0; i < n; i++)
      printf(" Argumento %d: %d ", i + 1, va_arg(ap, int));

   va_end(ap);
}

A função foo é do tipo void, portanto não retorna nada. Toma um argumento do tipo inteiro chamado 'n'. Usamos esse parâmetro para dizer a função quantos são os outros argumentos. Começamos o escopo declarando uma variável 'i' que será usado como contador e nossa va_list para manipulação da lista de argumentos. Logo em seguida chamados va_start. Note que 'n' *não foi passado como ponteiro*, é apenas o nome. Se fosse um ponteiro, mesma coisa - só o nome. O compilador resolve o que fazer, nós só fornecemos o nome do último parâmetro conhecido.

O loop é bem simples. Para cada argumento (0 até n), imprimimos uma linha com o número do argumento e seu conteúdo. va_arg é chamada com ap e com int. Reparem que 'int' é a palavra reservada do tipo e não está entre aspas. Lembrem-se que va_arg é uma macro, até onde nos preocupamos. Isso também implica que *todos* os argumentos da função devem ser de tipo inteiro, caso contrário, va_arg fará uma conversão errada e tudo vai pro brejo...

Ao final, va_end(ap) para terminar nossa função. Abaixo, a função sum() tem um pouco mais de "utilidade", somando 'n' números. O princípio de funcionamento é idêntico ao de foo(), e você não terá dificuldades em analisá-la sozinho.

int sum(int n, ...)
{
   int i, sum = 0;
   va_list ap;

   va_start(ap, n);

   for(i = 0; i < n; i++)
      sum += va_arg(ap, int);

   va_end(ap);

   return sum;
}

Agora, debug(). Uma rotina que nos permite inserir linhas de código que imprimem mensagens diretamente em stderr.

#ifndef PRODUCTION
void debug(char *fmt, ...)
{
   va_list ap;
   va_start(ap, fmt);
   vfprintf(stderr, fmt, ap);
   va_end(ap);
}
#else
   #define debug(fmt, ...)
#endif

A diferença dessa função é que ela não manipula os argumentos diretamente. Ela apenas inicializa o ponteiro de sua lista de argumentos e passa esse ponteiro para outra função, vfprintf(). É uma forma bem interessante de utilizar as funções variádicas: como wrappers para outras funções variádicas da biblioteca.

Repare que com esse código podemos encher nosso projeto de chamadas a debug(), e quando o projeto for entregue, colocamos no Makefile a seguinte linha:

gcc -c debug.c -DPRODUCTION

E nossas mensagens de debugging nunca chegarão aos usuários... Mais a frente veremos como melhorar isso usando o pré-processador.

Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. stdarg.h
   3. Exemplos
   4. Expandindo horizontes
   5. MACROS Variádicas
   6. Conclusão e referências
Outros artigos deste autor

Linguagem C - Árvores Binárias

Linguagem C - Listas Duplamente Encadeadas

Leitura recomendada

lib cURL - Trabalhe com URLs em C

Mapear objetos em C

O Produtor e o Consumidor

openCertiface: Biométrica Facial em nuvem baseada em software livre

Algum humor e C++ Design Patterns (parte 2)

  
Comentários
[1] Comentário enviado por sacioz em 21/04/2016 - 10:15h

Gostei , com certeza vou dar um controldê na pag.inicial
Obrigado...:-))

[2] Comentário enviado por removido em 21/04/2016 - 18:14h

Muito bom. Vou guardar como referência.

----------------------------------------------------------------------------------------------------------------
# apt-get purge systemd (não é prá digitar isso!)

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden

[3] Comentário enviado por EnzoFerber em 30/04/2016 - 12:49h

Muito obrigado, @sacioz e @listeiro_037.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts