2010-01-02 4 views
5

Dans le programme C-je obtenir l'avertissement:Listes d'arguments variables dans les fonctions C - Comment parcourir correctement la liste d'arguments?

warning #2030: '=' used in a conditional expression.

Quel est le problème exactement et comment puis-je éviter cela? Quelle est la bonne façon de parcourir les arguments variables?

#include <stdio.h> 
#include <stdarg.h> 

int Sum(int a, int b, ...) 
{ 
    int arg; 
    int Sum = a + b; 

    va_list ap; 
    va_start(ap, b); 

    while(arg = va_arg(ap, int)) 
    { 
     Sum += arg; 
    } 
    va_end(ap); 

    return Sum; 
} 

int main(int argc, char *argv[]) 
{ 
    printf("%d\n", Sum(1, 2, 4, 8)); 

    return 0; 
} 
+0

votre exemple de code est cassé: la boucle se termine si 'arg == 0', mais vous ne fournissez jamais un argument' 0' à 'Sum()'; Si tous les arguments optionnels ont le même type, il est préférable de passer un tableau au lieu d'utiliser varargs et de faire un peu de magie pour le rendre joli: http://stackoverflow.com/questions/1375474/variable-arity-in-c/ 1375636 # 1375636 – Christoph

+0

Bon point! mais cela n'affecte pas la question. Votre macro est sympa et un meilleur choix évident! –

Répondre

5

Ce que vous faites est idiomatiques, si légèrement laid C.

Afin de convaincre le compilateur que vous savez ce que vous faites, cependant, vous pouvez envelopper l'affectation dans un ensemble supplémentaire de parenthèses:

while((arg = va_arg(ap, int))) 

Cela devrait prendre en compte l'avertissement.

Mise à jour:

ajoutant entre parenthèses autour de la mission ne semble pas supress l'avertissement du compilateur C99 im en utilisant (PellesC). - Gary Willoughby

Qu'est-ce qui n'a pas fonctionné? Ensuite, vous devez rendre le test un peu plus explicite:

while((arg = va_arg(ap, int)) != 0) 

devrait faire l'affaire. On pourrait aussi soutenir qu'il est légèrement plus lisible.


Vous allez me demander ce que je veux dire par "légèrement moche". De travailler avec d'autres langues, j'ai l'habitude d'avoir une séparation claire entre tester et modifier. Vous faites un test dans ce while d'une valeur, mais en même temps vous créez un effet secondaire (lire dans l'argument suivant). Comme je l'ai dit, cela est considéré comme assez normal, voire "idiomatique" en C parce que beaucoup de programmeurs en C le font; Je pense qu'il ya même des exemples de code similaire dans K & R.

Par préférence personnelle, je serais probablement réécrire ce que:

while (1) { 
    arg = va_arg(ap, int); 
    if (!arg) break; 
    ... 
} 

Cela sépare clairement l'affectation du test, et laisse la boucle autonome comme une boucle (potentiellement) infinie. Beaucoup de gens considéreraient mon code plus laid; Comme je l'ai dit, c'est une question de préférence personnelle.

+0

Vous avez raison, j'ai utilisé un raccourci sournois dans le test de temps. Je suis en train de lire K & R et le livre entier est plein de petits raccourcis intelligents comme celui-ci. Après avoir lu le livre, je commence à m'y habituer et je l'aime vraiment. Mais, et c'est un gros mais, cela rend le code un peu plus difficile à lire. Je comprends pourquoi les gens utilisent les deux et votre code rend les choses plus claires. –

+0

P.S. l'ajout de parenthèses autour de l'affectation ne semble pas supprimer l'avertissement dans le compilateur C99 im (PellesC). –

+0

Les astuces sont bonnes pour les manuels. Je préférerais écrire du code facilement compréhensible par les autres. Même si j'ai l'air un peu codeur défensif .. – Jack

0

modifiez while(arg = va_arg(ap, int)) à while((arg = va_arg(ap, int))).

L'avertissement est dû au fait que vous affectez et vérifiez la valeur de l'affectation dans une instruction.

1

L'avertissement est sur:

while(arg = va_arg(ap, int)) 

et dit « êtes-vous sûr de ne pas dire: »

while(arg == va_arg(ap, int)) 

Dans ce cas, vous ne l'avez pas, vous pouvez supress il en disant:

while((arg = va_arg(ap, int))) 

Cependant, votre code ne fonctionnera toujours pas. Il n'y a aucun moyen d'utiliser des fonctions variadiques sans fournir en quelque sorte le nombre de paramètres représentés par les elipsis. Par exemple, printf utilise le signe%:

printf ("% s% d% p", x, y, z);

signifie qu'il y a trois paramètres représentés par l'elpisis.

Dans votre cas, vous pouvez probablement utiliser zéro comme valeur de fin dans la liste des entiers - c'est ce que votre boucle implique.

+0

Son code utilise zéro pour terminer la liste des entiers, il doit donc appeler la fonction comme ceci: Somme (1, 2, 4, 8, 0); –

+0

N'est-ce pas ce que j'ai dit dans mon dernier paragraphe? –

0

Encore une autre façon d'écrire la fonction:

int Sum(int a, ...) 
{ 
    int sum = 0; 
    int current = a; 

    va_list args; 
    va_start(args, a); 

    for(; current; current = va_arg(args, int)) 
     sum += current; 

    va_end(args); 

    return sum; 
} 

Il se débarrasser de la (inutile) deuxième paramètre nommé et déplace l'incrément du pointeur argument de la condition de la boucle.

Questions connexes