Order of evaluation
任何C运算符操作数的求值顺序,包括函数调用表达式中函数参数的求值顺序,以及任何表达式中子表达式的求值顺序都是未指定的(除非下文另有说明)。编译器可以按任意顺序对它们进行求值,并且在再次对同一表达式求值时可能选择不同的顺序。
C语言中不存在从左到右或从右到左求值的概念,这不应与运算符从左到右和从右到左的结合性混淆:表达式 f1 ( ) + f2 ( ) + f3 ( ) 由于 operator + 的左结合性被解析为 ( f1 ( ) + f2 ( ) ) + f3 ( ) ,但在运行时对 f3 ( ) 的函数调用可能先于、后于或在 f1 ( ) 与 f2 ( ) 之间执行。
目录 |
定义
求值顺序
编译器对每个表达式或子表达式执行两种评估(两者均为可选):
- 值计算 :计算表达式返回的数值。这可能涉及确定对象的身份( 左值求值 )或读取先前赋给对象的值(右值求值)。
-
副作用
:对由
volatile左值指定的对象进行访问(读取或写入)、修改(写入)对象 、原子同步 (C11起) 、修改文件、修改浮点环境(若支持),或调用执行上述任意操作的函数。
如果表达式不产生副作用且编译器能确定其值未被使用,该表达式 可能不会被求值 。
求值顺序
Sequenced-before 是同一线程内各求值之间的非对称、可传递的成对关系(若涉及原子类型与内存屏障,该关系可能跨线程延伸)。
- 若在子表达式 E1 与 E2 之间存在 序列点 ,则 E1 的值计算和副作用均 先序于 E2 的所有值计算与副作用。
|
(since C11) |
规则
&&
(逻辑与)、
||
(逻辑或)以及
,
(逗号运算符)。
?:
的第一个(左侧)操作数求值之后,以及第二个或第三个操作数(无论哪个被求值)求值之前,存在一个序列点
|
5)
完整声明符的末尾存在一个序列点。
6)
库函数返回前立即存在一个序列点。
|
(C99 起) |
|
9)
任何运算符操作数的值计算(但不含副作用)均先序于该运算符结果的值计算(但不含其副作用)。
10)
直接赋值运算符及所有复合赋值运算符的副作用(左参数的修改)均后序于左右参数的值计算(但不含副作用)。
11)
后自增与后自减运算符的值计算均先序于其副作用。
12)
既不先序也不后序于另一函数调用的函数调用为不确定顺序(构成不同函数调用的 CPU 指令不可交错,即使函数被内联)
13)
在
初始化
列表表达式中,所有求值均为不确定顺序
14)
相对于不确定顺序的函数调用,复合赋值运算符的操作以及自增/自减运算符的前缀与后缀形式均为单次求值。
|
(C11 起) |
未定义行为
i = ++i + i++; // undefined behavior i = i++ + 1; // undefined behavior f(++i, ++i); // undefined behavior f(i = -1, i = -1); // undefined behavior
f(i, i++); // undefined behavior a[i] = i++; // undefined behavior
参见
运算符优先级 定义了表达式如何从其源代码表示形式构建。
|
C++ 文档
关于
求值顺序
|