我想知道为什么这段代码会输出2。

3
我不知道是否有人能够友好地为我解释这段代码?
unsigned int x = 0;
(x ^= x ) || x++ || ++x || x++;

printf("%d\n", x);

当我在我的电脑上使用gcc 4.2编译时,输出结果为2。
原本我以为这种行为是未指定的,但是我发现"||"运算符的优先级比其他运算符低,所以答案不应该是3吗?因为有三个"++"。
有人能解释一下吗?谢谢。

3
重点并不在于||的优先级,而在于它是一个序列点。 - Flexo
行为已经完全规定(不像这里时常出现的类似问题)。 - Alexandre C.
6个回答

6
  • 执行(x ^= x)并产生0,因此:
  • 执行(x++)产生0,因此:
  • 执行(++x)并产生2,因此停止运行

这可以归结为一个规则:||只有在左侧为false时才会评估其右侧。


糟糕!你是对的。我看错了,它溢出了32位整数,然后加上3(这也会产生2),但你的答案是正确的。 - Peter Rowell
@PeterRowell 这非常有趣,我没有想到那么远 :-) - cnicutar

5
问题在于 || 运算符是短路的。一旦它找到一个真值,它就不再需要检查剩余的 || 语句; 答案已经知道了。 (x ^= x) 计算结果为0。
x++ 先计算出0,然后将x增加到1。
++x 计算结果为2 - true。
最后一个 or 语句不需要被计算。它"短路"并立即返回真值。

这似乎是正确的答案,其他人忘记解释 ++ 运算符在表达式的那部分评估之后生效。 - Maarten Bodewes

2
行为是明确定义的。您正在观察||的短路行为;最终的x++永远不会被评估。

1

这就是短路语义的作用。第一个表达式x ^= x计算结果为0,第二个表达式也计算结果为0。第三个表达式计算结果为2,由于逻辑表达式的结果已经确定为true,因此它被短路了。


0

当然,你不应该使用这样的结构,但让我们分析一下表达式。

有4个表达式与快捷-或(shortcut-OR)组合在一起:

a || b || c || d

如果a为假,则只计算b、c和d,如果b也为假,则只计算c和d,如果前面所有的都为假,则只计算d。

整数被视为0 == false,其他所有值均不为false。

x ^= 0 

当 x 为 0 时,结果再次为 0。

x++ 

被评估并稍后增加,因此它的值为0,这将调用表达式c,但稍后x将被增加。

++x 

首先,变量b被增加了1,变成了1,然后被计算(结果为1),这就是为什么变量d没有被计算,但变量b的增量还未完成,所以我们得到了2。

但我不确定这种行为是否完全定义,并且在所有编译器上都会导致相同的结果。

Avoid it. 

0

|| 运算符之间的表达式将从左向右求值,直到其中一个为 true 为止:

(x ^= x ) 

x中的所有位设置为0/关闭(false);

x++ 

增加 x,现在是 1,但仍然是 false,因为这是后增量。

++x 

(pre-)Increments x, which is now 2 and also true, so there is no need for the right hand side of || to be evaluated.

(前置)递增x,现在为2,也为true,因此无需评估||的右侧。


你一定很困了,即使你有11800分,0 XOR 0也不会评估为1。 - Maarten Bodewes
1
@owlstead - 我最初误读了代码。我以为我已经纠正了那个错误。我错过了一个吗? - Flexo
我现在正在阅读不同的内容,所以在更新过程中写了这个注释(似乎是你编辑后的2分钟之后提交的)。 - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接