我的印象是,在C语言中,逻辑OR运算符||
是一个短路运算符,如果lhs为假,则不会计算rhs。我在比较OR值时遇到了问题。有人可以向我解释为什么下面的代码(在gcc 5.3上)评估为true?我在clang中得到了相同的行为。
#include <stdio.h>
int main() {
int attr = 2;
if( ((attr & 2) != 2) || ((attr & 4) != 4) ) {
printf("No short circuit?\n");
};
printf("%i %i\n",attr,(attr & 2));
};
输出:
No short circuit?
2 2
答案 0 :(得分:2)
((attr & 2) != 2) || ((attr & 4) != 4)
评估为true,因为
attr & 4 == 0
和(attr & 4) != 4
为1
,因为attr & 4
不等于4
。 (N1570 6.5.9平等运营商)1
。 (N1570 6.5.14逻辑OR运算符)if
语句将执行第一个子语句(N1570 6.8.4.1 if语句),您将其称为“表达式计算为true”。如果lhs true ,逻辑OR运算符将不会计算rhs,因为在rhs为true或false的情况下该值都为true。
如果lhs为假,逻辑 AND 运算符将不会计算rhs,因为在rhs为true或false的情况下,该值都将为false。
引自N1570:
6.5.13逻辑AND运算符
[...]
3&amp;&amp;如果两个操作数的比较不等于0,则运算符应为1;否则,它 收益率为0.结果的类型为int。
4与按位二进制&amp;操作员,&amp;&amp;运营商保证从左到右的评估; 如果计算第二个操作数,则在评估之间存在一个序列点 第一和第二个操作数。如果第一个操作数比较等于0,则第二个操作数 操作数未被评估。
6.5.14逻辑OR运算符
[...]
3 ||如果操作数的任何一个比较不等于0,则运算符应该为1;否则,它 收益率为0.结果的类型为int。
4与按位|不同运算符,||运营商保证从左到右的评估;如果 评估第二个操作数,在第一个操作数的评估之间有一个序列点 和第二个操作数。如果第一个操作数比较不等于0,则第二个操作数为 没有评估。
答案 1 :(得分:2)
您拥有的代码:
((attr & 2) != 2) || ((attr & 4) != 4) )
会发生什么:
(attr & 2)
评估为2.(0010 AND 0010 = 0010,即2)(2 != 2)
评估为0或false。(attr & 4)
是按位和操作,例如0010&amp; 0100.评估为0000或0。(0 != 4)
的计算结果为1,或者为true,因此if语句的主体将执行。记住:
&
是按位的。&&
是布尔AND。|
是按位OR。||
是布尔值OR。 答案 2 :(得分:0)
Here's two ways you can get the short circuiting behavior in C:
unsigned int bitwise_logical_or(unsigned int p, unsigned int q) {
return (p | (q & ((p != 0) - 1)));
}
unsigned int numerical_logical_or(unsigned int p, unsigned int q) {
return p + (p == 0) * q;
}
As mentioned in other answers, the ||
operator returns true (0x01) or false (0x00).
bitwise_logical_or
works as follows:
If bitwise or is performed on integers p and q, it will work only so long as p is zero. If p is not zero, bitwise or will intermingle p and q in an unpredictable way. If q could be set to zero if p is greater than zero we’ll get the result we want. Therefore, when p is non-zero, we’d like to perform a bitwise and between q and zero. The trick is that simply testing p == 0 will return (in 8 bit) 0x00 or 0x01. We need it to return 0xff or 0x00 appropriately. We accomplish this by checking p != 0, this will return 0x01 when p > 0 and 0x00 when p == 0. Subtract 1, and in the case that p > 0, you get 0x00 (false). When p == 0, you already have 0x00 (all zeros), there’s no where to go, so the integer wraps around (underflows) and you get 0xff (all ones).