众所周知,这循环为零:
while (x-- > 0) { /* also known as x --> 0 */
printf("x = %d\n", x);
}
但x = x--
会产生undefined behaviour。
两个示例都需要x--
的某些“返回”值,我猜不到。如何定义x-- > 0
但x = x--
不是?
答案 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
无法同时成为x
和4
。
虽然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
一般情况下:避免在一个表达式中将同一个变量分配(包括前/后++ / - 的修改)两次。