Digamos que eu tenho uma função C que recebe um número variável de argumentos: Como posso chamar outra função que espera um número variável de argumentos dentro dela, passando todos os argumentos que entraram na primeira função?
Exemplo:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
c
variadic-functions
Vicent Marti
fonte
fonte
Respostas:
Para passar as elipses, você deve convertê-las em uma va_list e usar essa va_list em sua segunda função. Especificamente;
fonte
format_string
também dificilmente será útil, pois teria que fazer modificações in situ no fmt, o que certamente também não deveria ser feito. As opções incluiriam livrar-se de format_string completamente e usar vfprintf, mas isso faz suposições sobre o que format_string realmente faz, ou faz com que format_string retorne uma string diferente. Vou editar a resposta para mostrar a última.argptr
e chamadaargptr
, a única coisa segura a fazer é chamarva_end()
e reiniciarva_start(argptr, fmt);
para reinicializar. Ou você pode usarva_copy()
se o seu sistema suportar (C99 e C11 exigem; C89 / 90 não).Não há como chamar (por exemplo) printf sem saber quantos argumentos você está passando, a menos que queira fazer truques impertinentes e não portáteis.
A solução geralmente usada é sempre fornecer uma forma alternativa de funções vararg, assim
printf
como avprintf
queva_list
substitui a...
. As...
versões são apenas wrappers em volta dasva_list
versões.fonte
vsyslog
é compatível com POSIX .Funções variáveis podem ser perigosas . Aqui está um truque mais seguro:
fonte
#define callVardicMethodSafely(values...) ({ values *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })
No magnífico C ++ 0x, você pode usar modelos variados:
fonte
Você pode usar montagem embutida para a chamada de função. (neste código, presumo que os argumentos sejam caracteres).
fonte
Você pode tentar macro também.
fonte
Embora você possa resolver passar o formatador armazenando-o no buffer local primeiro, mas isso precisa ser empilhado e pode ser um problema para resolver. Eu tentei seguir e parece funcionar bem.
Espero que isto ajude.
fonte
A solução de Ross limpou um pouco. Só funciona se todos os argumentos forem ponteiros. Além disso, a implementação da linguagem deve oferecer suporte à exclusão da vírgula anterior, se
__VA_ARGS__
estiver vazia (o Visual Studio C ++ e o GCC).fonte
Digamos que você tenha uma função variável típica que você escreveu. Como pelo menos um argumento é necessário antes do variável
...
, você sempre deve escrever um argumento extra em uso.Ou você?
Se você agrupar sua função variável em uma macro, não precisará de um argumento anterior. Considere este exemplo:
Isso é obviamente muito mais conveniente, pois você não precisa especificar o argumento inicial todas as vezes.
fonte
Não tenho certeza se isso funciona para todos os compiladores, mas funcionou até agora para mim.
Você pode adicionar o ... ao inner_func () se quiser, mas não precisa. Funciona porque o va_start usa o endereço da variável especificada como ponto de partida. Nesse caso, estamos fazendo referência a uma variável em func (). Portanto, ele usa esse endereço e lê as variáveis depois na pilha. A função inner_func () está lendo o endereço da pilha de func (). Portanto, ele só funciona se as duas funções usarem o mesmo segmento de pilha.
As macros va_start e va_arg geralmente funcionarão se você fornecer algum var como ponto de partida. Então, se você quiser, pode passar ponteiros para outras funções e usá-las também. Você pode criar suas próprias macros com bastante facilidade. Tudo o que as macros fazem é digitar endereços de memória. No entanto, fazê-los funcionar para todos os compiladores e convenções de chamada é irritante. Portanto, geralmente é mais fácil usar os que acompanham o compilador.
fonte