C++逗号运算符未定义行为判定及序列规则说明
问题解答
结论先行
你给出的两处包含内置逗号运算符的代码均不会产生未定义行为,行为完全符合C++11及之后版本的标准要求,输出结果可预测。
核心规则说明(C++11及以上标准)
首先明确和问题相关的sequenced-before核心规则:
- 内置(非重载)逗号运算符
,的左操作数的所有值计算、副作用sequenced before右操作数的所有值计算、副作用,即左操作数的所有读写操作全部完成后,才会执行右操作数的任何操作 - 若两个对同一标量的操作是unsequenced关系,且其中一个是写操作,则会触发未定义行为
- 链式
operator<<调用等价于嵌套的函数调用,函数多个参数的求值之间是unsequenced关系,这也是你已知的std::cout << n << " " << ++n << std::endl;属于UB的原因:n的读操作和++n的写操作没有明确先后顺序。
逐行代码行为解释
1. 逗号表达式赋值语句
int m = (++n, std::cout << "n = " << n << '\n', ++n, 2*n);
该语句括号内的逗号均为内置逗号运算符,按照从左到右的顺序执行,所有前序操作全部完成后才会执行后续操作:
- 首先执行
++n:n的初始值为1,自增后n=2,写副作用完成 - 执行
std::cout << "n = " << n << '\n':读取到n的值为2,输出n = 2,输出操作的副作用完成 - 执行第二个
++n:n自增为3,写副作用完成 - 执行
2*n:读取n的值为3,计算得到结果6,作为整个逗号表达式的返回值赋值给m,最终m=6
全程不存在无顺序的读写冲突,无未定义行为。
2. 输出语句中的逗号表达式
std::cout << "m = " << (++m, m) << '\n';
括号内的逗号为内置逗号运算符:
- 先执行
++m:m初始值为6,自增后m=7,写副作用完成 - 再读取m的值为7,作为括号内表达式的返回值参与输出,最终输出
m = 7
全程不存在无顺序的读写冲突,无未定义行为。
注意区分
只有作为表达式运算符的逗号才符合上述sequenced-before规则,如果逗号是函数参数的分隔符,则不属于逗号运算符,多个参数的求值之间仍然是unsequenced关系。
内容的提问来源于stack exchange,提问作者Anoop Rana
相关产品推荐
相关产品推荐

