在this answer中,有一些明确定义和未定义的表达式的例子。我对其中两个特别感兴趣:
(6) i = i++ + 1; // Undefined Behaviour
(7) i = ++i + 1; // Well-defined Behaviour
这意味着在序列点和明确/未指定/未定义的行为方面,前增量和后增量之间存在差异,但我不明白这种差异来自何处。
在标准草案( N4618 )中,有一个代码示例([intro.execution],第18页)
i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined
据我了解,这意味着表达式i = i++ + 1
应该定义明确,变量i
的值应该增加1
作为此表达式的结果。但是,在MSVS 2015中运行的此代码会将i
增加2
。
那么,表达式i = i++ + 1
会发生什么?是定义明确,未定义,实现定义还是未指定的行为?如原始答案所述,在序列点和UB方面,这个和类似表达式的前增量和后增量之间是否存在任何差异?为什么Visual Studio会显示与标准中写的不同的行为?
请注意,我主要对现代c ++(14/17)感兴趣。
答案 0 :(得分:1)
表达式i = i++ + 1
会发生什么?它是定义明确,未定义,实现定义还是未指定的行为?
这个确切的例子在标准中给出,我们有多幸运?
N4296 1.9.15 [intro.execution]
i = i++ + 1; // the behavior is undefined
当然,我们也想知道为什么。以下标准引用似乎与此相关:
N4296 1.9.15 [intro.execution]
[...]对运算符的操作数的值计算进行排序 在运算符结果的值计算之前。 [...]
这告诉我们总和将在赋值之前发生(呃,它怎么知道要分配什么!),但它并不保证增量将在赋值之前或之后发生,现在我们在浑水......
N4296 1.9.15 [intro.execution]
[...]如果标量对象的副作用相对于其中任何一个都没有排序 对同一标量对象或值计算的另一个副作用 使用相同标量对象的值,它们不是 可能并发(1.10),行为未定义。 [...]
赋值运算符对i
的值有副作用,这意味着我们在同一个标量对象上有两个副作用(另一个是由i++
执行的赋值),这些副作用是未排序的,这是未定义的。
为什么Visual Studio会显示与标准中写的不同的行为?
没有。该标准表示它是未定义的,这意味着它可以做任何事情,从你想要的东西到完全不同的东西,只是碰巧这是由编译器吐出来的行为!
答案 1 :(得分:0)
i = ++i + 1; // Well-defined Behaviour
这意味着在序列点和明确/未指定/未定义的行为方面,preincrement和postincrement之间存在差异,但我不明白这种差异来自何处。
我认为帖子在几个方面是不正确的。引用与他们相同的部分,强调我的:
C ++ 11 1.9 / 15
一个操作数的值计算 在运算符结果的值计算之前对运算符进行排序。如果对标量有副作用 对于相同标量对象或值计算的另一个副作用,对象未被排序 使用相同标量对象的值,行为未定义。
然后是赋值运算符:
C ++ 11 5.17
在所有情况下,赋值在右和左操作数的值计算之后,以及赋值表达式的值计算之前排序。
值得注意的是,值计算或左右操作数未按顺序排列。 (这已在C11 1)中明确说明,否则其文本与C ++ 11完全相同。)
意味着在表达式i = ++i + 1;
中,++i
的副作用与左操作数i
的值计算无关。因此,根据1.9 / 15,它是未定义的行为。 UB与任务副作用毫无关系。
对于表达式i = i++ + 1;
,赋值的副作用是,根据C ++ 11,在值计算之后,但在表达式的值计算整体之前显式排序。根据5.2.6,i++
的值计算不是问题“++表达式的值计算在修改操作数对象之前被排序”。根据后缀++的性质,更新i++
的副作用必须在整个表达式的值计算之后排序。据我所知,这是明确定义的行为。
因此,正确的文字应为
(6) i = i++ + 1; // Well-defined Behaviour
(7) i = ++i + 1; // Undefined Behaviour
显然在C ++ 11 1.9 / 15 i = i++ + 1; // the behavior is undefined
中有一个不正确的例子,该例子已在该标准的更高版本中得到纠正。
注意:对于序列点的措辞改变,这些都没有任何关系!
1) C11 6.5.16 / 3
更新存储值的副作用 左操作数在左和右的值计算之后排序 正确的操作数。 操作数的评估未被排除。