我使用的书将逻辑运算符的关联性从右到左给出,所以我希望这段代码的结果是,2 2 1
但它是2 1 1
.
int x,y,z;
x=y=z=1;
z=++x||++y||++z;
printf("%d %d %d",x,y,z);
为什么是这样?
我使用的书将逻辑运算符的关联性从右到左给出,所以我希望这段代码的结果是,2 2 1
但它是2 1 1
.
int x,y,z;
x=y=z=1;
z=++x||++y||++z;
printf("%d %d %d",x,y,z);
为什么是这样?
||
有短路评估要求。如果第一个操作数不同于0
,则不计算第二个操作数。
(C11,6.5.14 逻辑 OR 运算符) p4 “如果第一个操作数比较不等于 0,则不计算第二个操作数。”
在你的情况下++y
,++z
永远不会被评估。
这是一个微妙的话题。有两种订购方式;评估顺序和关联性。现在事实证明,对于&&
和||
在 C 中,求值和关联性都是从左到右的,所以你的书是错误的。尽管这种情况下的关联性没有实际区别。
为了解释关联性,a || b || c
如果||
是从右到左的,则被视为a || (b || c)
。但如果||
是从左到右,则被视为(a || b) || c
。好吧,两者在所有情况下都会产生相同的结果。所以布尔运算符的关联性并不重要(当然,对于其他一些运算符来说它确实很重要:(a - b) - c
!= a - (b - c)
。
评价顺序不同;它告诉我们在应用了关联性中的隐式括号之后比较事物的顺序。因此,对于从左到右的求值顺序,a || (b || c)
(and (a || b) || c
) 的求值顺序为a
,然后b
,然后c
。从右到左,两者都将按c
, b
,的顺序进行评估a
。
这意味着即使使用从右到左的评估,您也不会看到2 2 1
而是1 1 2
. 再次不管关联性如何。(编辑:实际上你会看到1 1 1
,因为你将 z 设置为表达式的结果,当然是true
)
另一个有趣的注意事项是,对于大多数操作员来说,实际上没有定义评估顺序。这意味着(a ++) - (a ++)
未定义的行为(谢天谢地;否则这将是一场混淆的噩梦)
请参阅http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
或者对于较少的维基百科页面,http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm
这里还有规则 6:http: //en.cppreference.com/w/cpp/language/eval_order#Rules(我确定它在标准中,但我只能找到 C++03 的参考,而不是 C)