C++ 根据序列点的预增量与后增量
在本文中,有一些定义良好和未定义表达式的示例。我对其中两个特别感兴趣:C++ 根据序列点的预增量与后增量,c++,c++14,language-lawyer,increment,undefined-behavior,C++,C++14,Language Lawyer,Increment,Undefined Behavior,在本文中,有一些定义良好和未定义表达式的示例。我对其中两个特别感兴趣: (6) i = i++ + 1; // Undefined Behaviour (7) i = ++i + 1; // Well-defined Behaviour 这意味着在序列点和定义良好/未指定/未定义的行为方面,增量前和增量后存在差异,但我不明白这种差异来自何处 在标准草案(N4618)中有一个代码示例([intro.execution],第18页) i=i+++1;//i的值递增 i=i+++i;//
(6) i = i++ + 1; // Undefined Behaviour
(7) i = ++i + 1; // Well-defined Behaviour
这意味着在序列点和定义良好/未指定/未定义的行为方面,增量前和增量后存在差异,但我不明白这种差异来自何处
在标准草案(N4618)中有一个代码示例([intro.execution],第18页)
i=i+++1;//i的值递增
i=i+++i;//行为未定义
据我所知,这意味着表达式I=I+++1
应该得到很好的定义,变量I
的值应该增加1
。然而,MSVS 2015中运行的此代码将i
增加2
那么,表达式i=i+++1
中会发生什么?它是定义良好的、未定义的、实现定义的还是未指定的行为?如原始答案所述,在序列点和UB方面,在这个表达式和类似表达式中,增量前和增量后有什么区别吗?为什么VisualStudio显示的行为不同于标准中编写的行为
请注意,我主要对现代C++(14/17)感兴趣。
< P> <强>表达式中的代码> i=I+++ 1 < <代码>中会发生什么?它是定义良好的、未定义的、实现定义的还是未指定的行为? 标准中给出了这个确切的例子,我们有多幸运 N4296 1.9.15[简介执行]i=i+++1;//行为未定义
当然,我们也想知道为什么。以下标准报价似乎与此相关:
N4296 1.9.15[简介执行]
[…]运算符操作数的值计算按顺序排列
在计算运算符结果的值之前。[……]
这告诉我们,求和将发生在赋值之前(duh,否则它怎么知道赋值什么!),但它不能保证增量将发生在赋值之前或之后,现在我们陷入了困境
N4296 1.9.15[简介执行]
[…]如果标量对象上的副作用相对于
对同一标量对象或值计算的另一个副作用
使用同一标量对象的值,而它们不是
潜在并发(1.10),行为未定义。[……]
赋值运算符对i
的值有副作用,这意味着我们对同一标量对象有两个副作用(另一个是由i++
执行的赋值),未排序,未定义
为什么Visual Studio显示的行为与标准中的书面行为不同?
没有。标准说它是未定义的,这意味着它可以做任何事情,从你想要的到完全不同的事情,只是碰巧这是被编译器吐出来的行为
i=++i+1;//定义明确的行为
这意味着在序列点和定义良好/未指定/未定义的行为方面,预增量和后增量之间存在差异,但我不明白这种差异来自何处
我认为这篇文章在几个方面是不正确的。引用与他们相同的部分,强调我的:
C++11 1.9/15函数的操作数的值计算 运算符在计算运算符结果的值之前排序。如果对标量有副作用 对象相对于同一标量对象上的另一个副作用或值计算未排序 使用同一标量对象的值,行为是未定义的 然后,赋值运算符: C++11.5.17
在所有情况下,赋值都是在右操作数和左操作数的值计算之后、赋值表达式的值计算之前排序的 值得注意的是,值计算或左右操作数不按顺序排列。(这已在C11中明确说明),否则它的文本与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/15i=i+++1;//中有一个不正确的例子该行为未定义
,已在本标准的后续版本中更正
注意:所有这些都与序列点措辞的变化没有丝毫关系
1) C116.5.16/3 更新的存储值的副作用 左操作数在左操作数和左操作数的值计算之后排序 右操作数操作数的求值是不排序的。
序列点在C++11之后就不存在了。我猜(没有什么可以支持它)