为什么`x--> 0`不是未定义的行为,而`x = x - `是?

时间:2011-02-07 17:27:28

标签: c operators decrement

众所周知,这循环为零:

while (x-- > 0) { /* also known as x --> 0 */
  printf("x = %d\n", x);
}

x = x--会产生undefined behaviour


两个示例都需要x--的某些“返回”值,我猜不到。如何定义x-- > 0x = x--不是?

5 个答案:

答案 0 :(得分:19)

因为在x = x--中你在没有插入序列点的情况下两次修改x的值。因此,未定义操作顺序。在x-- > 0中,x的值被修改一次,并且明确定义了在递减之前评估x--的结果将是x的值。

答案 1 :(得分:7)

我不知道你在哪里知道“需要一些'返回'的x值,这是不存在的”。首先,你的意思并不清楚。其次,无论你的意思是什么,这似乎都与x = x--中未定义行为的来源无关。

x = x--会产生未定义的行为,因为它会尝试两次修改x而没有插入序列点。这里不涉及任何“返回值”的“需要”。

x = x--的潜在问题是它有两个副作用,这些副作用是在未定义的时刻以未定义的顺序发生的。赋值运算符引入了一个副作用。另一个副作用是由postfix --运算符引入的。两种副作用都试图修改相同的变量x并且通常相互矛盾。这就是为什么在这种情况下的行为在法律上被宣布为未定义的原因。

例如,如果x的原始值为5,那么您的表达式需要x同时成为4(减量的副作用)和{{ 1}}(分配的副作用)同时。毋庸置疑,5无法同时成为x4

虽然UB不需要这种直截了当的矛盾(如5 vs 4)。每当你有两个副作用击中相同的变量而没有插入序列点时,行为是不确定的,即使这些副作用试图放入变量匹配的值。

答案 2 :(得分:3)

为了理解这一点,您需要对序列点有基本的了解。请看这个链接:http://en.wikipedia.org/wiki/Sequence_point

对于=运算符,没有序列点,因此无法保证x的值在再次分配给x之前将被修改。

当您在while循环x-- > 0中检查条件时,将评估x--并在关系运算符评估中使用该值,因此不存在未定义行为的可能性,因为x正在修改一次。

答案 3 :(得分:2)

只是为了向其他答案添加内容,请尝试阅读有关序列点的this wikipedia page

答案 4 :(得分:1)

我建议阅读https://stackoverflow.com/a/21671069/258418。如果你把List<Integer> exampleInts = new ArrayList<>(Arrays.asList(1, 2, 3, 5, 8, 13, 21)); int size = (exampleInts.size()-1)*2; for (int i = 0; i < size; i+=2) { int delimiter = 0; exampleInts.add(i+1, delimiter); } System.out.println(exampleInts); 放在一起=并且编译器可以自由交错操作,只要它们没有被你链接的答案中的序列点分开,你就会看到即以下两个序列是合法的:

load i to reg
increment i
assign reg to i
=> i has previous value of i

load i to reg
assign reg to i
increment i
=> i has value of previous value of i + 1

一般情况下:避免在一个表达式中将同一个变量分配(包括前/后++ / - 的修改)两次。