2010-01-02 6 views
5

En el siguiente programa en C me da la advertencia:Listas de argumentos de variables en funciones C - ¿Cómo iterar correctamente a través de la lista arg?

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

¿Cuál es exactamente el problema y cómo evitar esto? ¿Cuál es la forma correcta de iterar a través de los argumentos 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

su código de ejemplo está roto: el ciclo termina si 'arg == 0', pero nunca proporciona un argumento' 0' a 'Sum()'; si todos los argumentos opcionales tienen el mismo tipo, es mejor pasar una matriz en lugar de usar varargs y hacer algo de magia macro para que se vea bien: http://stackoverflow.com/questions/1375474/variable-arity-in-c/ 1375636 # 1375636 – Christoph

+0

¡Buen punto! pero no afecta la pregunta. ¡Su macro es agradable y una mejor opción obvia! –

Respuesta

5

Lo que está haciendo es idiomático, aunque un poco fea C.

Con el fin de convencer al compilador que sabes lo que estás haciendo, sin embargo, usted podría envolver la asignación en un conjunto adicional de paréntesis:

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

Eso debería ocuparse de la advertencia.

Actualización:

añadiendo paréntesis alrededor de la asignación no parece suprimir la advertencia en el compilador C99 im usando (PellesC). - Gary Willoughby

¿Qué, no? A continuación, debe hacer que la prueba sea un poco más explícita:

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

debería hacer el truco. También podría argumentarse que es un poco más legible.


Me preguntará lo que quiero decir con "levemente feo".

Al trabajar con otros idiomas, estoy acostumbrado a tener una clara separación entre probar y modificar. Está haciendo una prueba en ese while de un valor, pero al mismo tiempo crea un efecto secundario (es decir, leyendo en el siguiente argumento). Como dije, esto se considera bastante normal, sí, "idiomático" en C porque muchos programadores C lo hacen; Creo que hay incluso ejemplos de código similar en K & R.

por preferencia personal, probablemente me reescribir esto como:

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

Esto separa claramente la asignación de la prueba, y permite que el bucle stand alone como un bucle (potencialmente) infinito. Mucha gente consideraría mi código más feo; como dije, es una cuestión de preferencia personal.

+0

Tienes razón, he usado un atajo furtivo en la prueba de tiempo. Actualmente estoy leyendo K & R y todo el libro está lleno de pequeños atajos inteligentes como este. Después de leer el libro me estoy acostumbrando a estos y me gusta bastante. Pero, y es un gran pero, hace que el código sea un poco más difícil de leer. Entiendo por qué la gente usa ambos y tu código de hecho deja las cosas más claras. –

+0

P.S. agregar paréntesis alrededor de la asignación no parece suprimir la advertencia en el compilador C99 que estoy usando (PellesC). –

+0

Los trucos son buenos para los libros de texto. Prefiero escribir un código que sea fácilmente comprensible para otros. Incluso si me veo un poco codificador defensivo ... – Jack

0

cambio while(arg = va_arg(ap, int)) a while((arg = va_arg(ap, int))).

La advertencia se produce porque está asignando y verificando el valor de la asignación en una declaración.

1

La advertencia es acerca de:

while(arg = va_arg(ap, int)) 

y está diciendo "¿está seguro de que no quería decir:"

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

En este caso, que no se puede suprimir de manera que diciendo:

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

Sin embargo, su código todavía no funcionará. No hay forma de usar funciones variadas sin proporcionar de alguna manera el número de parámetros representados por elipsis. Por ejemplo, printf hace esto usando el signo%:

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

significa que hay tres parámetros representados por el elipisis.

En su caso, probablemente pueda usar cero como valor de terminación en la lista de enteros, eso es lo que implica su bucle.

+0

Su código usa cero para terminar la lista de enteros, por lo que necesita llamar a la función de esta manera: Suma (1, 2, 4, 8, 0); –

+0

¿No es eso lo que dije en mi último párrafo? –

0

Sin embargo, otra manera de escribir la función:

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; 
} 

Es deshacerse de la (inútil) segundo parámetro llamado obtener y mueve el incremento del puntero del argumento de la condición del bucle.

Cuestiones relacionadas