C++ "and"、"&&"和"bitand"之间的区别

C++ difference between "and", "&&" and "bitand"

本文关键字:之间 区别 bitand C++ and      更新时间:2023-10-16

我想知道以下两者之间的速度或性能是否有任何差异C++:

和操作:&&, and, bitand

手术室操作:||, or, bitor

还是他们所有人的表现都一样?

在详细介绍之前,&&and是等价的,&bitand||or以及|bitor也是等价的。更多详情请见 cppreference.com

它们之间肯定有区别,所以让我们更详细地看一下它们:

  • &&||逻辑运算符。他们的结果要么是true要么是false,没有别的。
    如果至少一个操作数(||)或两个操作数(&&)不false,则结果truefalse其他结果。

  • &|按位运算符。它们独立地操作操作数的每一部分。
    这主要用于对数字的位微调操作,例如将数字的最底层 3 位以外的所有位设置为 0(考虑它们的二进制表示):

    int result1 = number & 0b111;
    // or to set the 3 lowermost bits to 1
    int result2 = number | 0b111;
    

您可能知道,对于条件语句,C++中的每个数字都可以解释为布尔值,更具体地说,0 是false,其他所有内容都是true的。这可能会导致一些混淆,如以下示例所示:

int a = 1;
int b = 2;
if (a && b) {
std::cout << "a && bn";
}
if (a & b) {
std::cout << "a & bn";
}

这将只输出a && b,因为a & b是 0,因此false,即使ab两者都不是false

简而言之,使用&&||进行逻辑运算,&|用于数字的按位运算,但要注意副作用:

除了使用范围不同外,这些运算符之间还有另一个区别,即逻辑运算符的强制短路评估(&&||)。这意味着,如果我们已经通过计算第一个操作数知道表达式的结果,则不得计算第二个操作数。这意味着以下两段代码是等效的:

bool result = is_this_true() && is_that_true();
// equivalent:
bool result;
if (is_this_true()) {
result = is_that_true();
} else {
result = false;
}

逻辑或运算符也是如此:

bool result = is_this_true() || is_that_true();
// equivalent:
bool result;
if (is_this_true()) {
result = true;
} else {
result = is_that_true();
}

这是因为

  1. 如果&&的一个操作数是false,则结果总是false
  2. 如果||的一个操作数是true,则结果总是true

与按位运算符相比,这肯定会对性能产生影响,基本上有两种不同的方式:

  1. 如果is_that_true()评估需要大量时间,那么在结果短路的情况下,短路评估可能会节省您的时间。

  2. 如果is_this_true()is_that_true()的计算都非常快,但有编译器无法摆脱的副作用,那么等效if语句引入的额外分支可能会涉及很小的性能损失(有关更多详细信息,请阅读分支错误预测)。但是,在大多数情况下,这种性能差异非常小,除非对这些逻辑运算符的评估是性能瓶颈(同样,这应该非常不可能),否则您永远不必担心它。

如果您想了解更多信息,已经有几个答案详细介绍了短路评估的影响,例如 是否强制要求短路逻辑运算符?和评估顺序?

或者他们所有人的表现都是一样的?

这是一个苹果/橙子的问题。andbitand执行不同的工作。

例:

bool both_nonzero(int x, int y)
{
return x and y;
}
bool have_corresponding_bits(int x, int y)
{
return bool(x bitand y);
}

相应的汇编程序 (gcc-x86_64 -O3):

both_nonzero(int, int):
test    edi, edi
setne   al
test    esi, esi
setne   dl
and     eax, edx
ret
have_corresponding_bits(int, int):
test    edi, esi
setne   al
ret

如您所见,第二个函数需要的指令较少,但从 CPU 的角度来看,它正在执行更简单的任务(按位运算是 CPU 一生工作的面包和黄油)。