众所周知,这循环通过零:
while (x-- > 0) { /* also known as x --> 0 */
printf("x = %d\n", x);
}
但x = x--
会产生未定义的行为。
这两个例子都需要一些“返回”值x--
,我猜这不存在。怎么可能有x-- > 0
定义但x = x--
没有定义?
因为在x = x--
您修改x
两次的值时没有插入序列点。所以没有定义操作的顺序。中x-- > 0
的值x
被修改一次,并且明确定义评估的结果x--
将是x
减量前的值。
我不知道您从哪里得到关于“需要一些 x-- 的'返回'值,它不存在”的想法。首先,您的意思并不完全清楚。其次,不管你的意思是什么,这似乎与x = x--
.
x = x--
产生未定义的行为,因为它尝试在x
没有中间序列点的情况下修改两次。这里不涉及任何“返回值”的“需要”。
潜在的问题x = x--
是它有两个副作用,在未定义的时刻以未定义的顺序发生。赋值运算符引入了一个副作用。后缀运算符引入了另一个副作用--
。两种副作用都试图修改相同的变量x
并且通常相互矛盾。这就是为什么在这种情况下的行为在法律上被宣布为未定义的原因。
例如,如果原始值为x
was 5
,那么您的表达式需要x
同时成为4
(递减的副作用)和5
(赋值的副作用)。不用说,不可能x
同时成为4
和5
。
尽管UB 发生不需要这样一个直接的矛盾(如4
vs )。5
每次你有两个副作用在没有干预序列点的情况下击中同一个变量时,行为是未定义的,即使这些副作用试图放入变量中的值匹配。
为了理解这一点,您需要对序列点有一个基本的了解。请参阅此链接:http ://en.wikipedia.org/wiki/Sequence_point
对于=
操作符而言,没有序列点,因此无法保证 的值x
在再次分配给 之前会被修改x
。
当您在 while 循环中检查条件时x-- > 0
,x--
会评估并在关系运算符评估中使用该值,因此不会出现未定义的行为,因为x
只修改一次。
只是为了在其他答案中添加一些内容,请尝试阅读有关序列点的维基百科页面。
我建议阅读https://stackoverflow.com/a/21671069/258418。如果您将=
不是序列点的内容放在一起,并且编译器可以自由交错操作,只要它们与您链接的答案没有被序列点分隔,您就会看到以下两个序列是合法的:
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
一般来说:避免在一个表达式中两次分配(这包括通过前/后 ++/-- 修改)相同的变量。