【问题标题】:Variable argument lists in C functions - How to properly iterate through the arg list?C 函数中的变量参数列表 - 如何正确遍历 arg 列表?
【发布时间】:2026-01-24 02:25:01
【问题描述】:

在以下 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/…
  • 好点!但这不会影响问题。你的宏虽然不错,但显然是更好的选择!

标签: c function variables arguments


【解决方案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

      【讨论】: