views:

316

answers:

4

In the following C program i get the warning:

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

What exactly is the problem and how do i avoid this? What is the correct way to iterate through the variable arguments?

#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;
}
+5  A: 

What you're doing is idiomatic, if slightly ugly C.

In order to convince the compiler you know what you're doing, though, you could wrap the assignment into an additional set of parentheses:

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

That should take care of the warning.

Update:

adding parenthesis around the assignment doesn't seem to supress the warning in the C99 compiler im using (PellesC). – Gary Willoughby

What, it didn't? Then you need to make the test a little more explicit:

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

should do the trick. It could also be argued to be slightly more readable.


You're going to ask me what I mean by "slightly ugly."

From working with other languages, I'm used to having a clear separation between testing and modifying. You're doing a test in that while of a value, but at the same time creating a side effect (namely reading in the next argument). As I said, this is considered pretty normal, yea "idiomatic" in C because a lot of C programmers do this; I think there are even examples of similar code in K&R.

By personal preference, I'd probably rewrite this as:

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

This clearly separates the assignment from the test, and lets the loop stand alone as a (potentially) infinite loop. Many people would consider my code more ugly; as I said, it's a matter of personal preference.

Carl Smotricz
Gary Willoughby
P.S. adding parenthesis around the assignment doesn't seem to supress the warning in the C99 compiler im using (PellesC).
Gary Willoughby
Tricks are good for textbook. I would prefer to write code which is easily understandable by others. Even if I look bit defensive coder..
Jack
@Gary Willoughby: Sorry about the failing tip. I've updated my answer with what I hope will be more successful.
Carl Smotricz
one could use a `for`-loop as well: `for(arg = va_arg(ap, int); arg; arg = va_arg(ap, int)) {...}`; this will avoid the warning, but is ugly because of code duplication
Christoph
@Carl Smotricz: That did it. ;) Thanks for your post.
Gary Willoughby
A: 

change while(arg = va_arg(ap, int)) to while((arg = va_arg(ap, int))).

The warning is caused because you are assigning and checking the value of the assignment in one statement.

Autopulated
+1  A: 

The warning is about:

while(arg = va_arg(ap, int))

and is saying "are you sure you didn't mean:"

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

In this case, you didn't so you can supress it by saying:

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

However, your code still won't work. There is no way to use variadic functions without supplying somehow the number of parameters represented by the elipsis. For example, printf does this using the % sign:

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

means there are three parameters represented by the elpisis.

In your case, you can probably use zero as a terminating value in the list of integers - that's what your loop implies.

anon
His code does use zero to terminate the list of integers so he needs to call the function like this: Sum(1, 2, 4, 8, 0);
Richard Pennington
Isn't that what I said in my last para?
anon
A: 

Yet another way to write the function:

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

It get's rid of the (useless) second named parameter and moves the increment of the argument pointer out of the loop condition.

Christoph