序列点与运算符优先级
Sequence Points vs Operator Precedence
可能重复:
无序列值计算(也称为序列点)
未定义的行为和序列点
操作员优先级与评估顺序
我仍然试图理解以下表达式是如何导致未定义行为的:
a = a++;
在搜索SO时,我发现了以下问题:
序列点和运算符优先级之间的区别?0_o
我通读了所有的答案,但在细节上仍然有困难。其中一个答案将我上面的代码示例的行为描述为不明确,即a
是如何修改的。例如,它可以归结为以下两种:
a=(a+1);a++;
a++;a=a;
究竟是什么使得a
的修改含糊不清?这与不同平台上的CPU指令有关吗?优化器如何利用未定义的行为?换句话说,它似乎是未定义的,因为生成的汇编程序?
我看不出编译器使用a=(a+1);a++;
的原因,它只是看起来很古怪,没有多大意义。编译器拥有什么才能使它以这种方式运行?
编辑:
需要明确的是,我确实理解发生了什么,我只是不明白当有关于运算符优先级的规则(本质上定义了表达式的求值顺序)时,它是如何被定义的。在这种情况下,赋值发生在最后,因此需要首先评估a++
,以确定要赋值给a
的值。因此,我所期望的是,在修复后增量期间,首先修改a
,然后生成一个值,将其分配回a
(第二次修改)。但运算符优先级的规则似乎让我非常清楚这种行为,我找不到任何"回旋余地"让它有未定义的行为。
您链接到的问题中的第一个答案准确地解释了发生了什么。我会尝试重新措辞,使其更清楚。
运算符优先级定义了通过表达式计算值的顺序。表达式CCD_ 8的结果是很好理解的。
但是
,变量a
的修改不是表达式的一部分。是的,真的。这是你难以理解的部分,但这只是C和C++对它的定义
表达式会产生值,但某些表达式可能会产生副作用。表达式a = 1
的值为1
,但它也具有将变量a
设置为1
的副作用。就C和C++如何定义事物而言,这是两个不同的步骤。类似地,a++
具有值和副作用。
序列点定义副作用对在这些序列点之后求值的表达式可见的时间。运算符优先级与序列点无关。这就是C/C++定义事物的方式。
这可能是一个过于简单的解释,但我认为这是因为当代码用"a"完成"时,没有办法解决。它是在增量之后完成的,还是在赋值之后完成的?决议最终是循环的。增量后的赋值会更改应用增量值时的语义。也就是说,在"a"增加之前,代码不会使用"a"完成,但在进行赋值之后,a才会增加。这几乎是死锁的语言版本。
正如我所说,我相信这不是一个很好的"学术"解释,但这就是我把它藏在自己耳朵里的方式。希望这能有所帮助。
优先级规则指定表达式的求值顺序,但在求值过程中不必发生副作用。它们可以在下一个序列点之前的任何时间发生。
在这种情况下,增量的副作用既不在赋值之前也不在赋值之后排序,因此表达式具有未定义的行为。
这里的重点是,在某些CPU体系结构(如英特尔安腾)上,编译器可以在指令级并行化这两个操作,但如果您的构造定义明确,则禁止这样做。在制定序列点规范时,这些体系结构大多是假设性的,由于安腾是一个失败的,因此到2012年,这在很大程度上是语言中不必要的复杂性。在任何仍在使用的体系结构上,基本上都没有可能的缺点——即使对于安腾来说,性能优势也是微乎其微的,编写一个甚至可以利用它的编译器也非常头疼。
还需要注意的是,在C++11中,序列点被替换为前序和后序,这使得更多类似的情况得到了明确定义。
语句a=a++
有两个结果和两个赋值:
a=a
(因为这是后增长)和
a=a+1
这些赋值显然会导致a
的最终值不同。
c标准的起草者没有指出两个赋值中的哪一个应该首先写入a
,哪一个第二个,因此编译器编写者可以在任何给定的情况下自由选择他们喜欢的。
结果是,它(这个特定的语句)不会崩溃,但您的程序不能再依赖于具有特定值的。
让我浏览一下语句a = a++
中的基本问题。我们希望实现以下所有目标:
-
确定值
a
(a++
的返回值,#1) -
增加
a
(a++
的副作用,#2) -
将旧值分配给
a
(分配的效果,#3)
有两种可能的排序方式:
-
将原始
a
存储到a
中(无操作);则递增CCD_ 26。与a = a; ++a;
相同。这是序列#1-#3-#2。 -
评估
a
,递增a
,将原始值分配回a
。与b = a; ++a; a = b;
相同。这是序列#1-#2-#3。
由于没有规定的顺序,因此这两种操作都是允许的。但他们最终会有不同的结果。两个序列都不比另一个更自然。
- C++ 带有函数指针的运算符优先级
- <<运算符优先级与字符串比较
- 在一个指令中声明更多指针的运算符优先级
- C++中的运算符优先级
- c++中的增量和三元运算符优先级
- 涉及模运算符优先级的错误以及C++中具有大数字的括号
- 带有 cout 和指针的运算符优先级
- C++ 使用矢量迭代器时的运算符优先级
- 序列点和运算符优先级有什么区别
- 运算符优先级 括号问题
- C++表达式中的运算符优先级
- 相等运算符优先级不起作用
- 递增和按位移位运算符优先级?
- 运算符优先级超载在C 中
- C++ 中的递增/递减和输出流运算符优先级
- 输出流中的运算符优先级C++
- 运算符优先级C++
- C++11 何时相对于运算符优先级进行算术类型转换
- 从表中了解运算符优先级
- 是否违反 C/C++ 运算符优先级和关联性规则?