2009-08-11 4 views
6

J'écris une fonction en C qui prend un nombre variable d'arguments.C varargs - va_copy issues

size_t myprintf(char *fmt, ...); 

Jusqu'ici, tout va bien. J'ai décidé qu'il est préférable de faire les choses de la bonne façon et de faire une version qui prend des arguments variables, et une autre version qui prend un va_list.

size_t myprintf(char *fmt, ...); 
size_t myvprintf(char *fmt, va_list args); 

Pas si difficile à faire. Sauf my_vprintf() doit envoyer ses args à deux fonctions différentes (d'abord à snprintf() avec une longueur de 0 pour déterminer combien de place nous avons besoin, puis à sprintf() après que nous avons alloué autant de place). Je fais cela avec va_copy.

size_t myvprintf(char *fmt, va_list args) 
{ 
    va_list args2; 
    va_copy(args, args2); 
    // do stuff with args2 
    va_end(args2); 
    // do more stuff with args 
} 

Tout cela est bien et dandy, mais C99 est un peu mal implémenté. Je voudrais, si possible, que mon code fonctionne aussi en C89, et que je travaille avec autant de compilateurs et sur autant de plateformes que possible. J'ai actuellement cela après #include <stddef.h> mais avant tout code:

#ifndef va_copy 
# ifdef __va_copy 
# define va_copy(a,b) __va_copy(a,b) 
# else /* !__va_copy */ 
# define va_copy(a,b) ((a)=(b)) 
# endif /* __va_copy */ 
#endif /* va_copy */ 

Je suis porté à croire que ((a)=(b)) est peu fiable, et que je devrais peut-être utiliser memcpy() ou quelque chose de similaire, mais cela est encore au niveau de « Si vous ne supporte pas C99, j'espère que ça marche "plutôt que" Si vous ne supportez pas C99, ne craignez jamais "(c'est ce que je veux). Y a-t-il un bon moyen de contourner cette limitation? J'ai vu quelques solutions - va_list fonctions qui mangent un argument et recurse, en passant le va_list deux fois de sorte que deux copies séparées sont faites, etc. - mais je ne sais pas comment ils fonctionneraient bien (et la solution récursive a gagné » t faire si bien si je veux juste appeler vsnprintf(), maintenant, va-t-il?). Donc, je me tourne vers vous, utilisateur de StackOverFlow. Y at-il quelque chose que je peux faire de plus pour fournir la compatibilité C89, ou est-ce que les utilisateurs sans va_copy et __va_copy (il est vrai que peu et loin) vont juste devoir le sucer et le prendre?

+0

C'est en 2009. Pourquoi avez-vous encore besoin de la compatibilité C89? – stepancheg

+0

Parce que VC++ ne le supporte pas (et ne le supportera probablement pas). Et j'aime l'avoir. Je pense que c'est une bonne chose à avoir. –

+0

Je pense que MS est allé aussi loin que sur le disque pour dire qu'ils n'ont pas l'intention d'aller pour C99, sauf pour choisir et choisir les caractéristiques bizarres de ce que veulent leurs clients. – KTC

Répondre

3

(a)=(b) n'est pas fiable. Même en passant deux va_list est (la fonction publique serait une simple enveloppe) comme va_list peut être quelque chose comme:

typedef __va_list_impl va_list[1]; 

pour lequel faire un va_arg sur un sera modifier l'autre (je crois me souvenir que Solaris utiliser comme genre de chose, ah, les fenêtres de registre ...). Malheureusement, je ne connais aucun moyen sûr de faire ce que vous voulez.

+0

J'avais peur de ça. Tant pis.Je suppose que la meilleure chose à faire serait de changer mon hack-'' '' '' cup_copy' en '#error 'Obtenir un nouveau compilateur' ' –

+0

Dans ce cas particulier, l'affectation dans la macro va_copy échouerait, car vous ne pouvez pas assigner un tableau à un autre. – caf