C, C++: Funções com número variável de parâmetros (stdargs)

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.

This entry was posted in C, CPP. Bookmark the permalink.

6 Responses to C, C++: Funções com número variável de parâmetros (stdargs)

  1. Ademar Reis says:

    Kojima: s/#include /#include /

  2. Ademar Reis says:

    Errr, maldito wordpress comendo os > e < dos comentários. Corrigindo:

    Kojima: s/#include <stdargs>/#include <stdarg>/

  3. Ops, obrigado pelo toque.

  4. cezeiro says:

    Morreu novamente ?
    /me Tentando manter esse ótimo site ativo …. :)

  5. Adenilson Cavalcanti says:

    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

  6. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *