Variable argument lists in C functions - How to properly iterate through the arg list?
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;
}
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.
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.
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.
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.
Example Code
#include <stdio.h>
#include <stdarg.h>
int add(int num, ...) {
va_list vaList;
int sum = 0;
va_start(vaList, num);
for (int i = 0; i < num; ++i) {
sum += va_arg(vaList, int);
}
va_end(vaList);
return sum;
}
int main() {
printf("%d\n", add(1, 1));
printf("%d\n", add(2, 1, 2));
printf("%d\n", add(3, 1, 2, 3));
printf("%d\n", add(4, 1, 2, 3, 4));
printf("%d\n", add(5, 1, 2, 3, 4, 5));
return 0;
}
Output: 1
3
6
10
15
精彩评论