Palavras-chave: C, C++, varargs, argumentos variáveis
Para escrever funções que aceitam quantidade variável de parâmetros, usa-se o mecanismo de stdargs do C. Para isso coloca-se “…” como último parâmetro na declaração da função e depois usa-se as funções de stdarg.h para acessar os valores passados quando a funcão é chamada.
-
É obrigatório a inclusão de pelo menos um parâmetro normal antes da parte variável. (ex.:
char *concat(const char *s, ...)) -
Qualquer tipo de valor pode ser passado como parâmetro, mas é impossível determinar em runtime o tipo dos valores que uma função recebeu. Porém é possível criar formas de o código que chama a funcão comunicar os tipos dos valores passados. Por exemplo, a função printf() determina os tipos dos parâmetros recebidos pela string de formatação (%s para char*, %i para int etc); a função
concat()no exemplo espera que todos os parâmetros recebidos sejam strings e assim por diante. -
O número de parâmetros recebido também não pode ser determinado explicitamente. É necessário usar artifícios adicionais como passar uma variável extra com o número de valores sendo passados, usar o valor NULL como indicador de último parâmetro ou derivar a quantidade de valores a partir da string de formatação, como no caso do printf() e similares.
Exemplo:
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
char *concat(const char *s, ...)
{
va_list args;
char *tmp;
char *res;
size_t len= strlen(s);
// pega um handle ao início da lista de parâmetros
va_start(args, s);
// calcula o tamanho total de todas as strings
// pega o próximo parâmetro da lista, até chegar no NULL
while ((tmp= va_arg(args, char*))) {
len+= strlen(tmp);
}
va_end(args);
res= malloc(len+1);
if (!res) return NULL;
// cria a string concatenada
strcpy(res, s);
va_start(args, s);
// pega o próximo parâmetro da lista, até chegar no NULL
while ((tmp= va_arg(args, char*))) {
strcat(res, tmp);
}
va_end(args);
return res;
}
int main()
{
char *s= concat("hello", " ", "world", "!!!!", NULL);
puts(s);
free(s);
return 0;
}
Se você quer usar macros com número de parâmetros variável (por exemplo, uma macro que chama uma função com stdargs), veja o post sobre o assunto.





Kojima: s/#include /#include /
Errr, maldito wordpress comendo os > e < dos comentários. Corrigindo:
Kojima: s/#include <stdargs>/#include <stdarg>/
Ops, obrigado pelo toque.
Morreu novamente ?
/me Tentando manter esse ótimo site ativo …. :)
Alfredo
Belo post, acho que complementa o anterior… agora usar strlen/strcat não é considerado ‘herético’? Heheheheh…
Vai uma dica de gcc:
pragma GCC poison strlen strcpy sprintf
Abraços
Adenilson
Adenilson: não vejo qual seria o problema com o strlen(). E se a gente já sabe que o tamanho do buffer é suficiente (como no código acima), também não vejo problema com strcat() e strcpy().
sprintf() até entendo, já que é difícil ter certeza que a string resultante realmente vá caber.