C中条件语句中的按位运算符和逻辑运算符有什么区别?

What is the difference between bitwise and logical operators inside conditional statements in C?

网上有很多问题都提到了位运算符和逻辑运算符的区别。希望我已经做好了搜索,其中 none 专门研究了它们在条件语句中使用时是否相同,也没有专门指代 C 语言。大多数提到了C++和C#,我不知道同样的答案是否也适用于C语言。

这是我编写的示例代码,用于测试发生了什么:

// Difference between logical && and bitwise & //

#include <stdio.h>

#define TRUE 123>45
#define FALSE 4>2342

void print_tt(int table[][4]);

int main(void) {

    int and_tt[2][4];   // AND truth table
    int or_tt[2][4];    // OR truth table

    // Create truth table for logical and bitwise AND operator all in one 2d array
    and_tt[0][0] = TRUE && TRUE ? 1 : 0;
    and_tt[0][1] = TRUE && FALSE ? 1 : 0;
    and_tt[0][2] = FALSE && TRUE ? 1 : 0;
    and_tt[0][3] = FALSE && FALSE ? 1 : 0;
    and_tt[1][0] = TRUE & TRUE ? 1 : 0;
    and_tt[1][1] = TRUE & FALSE ? 1 : 0;
    and_tt[1][2] = FALSE & TRUE ? 1 : 0;
    and_tt[1][3] = FALSE & FALSE ? 1 : 0;

    // Create truth table for logical and bitwise OR operator all in one 2d array
    or_tt[0][0] = TRUE || TRUE ? 1 : 0;
    or_tt[0][1] = TRUE || FALSE ? 1 : 0;
    or_tt[0][2] = FALSE || TRUE ? 1 : 0;
    or_tt[0][3] = FALSE || FALSE ? 1 : 0;
    or_tt[1][0] = TRUE | TRUE ? 1 : 0;
    or_tt[1][1] = TRUE | FALSE ? 1 : 0;
    or_tt[1][2] = FALSE | TRUE ? 1 : 0;
    or_tt[1][3] = FALSE | FALSE ? 1 : 0;

    puts("_______AND_______");
    puts("Logical   Bitwise");
    print_tt(and_tt);

    puts("_______OR________");
    puts("Logical   Bitwise");
    print_tt(or_tt);

}


// prints the truth table of the bitwise and logical operator given side by side
void print_tt(int table[][4]) {
    int i;
    for(i=0; i<4 ; ++i) {
        printf("%-10s%s\n", table[0][i] ? "true" : "false",
            table[1][i] ? "true" : "false");
    }
}

程序的输出是:

_______AND_______
Logical   Bitwise
true      true
false     false
false     false
false     false
_______OR________
Logical   Bitwise
true      true
true      true
true      true
false     false

这证明位运算符和逻辑运算符之间没有区别。更改 TRUEFALSE 宏的定义以包括剩余的比较运算符,可以再次看到没有区别。

因此,如果存在差异,则可能与编译器解释语句的方式或代码的效率有关。

总而言之,在特定情况下,当我们在条件语句中的两个或多个比较运算结果之间使用按位或逻辑运算符时,我们应该使用两者中的哪一个,主要是为了提高效率?

1101 & 0010 = 0000, 1101 && 0010 = True
1101 | 0010 = 1111, 1101 || 0010 = True

原因是按位分别比较每个位,而逻辑将整个位串视为一位真或假。当查看一个位的位串时,逻辑运算符和按位运算符之间确实没有区别。另一种思考方式是按位运算符是从整数到整数的函数,其中逻辑运算符是从布尔值到布尔值的函数。

通过调用 table[0][i] ? "true" : "false",您可以将整数转换为位。如果将其保留为整数,您将看到两种运算符之间的区别。

您只检查值 01。尝试 其他值,您会发现差异。

int a = 4, b = 2;

puts(a && b ? "true" : "false");
puts(a & b  ? "true" : "false");

这会打印:

true
false

按位运算符仅适用于整数。逻辑运算符可用于指针、浮点数和其他非整数类型。

还有短路。如果第一个操作数足够,逻辑运算符将不会计算第二个操作数。

int a() { puts("a"); return 0; }
int b() { puts("b"); return 1; }

int main() {
    puts(a() && b() ? "true" : "false");
    puts("---");
    puts(a() & b()  ? "true" : "false");
}

这会打印:

a
false
---
a
b
false

注意使用 & 时如何打印 b。没有短路,所以 & 调用两个函数,而 && 只调用 a().

更微妙的是,与 && 不同,& 不会对其操作数强加 求值顺序 。输出同样可以将 ab 打印输出颠倒过来。

a
false
---
b
a
false

如果你把所有这些差异放在一边,那么是的,运算符是等价的。那样的话,不用担心效率。使用语义正确的运算符:逻辑运算符。

(如果它能帮助您放松心情,那么效率不会有任何差异。编译器非常聪明,无论您使用哪种运算符,它肯定会发出最佳字节码来评估这些表达式。)

&& 是布尔运算符,而 & 是按位运算符。

& 是对两个整数的 运算。示例:1100 & 1001 = 1101,所以 12 & 9 = 13.

&& 仅检查两个(左和右)值是否为真(即非零)。

例如

1 & 20,因为 1 和 2 的二进制与是 0。示例:01 & 10 = 00

1 && 2 类似于 TRUE && TRUE,也等于 true。所以对于&&,左右两个值都是先"converted"到一个布尔表达式,然后比较。

此外,不要忘记编译器能够短路 && 表达式。喜欢这个:

bool variable = isValid && compareSomething()

不评估正确的值,因为它不需要。第一个已经明确说明了variable就是isValid,只要isValid为真即可。

Read more