b&&0可以优化吗

Can b&&0 be optimized

我知道C/C++使用短路计算来计算布尔表达式。例如,C/C++肯定会在表达式a && b中的操作数b之前计算操作数a,如果a为假,b 不会被评价。

此外,我知道 5==6 之类的东西可能会被编译器完全忽略,因为它是一个常量表达式,可以在编译时求值。

但是不知道b && 0能不能被编译器优化?编译器可以说:好的,0 的计算比 b 的计算容易得多,而且 b 没有任何副作用,所以我决定更改 b && 0进入 0 && b 以首先评估 0

你的问题涉及两个独立的问题。第一个是,当编译器“看到”if 条件总是 false(由于 && 0)时,它可以完全丢弃相应的分支。示例翻译单元:

bool f(int);

int main()
{
  if (f(1) && 0)
    return 1;
}

启用优化后,很可能不会为分支生成机器代码。但是,f(1) 表达式仍必须在运行时进行计算,因为编译器无法证明 f(1) 调用没有可观察到的行为。

机器码:https://godbolt.org/z/sEMrfh

相反,如果编译器能够证明f(1)没有可观察到的行为,它就可以消除它的调用。这与评估顺序无关,而是与 as-if 规则有关。演示翻译单元:

static bool f(int i)
{
  int j = i + 1;
  return true;
}

int main()
{
  if (f(1) && 0)
    return 1;
}

机器码:https://godbolt.org/z/scs3je

&&|| 运算符保证从左到右求值。评估意味着编译器必须检查操作数的副作用,如果存在副作用,则必须执行这些副作用。如果 && 的左操作数计算为零,则不会计算右操作数。

考虑if(func() && 0) { do_stuff(); }。即使 && 表达式永远不会为真,函数仍然必须执行。编译器不会做一些奇怪的重新排序,例如 0 && func(),它只会用 func(); 替换整个表达式,删除 ifdo_stuff() .

一般来说,编译器明确不允许对&&||的操作数的求值或执行进行重新排序;他们在左右操作数的求值之间有一个所谓的序列点。这反过来又允许像 (ptr=malloc(...)) && (*ptr = x) 这样的代码定义明确,并且在 malloc 失败的情况下不访问空指针。