短路逻辑或行为

时间:2016-05-15 00:55:28

标签: c gcc clang

我的印象是,在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

3 个答案:

答案 0 :(得分:2)

((attr & 2) != 2) || ((attr & 4) != 4)评估为true,因为

  1. attr & 4 == 0(attr & 4) != 41,因为attr & 4不等于4。 (N1570 6.5.9平等运营商)
  2. 因为至少有一个操作数不为零,所以表达式的计算结果为1。 (N1570 6.5.14逻辑OR运算符)
  3. 当控制表达式不为零时,if语句将执行第一个子语句(N1570 6.8.4.1 if语句),您将其称为“表达式计算为true”。
  4. 如果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) )

会发生什么:

  1. (attr & 2)评估为2.(0010 AND 0010 = 0010,即2)
  2. (2 != 2)评估为0或false。
  3. 现在评估OR的右侧(如果左侧为真,则右侧不会被执行/评估,即“短路”。但在此示例中它是错误的,所以右侧是求值)。
  4. (attr & 4)是按位和操作,例如0010&amp; 0100.评估为0000或0。
  5. (0 != 4)的计算结果为1,或者为true,因此if语句的主体将执行。
  6. 然后执行程序的其余部分(最后一个语句),程序终止。
  7. 记住:

    • &是按位的。
    • &&是布尔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).