我使用的书从右到左给出了逻辑运算符的关联性,因此我希望此代码的结果为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 :(得分:6)
||
有短路评估要求。如果第一个操作数与0
不同,则不评估第二个操作数。
(C11,6.5.14逻辑OR运算符)p4“如果第一个操作数与0不等,则不计算第二个操作数。”
在您的情况下,++y
和++z
永远不会被评估。
答案 1 :(得分:2)
这是一个微妙的话题。订购有两种类型;评估顺序和关联性。现在结果是,对于C中的&&
和||
,评估和关联性都是从左到右,因此您的书是错误的。虽然这种情况下的关联性没有实际区别。
要解释关联性,a || b || c
,如果||
从右向左,则会被视为a || (b || c)
。但如果||
是从左到右,则会将其视为(a || b) || c
。那么,在所有情况下都产生相同的结果。因此,布尔运算符的关联性并不重要(当然,它对其他一些运算符很重要:(a - b) - c
!= a - (b - c)
。
评估顺序不同;它告诉我们在之后中比较事物的顺序,我们已经应用了关联性的隐式括号。因此,使用从左到右的评估顺序,a || (b || c)
(和(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)