Funções com Lista Variável de Argumentos

por Fabio A. Mazzarino

Uma das primeiras funções que a maioria aprende em C é printf, mas pouca gente sabe como definir uma função como printf, que recebe uma quantidade de argumentos que depende do primeiro argumento. Para isso existe um conjunto de funções declaradas no arquivo stdarg.h (ou cstdarg).

Para declarar uma lista variável de argumentos é utilizada a declaração …, com uma condição: é necessário haver pelo menos um argumento. Dessa forma

int sum(...); /* invalido */
long sumint(int a, ...) /* válido */
double sumfloat(float a, float b, ...); /* válido */

Note a declaração de funções do stdio.h (ou cstdio):

int printf (const char * format, ...);
int fprintf (FILE * stream, const char * format, ...);

Vamos usar um exemplo, valor máximo de um conjunto de inteiros, por exemplo:

int maxint(unsigned n, ...) {
    va_list args;
    int max = INT_MIN;
    va_start(args, n);
    for (int ct = n; ct--; ) {
        int arg = va_arg(args, int);
        if (arg > max)
            max = arg;
    }
    va_end(args);
    return max;
}

Na função acima o primeiro parâmetro é a quantidade de inteiros que serão comparados, e os demais parâmetros, os números que serão comparados.

O tipo va_list é a estrutura de dados que armazena as informações sobre a lista variável de parâmetros. A função va_start inicializa a estrutura de dados, enquanto que a função va_end finaliza a estrutura de dados, garantindo que não haverá vazamento de memória. O segundo parâmetro de va_start é a variável do último argumento antes da lista variável de argumentos.

A função va_arg recupera iterativamente o valor do argumento, conforme o tipo definido no segundo parâmetro.

A utilização da função:

int max = maxint(5, 5, 9, 1, 15, 3);

É possível também utilizar um outro padrão, como por exemplo o número INT_MIN indicando o fim da lista de argumentos:

int maxint(int a, ...) {
    va_list args;
    int max = a;
    int arg = INT_MIN;
    va_start(args, a);
    do {
        arg = va_arg(args, int);
        if (arg != INT_MIN && arg > max)
            max = arg;
    } while (arg != INT_MIN);
    va_end(args);
    return max;
}

E nesse caso a utilização é um pouco diferente:

int max = maxint(5, 9, 1, 15, 3, INT_MIN);

Em ambos os casos o resultado será o mesmo.

Com poucas e simples funções, e uma declaração apropriada, é possível declarar uma função com uma lista variável de argumentos.