i = i ++的行为是否真的未定义?

时间:2011-02-11 12:14:05

标签: c++

  

可能重复:
  Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)

根据c ++标准,

i = 3;
i = i++;

会导致未定义的行为。

如果它可以导致多个结果,我们使用术语“未定义的行为”。但是在这里,无论评估的顺序如何,i的最终值都是4,所以这不应该被称为“未指明的行为”吗?

9 个答案:

答案 0 :(得分:28)

短语“...... i的最终值将是4,无论评估顺序如何......”都是不正确的。编译器可以发出相当于:

i = 3;
int tmp = i;
++i;
i = tmp;

或者这个:

i = 3;
++i;
i = i - 1;

或者这个:

i = 3;
i = i;
++i;

关于术语的定义,如果答案保证为4,不会是未指定或未定义的行为,那么它将被定义为行为。

根据标准(Wikipedia),它是未定义的行为,所以它甚至可以自由地执行此操作:

i = 3;
system("sudo rm -rf /"); // DO NOT TRY THIS AT HOME … OR AT WORK … OR ANYWHERE.

答案 1 :(得分:9)

不,我们不会使用术语“未定义的行为”,因为它只能导致多个算术结果。如果行为仅限于不同的算术结果(或者更常见的是某些可预测的结果集),则通常将其称为未指定的 >行为。

未定义的行为意味着完全不可预测且无限制的后果,例如格式化计算机上的硬盘驱动器或只是让程序崩溃。 i = i++未定义的行为。

在这种情况下你明白i应该是4的想法并不明确。在C ++语言中绝对没有任何东西可以让你得出这个结论。

答案 2 :(得分:6)

在C和C ++中,两个sequence points之间的任何操作的顺序完全取决于编译器,并且不能依赖于它。该标准定义了构成序列点的事物列表,从内存中可以看出

  1. 声明后的分号
  2. 逗号运算符
  3. 在调用函数之前评估所有函数参数
  4. &&和||操作数
  5. 在维基百科上查找页面,列表更完整,更详细地描述。序列点是一个非常重要的概念,如果你还不知道它意味着什么,你马上就会受益匪浅。

答案 3 :(得分:4)

i =,和i ++都是修改i的副作用。

i ++并不意味着i仅在评估整个语句之后递增,仅仅是已经读取了i的当前值。 因此,分配和增量可以按任何顺序发生。

答案 4 :(得分:4)

1。 不,结果将根据评估顺序而有所不同。增量和赋值之间没有评估边界,因此可以在赋值之前或之后执行增量。考虑一下这种行为:

load i into CX
copy CX to DX
increase DX
store DX in i
store CX in i

结果是i包含3,而不是4

作为比较,在C#中, 是表达式和​​赋值的评估之间的评估边界,因此结果将始终为3

2。 即使未指定确切的行为,规范也非常清楚它涵盖的内容和未涵盖的内容。行为被指定为未定义,它没有未指定。

答案 5 :(得分:2)

回答你的问题:

  1. 我认为“未定义的行为”意味着编译器/语言实现者可以自由地做任何它认为最好的事情,而不是它可能导致多个结果。
  2. 因为它不是未指定。显然指定,其行为未定义

答案 6 :(得分:0)

当你只需输入i ++时输入i = i ++是不值得的。

答案 7 :(得分:0)

我在OCAJP实践测试中看到了这样的问题。 IntelliJ的IDEA反编译器可以解决这个问题

public static int iplus(){
    int i=0;
    return i=i++;
}

进入此

public static int iplus() {
    int i = 0;
    byte var10000 = i;
    int var1 = i + 1;
    return var10000;
}

从模块创建JAR,然后作为库导入并检查。 enter image description here

答案 8 :(得分:0)

这个问题很旧,但是似乎仍然经常被引用,因此,鉴于标准的变化,它值得一个新的答案。

http://eel.is/c++draft/basic.exec

http://eel.is/c++draft/expr.ass

[expr.ass]子句1解释“……分配在右操作数和左操作数的值计算之后排序……”和“右操作数在左操作数之前排序”。这里的含义是,右操作数的副作用在赋值之前被排序,这意味着[basic.exec]第10节“如果对存储位置有副作用([ [intro.memory])相对于同一存储位置上的另一副作用或使用同一存储位置中任何对象的值进行的值计算而言,都是未排序的,并且它们可能不是并发的([intro.multithread]),未定义。”

已定义行为,如后面的示例所述。