今天在遇到问题“ Why are these constructs using pre and post-increment undefined behavior? ”之后,我决定为我可以找到的下一个C标准获取最新的草案,并阅读更多有关它的信息。
在C17草案中发现以下段落之后不久:
一个 表达 是指定值计算的运算符和操作数的序列,或者 指定对象或功能,或产生副作用,或执行组合 其。 运算符的操作数的值计算在该值之前排序 计算运算符的结果
来源:ISO/IEC 9899:2017, Section 6.5 §1 "Expressions"(使用web.archive.org链接断开)
现在我有些困惑。这不是说i = i++
是定义的行为吗?这次,我查看了另一个草稿C99:
表达式是一个运算符和操作数的序列,它们指定值的计算,或者指定对象或函数,或者产生副作用,或者执行它们的组合。
来源:ISO/IEC 9899:1999, Section 6.5 §1 "Expressions"
这句话简直丢了!
答案 0 :(得分:7)
您突出显示的段落仅表示表达式i++
和i
在对完整表达式i = i++
求值之前先求值。这仍然是未定义的行为,因为在没有序列点的表达式中i
被多次修改了。
该段落最初出现在C11中,因此与该版本C17相同。
答案 1 :(得分:2)
全文。在C99中,该文本用于6.5.16赋值运算符:
更新左操作数的存储值的副作用应为 发生在上一个和下一个序列点之间。
操作数的评估顺序未指定。如果试图修改 赋值运算符的结果,或者在下一个序列点之后访问它, 行为是不确定的。
在C11中将其更改为:
更新左操作数的存储值的副作用是 在左右操作数的值计算之后排序。的评价 操作数是无序列的。
这只是不同的(而且更糟的)措辞,两个版本的行为相同-键是C11部分的最后一个句子,这仍然会导致这种不确定的行为,因为相对于左操作数,对左操作数的求值仍然没有顺序。正确的操作数。值计算仅涉及各个操作数。
C17的文字与C11相同。因此答案是:不,i = i++;
仍然是C17中未定义的行为。
仅供参考,请将其与C ++ 11(5.17)进行比较:
在所有情况下,赋值都在值之后排序 左右操作数的计算,以及赋值表达式的值计算之前。
这与C11大致相同,没有明确的“操作数的评估未排序”。这是C ++ 11中的一个缺陷,目前尚不清楚是否可以使某些表达式定义良好。
C ++ 17提供了一个说明(8.5.18):
在所有情况下,赋值都在值之后排序 左右操作数的计算,以及赋值表达式的值计算之前。 右侧操作数在左侧操作数之前排序。
因此在C ++ 17中,i=i++;
的定义明确。正如我们所看到的,措辞很明确,与C11 / C17中的“未排序”相对。