在以下C程序中,我收到警告:
warning #2030: '=' used in a conditional expression.
究竟是什么问题,我该如何避免这个?迭代变量参数的正确方法是什么?
#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;
}
你做的是惯用的,如果有点丑陋C.
但是,为了说服编译器您知道自己在做什么,可以将赋值包装到另外一组括号中:
while((arg = va_arg(ap, int)))
那应该照顾警告。
更新:
在赋值周围添加括号似乎并没有在使用(PellesC)的C99编译器中抑制警告。 - 加里威洛比
什么,它没有?然后你需要让测试更加明确:
while((arg = va_arg(ap, int)) != 0)
应该做的伎俩。它也可以被认为更具可读性。
你会问“我有点丑陋”。
从使用其他语言开始,我习惯于在测试和修改之间进行明确的分离。你正在测试一个值的while
,但同时产生副作用(即在下一个参数中读取)。正如我所说,这被认为是很正常的,因为很多C程序员都这样做,所以在C语言中是“惯用的”;我认为K&R甚至有类似代码的例子。
根据个人喜好,我可能会将其重写为:
while (1) {
arg = va_arg(ap, int);
if (!arg) break;
...
}
这清楚地将赋值与测试分开,并使循环独立于(可能)无限循环。很多人会认为我的代码更难看;正如我所说,这是个人偏好的问题。
警告是关于:
while(arg = va_arg(ap, int))
并且说“你确定你不是故意的:”
while(arg == va_arg(ap, int))
在这种情况下,你不是这样,你可以通过说:
while( (arg = va_arg(ap, int)) )
但是,您的代码仍然无效。如果不以某种方式提供由elipsis表示的参数数量,则无法使用可变参数函数。例如,printf使用%符号执行此操作:
printf(“%s%d%p”,x,y,z);
意味着有三个参数由elpisis表示。
在您的情况下,您可以使用零作为整数列表中的终止值 - 这就是您的循环所暗示的。
将while(arg = va_arg(ap, int))
改为while((arg = va_arg(ap, int)))
。
引发警告是因为您在一个语句中分配和检查赋值的值。
编写函数的另一种方法:
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;
}
它摆脱了(无用的)第二个命名参数,并将参数指针的增量移出循环条件。
示例代码
#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;
}
输出:1
3
6
10
15