2009-03-30 7 views
60

J'ai environ 30 fonctions variadiques. Chacun accepte un chemin comme argument final .: par exemplePassage d'une ellipse à une autre fonction variadique

bool do_foo(struct *f, int q, const char *fmt, ...) 

Dans chaque fonction, je dois vérifier que le format élargi est inférieure ou égale à une certaine taille. Donc, je me trouve copier/coller le même morceau de code pour vérifier combien de caractères vsnprintf() n'a pas imprimé, définir errno en conséquence et renflouer de l'écriture. Ce que je voudrais faire est d'écrire une fonction pour ce faire, qui retournerait une chaîne (étendue) allouée statiquement qui est connue pour être une taille sûre, ou une chaîne nouvellement initialisée en échec, qui pourrait être vérifiée par rapport à NULL . Les vérifications doivent également déterminer si la chaîne est un chemin absolu ou relatif, ce qui influe sur la taille sûre de la chaîne. C'est beaucoup de code en double et ça commence à sentir.

Existe-t-il un moyen de transmettre le contenu de l'elipsis de l'entrée de ma fonction à une autre fonction? Ou dois-je d'abord appeler va_start(), puis passer le va_list à la fonction d'assistance?

Edit:

Je ne suis pas du tout opposé à passer le va_list à l'aide, je voulais juste vous assurer que rien d'autre existait. Il me semble que le compilateur comprend où les arguments variés commencent, alors j'étais simplement curieux de savoir si je pouvais le faire passer.

+0

Y at-il une raison quelconque vous êtes défavorable à passer le va_list à l'aide? – ojblass

+0

J'ai dû faire des choses de même type mais j'ai dû enlever quelques args ... ce n'était pas un code agréable à maintenir. – ojblass

Répondre

63

Vous ne pouvez pas, vous pouvez uniquement transmettre les arguments en tant que va_list. Voir le comp.lang.c FAQ.

En général, si vous écrivez des fonctions variadiques (c.-à-d. Des fonctions qui prennent un nombre variable d'arguments) en C, vous devez écrire deux versions de chaque fonction: une qui prend une ellipse (...), et une qui prend un va_list. La version prenant une ellipse devrait appeler va_start, appeler la version en prenant un va_list, appeler va_end, et revenir. Il n'y a pas besoin de duplication de code entre les deux versions de la fonction, puisque l'une appelle l'autre.

+5

Serait bien si vous avez écrit le code. –

+0

Que dois-je faire si j'ai besoin de faire des choses avec 'va_list' deux fois? Normalement, je devrais appeler 'va_end' et' va_start' entre les usages (sinon c'est UB), mais je ne peux pas l'appeler dans une fonction qui prend 'va_list':' 'va_start' utilisé en fonction avec des arguments fixes' . –

+1

Nevermind, je l'ai compris - j'ai besoin d'utiliser 'va_copy' pour chaque utilisation ultérieure. –

0

Vous devez passer va_list à l'assistant.

+1

Cette réponse est très succincte pour être utile. Il devrait soit être étendu avec des détails utiles supplémentaires ou supprimé. – rjstelling

+0

@rjstelling J'ai trouvé cette réponse utile lorsque j'ai posé la question.Si vous remarquez, j'ai indiqué que j'ai fondamentalement acquiescé à passer la va_list, mais j'ai senti qu'il pourrait y avoir une façon différente de le faire. Andrew à peu près confirmé qu'il n'y en avait pas un (pas de magie de compilateur que je pourrais utiliser). Alors que d'autres réponses ont été approfondies, cela a suffisamment répondu à ma question. –

9

vous pouvez probablement utiliser des macros variadique - comme ceci:

#define FOO(...) do { do_some_checks; myfun(__VA_ARGS__); } while (0) 

NB! Les macros variadiques sont uniquement C99

+0

Je regardais ceux-là, ce qui me sauve d'avoir à ajouter un wrapper autour de la fonction qui fait l'écriture. –

+0

c99 ne pose aucun problème, mon programme est plutôt spécifique à gcc/linux –

-1

Je ne sais pas si cela aidera, vous pouvez accéder aux variables par référence. C'est une sorte de truc sournois, mais cela ne vous permettra malheureusement pas d'utiliser des ellipses dans la définition finale de la fonction.

#include <stdio.h> 

void print_vars(int *n) 
{ 
    int i; 
    for(i=0;i<=*n;i++) 
    printf("%X %d ", (int)(n+i), *(n+i)); 
    printf("\n"); 
} 

void pass_vars(int n, ...) 
{ 
    print_vars(&n); 
} 

int main() 
{ 
    pass_vars(4, 6, 7, 8, 0); 
    return 0; 
} 

Sur mon PC, il sorties

$ ./a.out 
BFFEB0B0 4 BFFEB0B4 6 BFFEB0B8 7 BFFEB0BC 8 BFFEB0C0 0 
+9

Non portable ... – aschepler