逗号运算符的评估顺序和 C 中的赋值是可预测的吗?
Is the order of evaluation with comma operator & assignment in C predictable?
最近 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`
虽然可以更改代码以消除警告,但顺序真的未定义吗?
顺序是确定的,因为它们之间有一个顺序点。见 ISO/IEC 9899 6.5.17:
The left operand of a comma operator is evaluated as a void
expression; there is a sequence point after its evaluation. Then
the right operand is evaluated; the result has its type and value. 95)
If an attempt is made to modify the result of a comma operator or to
access it after the next sequence point, the behavior is undefined.
然后他们给出了一个明确的例子:
In the function call
f(a, (t=3, t+2), c)
the function has three
arguments, the second of which has the value 5.
我不完全确定为什么 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`
虽然可以更改代码以消除警告,但顺序真的未定义吗?
顺序是确定的,因为它们之间有一个顺序点。见 ISO/IEC 9899 6.5.17:
The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value. 95) If an attempt is made to modify the result of a comma operator or to access it after the next sequence point, the behavior is undefined.
然后他们给出了一个明确的例子:
In the function call
f(a, (t=3, t+2), c)
the function has three arguments, the second of which has the value 5.
我不完全确定为什么 CppCheck 会标记它。