C++赋值两侧前后缀自增的求值顺序及未定义行为判定
结论
你给出的两段代码的行为要分C++版本判定:
C++17及更高版本
两段代码均不属于未定义行为,行为有明确规则约束。
规则依据
- 优先级规则(所有C++版本通用):
- 后缀自增
++> 前缀自增++> 加法+> 复合赋值+=,因此两段代码的表达式都会被分组为(++y) += (x + y + (z++))的结构。
- 后缀自增
- C++17新增的求值顺序规则:
对于复合赋值运算符
E1 op= E2,右操作数E2的所有值计算和副作用,都先序于左操作数E1的所有值计算和副作用;赋值操作本身的副作用,先序于整个表达式的值计算。
同时规则明确:前缀自增的副作用会在其值计算前完成,后缀自增的副作用会在其值计算后立即完成。
第二段代码执行流程(和你给出的输出5完全匹配)
初始值:x=1, y=1, z=1
- 先对
+=的右操作数x + y + z++求值:z++先返回z的原值1,随后z的副作用生效,z变为2- 此时y仍为1,求和结果为
1 + 1 + 1 = 3,右操作数求值完成
- 再对
+=的左操作数++y求值:- 前缀自增先修改y的值为2,返回y的左值
- 执行复合赋值:
y = 2 + 3 = 5,最终输出结果为5
第一段代码说明
你注释里第一段代码输出6,是不符合C17规则的:按照C17规则,第一段代码右操作数先求值得到1+1+1=3,左操作数++y把y改成2后赋值,最终结果应该是5。你得到的6是C++17之前版本的编译器行为。
C++17之前的版本
两段代码均属于未定义行为。
依据
C++17之前的标准没有规定复合赋值运算符左右操作数的求值顺序,标量y在两个相邻序列点之间被多次修改(前缀自增、复合赋值两次修改y),且对y的读取操作和修改操作之间没有顺序约束,符合未定义行为的判定条件,不同编译器、不同编译选项都可能得到不同的输出结果,你测试得到第一个输出6就是编译器优先对左操作数++y求值的结果。
内容的提问来源于stack exchange,提问作者Peter Green
相关产品推荐
相关产品推荐

