2016-04-30 78 views
6

最近cppcheck在一些C代码引发错误,即具有以下结构:是否用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

难道是get_next(i)是一个宏,就像#define getnext(i)i ++? – gnasher729

+1

不,在这种情况下,它被定义为一个函数,cppcheck在没有任何修改的情况下给出这个代码上的错误。 – ideasman42

回答

8

订单被定义,因为它们之间有一个序列点。参见ISO/IEC 9899 6.5.17:

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

然后,他们给出一个清楚的例子:

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

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

+0

序列点不是C++的措辞吗? – Alex

+0

@Alex如果是,则C99从C++中借用它。我没有比C99更早的C规格进行比较。 –