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

众所周知,这循环为零:

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

例如,如果x的原始值是5 ,那么你的表达式要求x同时变为4 (减量的副作用)和5 (赋值的副作用)。 不用说, x不可能同时变为45

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

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

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

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

只是为了向其他答案添加内容,请尝试阅读有关序列点的维基百科页面 。

我建议阅读https://stackoverflow.com/a/21671069/258418 。 如果你在一起ch =一个序列点 ,并且编译器可以自由地交错操作,只要它们没有被你链接的答案中的序列点分开,你会看到,即以下两个序列是合法的:

 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 

通常:避免在一个表达式中将指定(这包括通过前/后++ / – 的修改)分配到同一个变量两次。