7

可能重复:
未排序的值计算(又名序列点)
未定义的行为和序列点
运算符优先级与评估顺序

我仍在努力思考以下表达式如何导致未定义的行为:

a = a++;

在对此进行搜索时,我发现了以下问题:

序列点和运算符优先级之间的区别?0_o

我通读了所有答案,但我仍然对细节有困难。其中一个答案将我上面的代码示例的行为描述为模棱两可,就如何a修改而言。例如,它可能归结为以下任何一种:

a=(a+1);a++;
a++;a=a;

究竟是什么让a' 的修改模棱两可?这是否与不同平台上的 CPU 指令有关,以及优化器如何利用未定义的行为?换句话说,由于生成的汇编程序,它似乎未定义?

我看不出编译器使用的理由a=(a+1);a++;,它看起来很古怪而且没有多大意义。什么将拥有编译器使其行为如此?

编辑:

为了清楚起见,我确实了解正在发生的事情,但我只是不明白当有运算符优先级规则时(它本质上定义了表达式的评估顺序),它怎么可能是未定义的。在这种情况下,分配发生在最后,因此a++需要首先进行评估,以确定要分配给的值a。所以我期望的是a在后修复增量期间首先修改它,然后产生一个值来分配回a(第二次修改)。但是运算符优先级的规则似乎使我的行为非常清楚,我找不到任何“摆动空间”让它具有未定义的行为。

4

6 回答 6

8

您链接到的问题中的第一个答案准确地解释了发生了什么。我会尝试改写它以使其更清楚。

运算符优先级定义了通过表达式计算值的顺序。表达式的结果(a++)很好理解。

但是,变量的修改a 不是表达式的一部分。对真的。这是您难以理解的部分,但这只是 C 和 C++ 定义它的方式。

表达式会产生值,但某些表达式可能会产生副作用。该表达式a = 1的值为1,但它也具有将变量设置为的副作用。至于 C 和 C++ 如何定义事物,这是两个不同的步骤。同样,具有价值和副作用。a1a++

序列点定义在这些序列点之后计算的表达式何时可见副作用。运算符优先级与序列点无关。这就是 C/C++ 定义事物的方式。

于 2012-09-07T15:47:26.393 回答
1

这可能是一个过于简单的解释,但我认为这是因为当代码用“a”“完成”时没有办法解决。它是在增量之后完成的,还是在分配之后完成的?决议最终是圆形的。增量后的赋值改变了应用增量值时的语义。也就是说,在“a”递增之前,代码不会用“a”完成,但在赋值完成之前,a 不会递增。这几乎是死锁的语言版本。

正如我所说,我确信这不是一个很好的“学术”解释,但这就是我把它塞进我自己的耳朵里的方式。希望这会有所帮助。

于 2012-09-07T15:43:24.107 回答
1

优先级规则指定表达式的计算顺序,但在计算期间不必发生副作用。它们可以在下一个序列点之前的任何时间发生。

在这种情况下,增量的副作用既不在赋值之前也不在赋值之后排序,因此表达式具有未定义的行为。

于 2012-09-07T15:47:08.193 回答
0

让我来看看语句中的基本问题a = a++。我们希望实现以下所有目标:

  • 确定值a(的返回值a++,#1)

  • 增量a(的副作用a++,#2)

  • 将旧值分配给a(分配的效果,#3)

有两种可能的排序方式:

  1. 将原件存储aa(无操作);然后递增a。与 相同a = a; ++a;。这是序列#1-#3-#2。

  2. 评估a、增加a、分配原始值给a. 与 相同b = a; ++a; a = b;。这是序列#1-#2-#3。

由于没有规定的顺序,因此这些操作中的任何一个都是允许的。但他们有不同的最终结果。两个序列都不比另一个更自然。

于 2012-09-07T16:17:02.103 回答
0

该语句a=a++有两个结果和两个赋值:

a=a

(因为它是一个后增量)和

a=a+1

这些分配显然会导致不同的最终值a

c 标准的起草者没有指出两个赋值中的哪一个应该首先写入a,哪个第二个,因此编译器编写者可以在任何给定情况下自由选择他们喜欢的任何一个。

结果是,它(这个特定的语句)不会崩溃,但是您的程序不能再依赖具有特定值的 a。

于 2012-09-07T15:58:32.860 回答
0

这里的重点是,在某些 CPU 架构上,比如 Intel Itanium,这两个操作可以由编译器在指令级并行化——但是让你的构造定义良好会禁止这样做。在序列点规范时,这些架构大多是假设性的,而且由于 Itanium 失败了,因此到 2012 年,这在很大程度上是语言中不必要的复杂性,这是有争议的。任何仍然常用的架构基本上都没有可能的缺点——即使对于安腾来说,性能优势也很小,编写一个甚至可以利用它的编译器的头痛是巨大的。

另请注意,在 C++11 中,序列点被替换为先排序后排序,这使得更多类似的情况得到了很好的定义。

于 2012-09-07T15:50:46.300 回答