Remplir une liste va

Est-il possible de créer une liste va_list partir de zéro? J’essaie d’appeler une fonction qui prend un va_list comme paramètre:

 func(void **entry, int num_args, va_list args, char *key); 

… à partir d’une fonction qui ne prend pas un nombre variable d’arguments. Le seul moyen auquel je puisse penser est de créer une fonction intermédiaire qui prend varargs puis transmet son va_list, ce qui est assez stupide:

 void stupid_func(void **entry, char *key, int num_args, ...) { va_list args; va_start(args, num_args); func(entry, num_args, args, key); va_end(args); } 

Y a-t-il un meilleur moyen? Je ne peux pas changer la signature de func .

C’est une mauvaise idée car l’abstraction de va_list est là pour cacher quelques sortingstes détails spécifiques au compilateur / à l’architecture concernant les pointeurs de stack et autres. Et il est à peu près lié à la scope de la fonction une fois initialisée. Si vous remontez la stack et faites référence à une image précédente va_args hors de scope, les choses peuvent mal tourner. Vous pouvez les faire circuler mais …

attendre des insectes

Voir: http://lists.freebsd.org/pipermail/freebsd-amd64/2004-August/001946.html

Aussi checkout man (3) va_copy et ses amis pour une manipulation plus sûre des va_args et leur transmission.

IMHO les trucs va_args n’est pas très soigné. Dans le passé, j’ai traité cette question en initialisant des structures / des pointeurs opaques sur le tas, puis en utilisant l’arithmétique de pointeur pour exploiter les données. Mais ceci est un bidouillage et dépend des circonstances.

Je comprends et suis d’accord avec les avertissements d’Aiden – va_list et ses amis sont dangereux car ils cachent des conventions d’appel de bas niveau. Mais … dans cette situation, je pense que vous n’avez pas d’autre choix. Mettez la fonction static ... dans le fichier .c afin que personne d’autre ne puisse la voir, une sorte de proxy pour la fonction que vous devez appeler, testez-la et faites-la. Assurez-vous simplement de ne pas exposer les arguments variadiques tout au long de la chaîne d’appels.

Votre idée d’une fonction proxy qui crée la liste va_list est la bonne façon de le faire. Il n’est pas nécessaire que ce proxy ait une scope publique. Cependant, si vous trouvez que le proxy existe déjà. Par exemple, dans de nombreuses implémentations de bibliothèques, sprintf() n’est qu’un proxy pour vsprintf() .

À moins que vous ne souhaitiez lier votre code à un compilateur spécifique et à une plate-forme cible, il n’y a pas de meilleur moyen. Les noms définis dans servent à fournir une interface portable et cohérente pour prendre en charge l’access aux listes d’arguments variadiques. Le seul moyen portable d’implémenter et d’utiliser des fonctions variadiques consiste à utiliser cette interface.

Cela dit, il est possible de sacrifier la portabilité en dupliquant un cadre d’appel dans un tableau et en construisant à la main un va_list correctement. Le résultat ne sera jamais portable.

Un article de blog utile sur cocoawithlove suggère un moyen de simuler une liste va_list – il vous enferme dans un comportement spécifique du compilateur et de la plate-forme, comme indiqué par les autres bonnes réponses ici.

Votre stupid_func est un code C parfaitement valide, sinon comment appelleriez-vous vprintf et des fonctions similaires?

La bibliothèque glib utilise énormément ces wrappers. La spécification C99 elle-même a quelque chose de similaire dans les exemples. Extrait de la section 7.19.6.8 :

Ce qui suit montre l’utilisation de la fonction vfprintf dans une routine générale de rapport d’erreurs.

 #include  #include  void error(char *function_name, char *format, ...) { va_list args; va_start(args, format); // print out name of function causing error fprintf(stderr, "ERROR in %s: ", function_name); // print out remainder of message vfprintf(stderr, format, args); va_end(args) }