是逗号运算符和评估的评估顺序。 C中的赋值可预测吗?

时间:2016-04-30 02:15:41

标签: c static-code-analysis cppcheck

最近cppcheck在一些C代码中引发了一个错误,它有结构:

((void)(value_prev = value), value = new_value())

在大多数情况下,这可以拆分为2行,但在某些情况下,这在单个语句中很有用。

在实践中,我发现这适用于流行的编译器(GCC / Clang / MSVC),它们不会发出任何警告(即使警告级别设置为最高)

示例代码:

#include <stdio.h>

int get_next(int i);

int main() {
    int i = 0, i_prev = 10;
    do {
        printf("%d\n", i);
    } while ((void)(i_prev = i),
             (i = get_next(i)) != 10);
}

CppCheck 1.73 (撰写本文时最新)使用此代码时出错:

(error) Expression '(void)(i_prev=i),(i=get_next(i))!=10'
depends on order of evaluation of side effects`

虽然代码可以更改为安静警告,但订单是否真的未定义?

1 个答案:

答案 0 :(得分:8)

定义了顺序,因为它们之间有一个序列点。见ISO / IEC 9899 6.5.17:

  

逗号运算符的左操作数被评估为void   表达;评估后有一个序列点。然后   正确的操作数被评估;结果有它的类型和价值。 95)   如果尝试修改逗号运算符的结果或   在下一个序列点之后访问它,行为是未定义的。

然后他们给出一个明确的例子:

  

在功能调用中   f(a, (t=3, t+2), c)
  功能有三个   参数,其中第二个值为5。

我不完全确定为什么CppCheck会标记它。