O que exatamente é va_end para? É sempre necessário chamá-lo?
-
06-09-2019 - |
Pergunta
va_end
-. Macro para reporarg_ptr
Depois de acessar uma lista de argumentos variável, o ponteiro arg_ptr
geralmente é redefinir com va_end()
. Eu entendo que é necessário se você quiser re-iterate a lista, mas é realmente necessário se você não está indo? É apenas boas práticas, como a regra de "ter sempre um default:
em sua switch
"?
Solução
va_end
é usado para fazer a limpeza. Você não quer esmagar a pilha, não é?
De man va_start
:
va_end ()
Cada chamada de va_start () tem de ser compensada por uma correspondente invocação de va_end () na mesma função. Após a va_end chamada (ap) a ap variável é indefinido. Vários percursos da lista, cada enquadradas por va_start () e va_end () são possíveis. va_end () pode ser uma macro ou uma função.
Observe a presença da palavra deve .
A pilha pode ser corrompido porque você não sabe o que está fazendo va_start()
. As macros va_*
são feitos para serem tratadas como caixas pretas. Cada compilador em cada plataforma pode fazer o que quiser lá. Pode não fazer nada, ou pode fazer muita coisa.
Alguns ABIs passar os primeiros argumentos em registos, eo restante na pilha. A va_arg()
pode haver mais complicado. Você pode olhar para cima como uma determinada aplicação não varargs, o que pode ser interessante, mas em escrever código portátil que você deve tratá-los como operações opacos.
Outras dicas
No Linux x86-64 apenas um percurso pode ser feito sobre uma variável va_list
. Para fazer mais traversals tem que ser copiado usando va_copy
primeiro. man va_copy
explica os detalhes:
va_copy ()
Uma implementação óbvia teria um va_list ser um ponteiro para a quadro de pilha da função variádica. Em tal configuração um (de longe a mais comum) não parece nada contra uma atribuição
va_list aq = ap;
Infelizmente, existem também sistemas que tornam uma matriz de ponteiros (Comprimento de 1), e existe uma necessidade
va_list aq; *aq = *ap;
Finalmente, em sistemas onde os argumentos são passados ??nos registos, pode ser necessária para va_start () para alocar memória, armazenar os argumentos lá, e também uma indicação de que argumento é próximo, de modo que va_arg () lata percorrer a lista. Agora va_end () pode liberar a memória alocada novamente. Para acomodar esta situação, C99 adiciona um va_copy macro (), então que a atribuição acima pode ser substituído por
va_list aq; va_copy(aq, ap); ... va_end(aq);
Cada invocação de va_copy () deve ser acompanhada por uma invoca- correspondente ção de va_end () na mesma função. Alguns sistemas que não fornecem va_copy () tem __va_copy em vez disso, uma vez que era o nome usado na projecto de proposta.
Nos "parâmetros passados ??na pilha" comuns implementação, acredito va_end () é geralmente nada / vazia / null. No entanto, em plataformas que possuem esquemas menos tradicionais, torna-se necessário. É uma "boa prática" para incluí-lo para permanecer plataforma neutra.