C++中v[i] = ++i;是否为良定义行为?各版本标准差异咨询
表达式
v[i] = ++i;在C++各标准中的行为解析 核心结论
- C11/C14:未定义行为(UB)
- C17/C20:良定义行为
你推导中忽略的关键点,是不同C标准中赋值运算符求值顺序规则的差异,以及C11/14中左右操作数求值的无排序关系。
分版本规则详解
1. C11/C14:未定义行为的原因
在C11和C14中,赋值运算符的规则为:
赋值操作被排序于左右操作数的值计算之后,但左右操作数之间的求值顺序是不确定的(unspecified)
对于表达式v[i] = ++i;,涉及两个关键操作:
- 右操作数
++i:对i执行修改(副作用),并产生修改后的i的值。 - 左操作数
v[i]:需要读取i的值计算数组下标,进而访问v的元素。
由于左右操作数的求值顺序不确定,++i修改i的动作与v[i]读取i的动作之间没有明确的排序关系。而C++11/14标准规定:若对同一对象的修改操作与读取操作无显式排序,行为即为未定义,因此该表达式属于UB。
2. C++17:规则修改后变为良定义
C++17对赋值运算符的求值顺序做了明确强化:
赋值运算符的右操作数的求值被排序于左操作数的求值之前
同时,前置自增运算符++i的规则也明确:
前置自增的副作用(修改
i)被排序于该表达式的值计算之前
结合这两条规则,v[i] = ++i;的执行顺序被严格确定:
- 执行
++i:先修改i的值(副作用),再计算得到修改后的i的值(右操作数的值计算)。 - 计算左操作数
v[i]:读取已修改后的i的值,确定数组下标并定位到v的对应元素。 - 执行赋值:将右操作数的值(新
i)赋给左操作数定位到的数组元素。
所有对i的修改和读取操作都有明确排序关系,行为完全确定,属于良定义。
3. C20:延续C17的规则
C20未修改赋值运算符和前置自增的求值顺序规则,因此v[i] = ++i;的行为与C17一致,属于良定义。
关于C++核心指南ES.43的说明
C核心指南ES.43中指出该表达式存在未定义行为,大概率是基于C17之前的标准编写的。核心指南的部分内容未及时跟进C17及之后的规则变化,因此在现代C标准中,该表达式的行为已明确。
内容的提问来源于stack exchange,提问作者domdrag
相关产品推荐
相关产品推荐

