C 函数中的变量参数列表 - 如何正确遍历 arg 列表?
Posted
技术标签:
【中文标题】C 函数中的变量参数列表 - 如何正确遍历 arg 列表?【英文标题】:Variable argument lists in C functions - How to properly iterate through the arg list? 【发布时间】:2010-12-31 19:04:52 【问题描述】:在以下 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;
【问题讨论】:
您的示例代码已损坏:如果arg == 0
则循环终止,但您从未向Sum()
提供0
参数;如果所有可选参数都具有相同的类型,最好传递一个数组而不是使用可变参数,并做一些宏魔术让它看起来不错:***.com/questions/1375474/variable-arity-in-c/…
好点!但这不会影响问题。你的宏虽然不错,但显然是更好的选择!
【参考方案1】:
你正在做的是惯用的,如果有点丑 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 测试中使用了偷偷摸摸的快捷方式。我目前正在阅读 K&R,整本书都充满了这样的巧妙小捷径。读完这本书后,我现在有点习惯了,实际上非常喜欢它。但是,它是一个很大的但是,它确实使代码更难阅读。我理解人们为什么同时使用这两种方法,而您的代码确实让事情变得更加清晰。 P.S.在赋值周围添加括号似乎不会抑制使用 (PellesC) 的 C99 编译器中的警告。 窍门很适合教科书。我更喜欢编写其他人容易理解的代码。即使我看起来有点防守编码员.. @Gary Willoughby:对失败的提示感到抱歉。我已经用我希望会更成功的内容更新了我的答案。 也可以使用for
-loop:for(arg = va_arg(ap, int); arg; arg = va_arg(ap, int)) ...
;这将避免警告,但由于代码重复而很难看【参考方案2】:
警告是关于:
while(arg = va_arg(ap, int))
并且在说“你确定你不是故意的:”
while(arg == va_arg(ap, int))
在这种情况下,你没有这样做,所以你可以说:
while( (arg = va_arg(ap, int)) )
但是,您的代码仍然无法运行。如果不以某种方式提供省略号表示的参数数量,就无法使用可变参数函数。例如,printf 使用 % 符号执行此操作:
printf("%s %d %p", x, y, z);
表示省略号表示三个参数。
在您的情况下,您可能可以使用零作为整数列表中的终止值 - 这就是您的循环所暗示的。
【讨论】:
他的代码确实使用零来终止整数列表,所以他需要像这样调用函数:Sum(1, 2, 4, 8, 0); 这不是我在上一段中所说的吗?【参考方案3】:将while(arg = va_arg(ap, int))
更改为while((arg = va_arg(ap, int)))
。
警告是因为您在一个语句中分配和检查分配的值。
【讨论】:
【参考方案4】:函数的另一种写法:
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;
它摆脱了(无用的)第二个命名参数,并将参数指针的增量移出循环条件。
【讨论】:
【参考方案5】:示例代码
#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
【讨论】:
以上是关于C 函数中的变量参数列表 - 如何正确遍历 arg 列表?的主要内容,如果未能解决你的问题,请参考以下文章