【问题标题】:Is the order of evaluation with comma operator & assignment in C predictable?C 中逗号运算符和赋值的评估顺序是否可预测?
【发布时间】:2016-08-25 07:14:30
【问题描述】:

最近 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`

虽然可以更改代码以消除警告,但顺序真的未定义吗?

【问题讨论】:

  • 会不会 get_next(i) 是一个宏,比如#define getnext(i) i++ ?
  • 不,在这种情况下它被定义为一个函数,cppcheck 在没有任何修改的情况下给出了这个代码的错误。

标签: c static-code-analysis cppcheck


【解决方案1】:

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

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

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

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

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

【讨论】:

  • @Alex 如果是,那么 C99 是从 C++ 借来的。我没有任何早于 C99 的 C 规范可供比较。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
  • 2018-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多