评估C表达
int main() { int i = -3, j = 2, k = 0, m; m = ++i || ++j && ++k; printf("%d %d %d %d\n", i, j, k, m); return 0; }
我认为&&优先于|| 根据这个逻辑++j
应该执行,但它永远不会,程序输出-2 2 0 1
。 这里发生了什么? 中间步骤是什么?
&&
确实具有比||
更高的优先级 ,这意味着++i || ++j && ++k
++i || ++j && ++k
解析为++i || (++j && ++k)
++i || (++j && ++k)
。
然而,这并没有改变||
的RHS这一事实 仅在LHS返回0
执行。
优先权不会影响评估顺序。
优先级对评估顺序没有影响(除非必要 – 由于优先级,某些子表达式可能需要在其他子表达式之前进行评估)。 例如,在简单表达式中:
a() + b() + c() * d()
即使乘法优先于加法,编译器也可以按照自己喜欢的顺序自由执行对函数的调用,并且可以在执行乘法之前或之后调用a()
或b()
。 显然,它必须在执行乘法之前评估c()
和d()
。 如果这些函数具有副作用(如修改和使用全局变量),则不确定的评估顺序可能会导致意外结果。
但是,对于某些运营商而言,该标准确实规定了严格的评估顺序。 这是关于||
逻辑或运算符:
与按位|不同 运算符,|| 运营商保证从左到右的评估; 在评估第一个操作数后有一个序列点。 如果第一个操作数比较不等于0,则不计算第二个操作数。
所以不仅||
提供订购保证,它还保证在某些条件下,第二个操作数根本不会被评估。
(它也说&&
类似内容 – 除了在这种情况下,如果第一个操作数的第一个计算结果为0,则不计算第二个操作数。但在您的示例中, ||
首先出现)。
提供一些排序保证的其他运算符包括逗号运算符和函数调用(它保证已经评估了参数,但不保证评估这些参数的顺序)。
C ++对逻辑运算符使用惰性求值。
如果你写a || b
a || b
, a
为真, b
永远不会评估,因为即使b
为假,结果也是正确的。
同样,如果a
为假,则a && b
不会评估b
。
由于++i
评估为真值,因此不评估其他表达式。
&&和|| 使用短路评估,即在表达式a中首先评估&& b a,如果是假,那么整个表达式为假,b不进行评估。 在|| b中,如果a为真,则不计算b。 请注意,如果您重载&&或|| 短路规则将不再适用。 HTH
C会对逻辑表达式进行短路 ,因此对++i
评估足以certificatem
应该为真。
-
||
操作员强制从左到右评估,因此首先完全评估表达式++i
,结果为-2
。 -
||
操作符强制执行序列点,因此应用副作用,i
现在等于-2
。 - 表达式
++i
的结果不是0,因此根本不评估表达式++j && ++k
。 - 由于LHS非零,因此整个表达式的结果为
++i || ++j && ++k
++i || ++j && ++k
是1
(真),分配给m
。
只是为了回应其他几个人所说的,评价的优先顺序和顺序并不是一回事。
你是否偶然想要输入:
m = ++i | ++j & ++k;
输出-2 3 1 -1
m = ++ i || ++ j && ++ k;
因为&&
优先级高于||
所以表达式被解释为++i || (++j && ++k)
++i || (++j && ++k)
||
是短路,所以右边的操作数是||
运算符不会被评估,因为++i
返回非零值。