Can/do编译器简化了涉及函数的逻辑表达式

Can/do compilers simplify logical expressions involving functions?

本文关键字:函数 表达式 do 编译器 Can      更新时间:2023-10-16

一些计算布尔值的函数:

bool a()
{
   return trueorfalse;
}
bool b()
{
   //...
}
bool c()
{
   //...
}
这种情况

//somewhere else
if((a()&&b()&&c()) || (a()&&b()&&!c()) )
{
    doSomething();
}

也可以写成

if(a()&&b())
{
   doSomething();
}

编译器通常会把它优化掉吗?

那么纯布尔值呢:

if((a&&b&&c) || (a&&b&&!c))
{ 
   doSomething();
}

由于函数可能有副作用,因此不能以任何方式"优化"条件,因为所有函数都必须以良好定义的方式(有条件地)调用。

如果你想优化,你可以先把结果赋值给变量:

const bool ba = a(), bb = b(), bc = c();
if (ba && bb && bc || ba && bb && !bc) { /* ... */ } // probably optimized to "ba && bb"

在c++ 11中引入的constexpr函数有可能允许优化,如果它们产生一个常量表达式,但我不确定。

您甚至可以将其压缩:在以下代码中,f()必须被调用两次:

if (f() && false || f() && true)
{
  // ...
}

不,他们不会。原因是优化将对用户可见,因为它将改变可观察到的副作用。例如,在你的优化版本中,c()永远不会执行,即使用户明确地尝试这样做。这个可以并且将会导致bug。

既然你的前提是有缺陷的,不,他们不会。

(a()&&b()&&c()) || (a()&&b()&&!c())绝对不能重写为(a()&&b())

C(和c++)不是函数式编程语言(像Haskell)

但问题是,一般来说,它不能以这种方式重构 !

如果任何函数都有改变c()结果的副作用,那么第二次调用可能会返回与第一次不同的结果。

不仅如此,由于短路执行,事情可能会变得更加混乱。

在C语言中,函数的返回值通常给出了函数是否成功执行。例如调用图形例程,转换文件。想想你有多频繁地使用指针来改变函数外部的东西。或者调用另一个输出的函数。有人说这不是函数式编程。

如果编译器能够确定foo()变化而不做任何事情,那么它可能会通过各种方式简化它,但我不会指望它。

下面是一个非常简单的例子

bool foo()
{
    std::cout << "this needs to be printed each time foo() is called, even though its called in a logical expressionn";
    return true;
}
int main()
{
    if ((foo() && !(foo()) || foo() && !(foo())))
        return 0;
    return 1;
}

编辑任何布尔代数的变量都应该简化。