【问题标题】:Can b&&0 be optimizedb&&0可以优化吗
【发布时间】:2021-04-24 12:50:33
【问题描述】:

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

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

但是不知道b && 0是否可以被编译器优化?编译器可以说:好的,0 的求值比b 的求值要容易得多,而且b 没有任何副作用,所以我决定将b && 0 改成0 && b 来求值@987654334先@@。

【问题讨论】:

  • 取决于编译器 - 如果您查看汇编输出,则最简单。除非 b 是一个函数,否则编译器甚至可能不会生成任何代码,因为表达式始终为 false。
  • 如果b 没有可观察到的行为并且编译器可以证明它,它很可能不会在运行时评估它。演示:godbolt.org/z/scs3je。请注意,这与首先评估 0 无关;这是关于 as-if 规则的。
  • @DanielLangr 那么如果b 是一个函数呢?

标签: c++ c compiler-optimization boolean-expression


【解决方案1】:

您的问题涉及两个独立的问题。首先是当编译器“看到”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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2013-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      相关资源
      最近更新 更多