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.