Muitas linguagens suportam funções variárias, aliás de forma bem simples. Python usa o operador
*
para indicar quantidade variável de parâmetros, Lua usa o operador ...
e Common Lisp o operador &rest
.Outras linguagens podem ser ainda mais simples, como por exemplo Perl, onde toda função é variária e os parâmetros são recebidos na lista
@_
, tradicionalmente capturados por shift
.Já Java não suporta funções verdadeiramente variárias devido a sua limitação forçada de tipagem, no entanto é possível simular com o uso de
Object
e casting («vazamento» na falta de uma tradução melhor):void myFunction(Object... args) {
// Código do método
…
}
Funções variárias em C/C++
C/C++ usa o cabeçalho
stdarg.h
para suporte a funções variárias.O exemplo apresentado na Wikipédia é bastante simples: uma função
printargs
que recebe uma quantidade arbitrária de números inteiros, encerrando com -1 (ou qualquer número negativo em nosso exemplo), e os exibe na saída padrão.Precisamos incluir dois cabeçalhos em C++,
cstdarg
para suporte a funções variária e cstdio
para exibir o resultado:#include <cstdio>
#include <cstdarg>
Ou, em C:
#include <stdio.h>
#include <stdarg.h>
A assinatura da função fica assim:
void printargs(int arg1, ...) {
Para acesso aos parâmetros múltiplos é usado um objeto
va_list
: va_list args;
A função
va_start()
inicializa o objeto. Ela recebe dois parâmetros: o objeto va_list
e o nome do último argumento antes da lista: va_start(args, arg1);
Portanto é preciso haver pelo menos um argumento antes da lista variável. Podemos então exibir o primeiro parâmetro, recebido no argumento
arg1
: printf("%d", arg1);
A função
va_arg()
retorna o argumento seguinte. Ela recebe como parâmetros o objeto va_list
e o tipo do parâmetro da lista a ser recuperado.O tipo precisar ser plenamente promovido, ou seja, ponteiro, inteiro, ponto flutuante ou precisão dupla. Outros tipos, como
char
precisam sofrer casting, como por exemplo (não faz parte do código de printargs
):char c = static_cast<char>(va_arg(va, int));
Continuando o código, podemos agora reiterar sobre os resultados de
va_arg()
até encontrarmos o valor de parada negativo: int arg;
while((arg = va_arg(args, int)) >= 0)
printf(" %d", arg);
Após o fim da reiteração dos parâmetros obtidos do objeto
va_list
através de va_arg()
, é preciso encerrar o objeto: va_end(arg);
printf("\n");
}
Caso você queira restringir o formato de entrada da função, isso é possível usando
__attribute__
em sua declaração. Por exemplo, se a função log()
recebe o nível de log como primeiro parâmetro, uma string de formatação como segundo parâmetro (2
) e os parâmetros variáveis a partir do terceiro (3
), com formato similar ao da função printf()
, isso é feito com a seguinte assinatura:extern void
log(int level, cons char *fmt, ...)
__attribute__((format(printf, 2, 3)));
As opções para
format()
são printf
, scanf
, strftime
e strfmon
. Veja Declaring Attributes of Functions da documentação do GCC.[]'s
Cacilhas, La Batalema
¹Aridade: em Matemática é o número de operandos de uma função.