编译器能否简化涉及函数的逻辑表达式?

4

一些计算布尔值的函数:

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();
}

4
只要知道这些函数是“纯函数”,就可以将其描述为这样。 - user166390
2
bool c() { static bool r=true; r = !r; return r;}(例如)。 - Mooing Duck
如果你使用变量而不是函数调用,那么编译器会进行优化。 - N_A
如果你想要这样进行优化,为什么一开始要编写过于复杂的条件语句呢? - UncleBens
1
我认为值得尝试简化它。如果它太复杂了,你怎么能指望代码的读者(包括你自己)以后能理解它呢?也许还可以尝试将条件提取到单独的函数中? - UncleBens
显示剩余3条评论
5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
4

由于函数可能会产生副作用,条件语句无法进行任何“优化”,因为所有函数都必须以明确定义的方式(有条件地)调用。

如果您确实想要优化,可以先将结果分配给变量:

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)
{
  // ...
}

2

不会。原因是优化将对用户可见,因为它会改变可观测的副作用。例如,在您优化后的版本中,尽管用户明确尝试执行c(),但其实际上将永远不会执行。这可能会导致错误。


1
一个函数可能是无副作用的,但我认为它仍然不是纯的。 - user166390
但是编译器能够检测到纯函数并在这种情况下对其进行优化吗? - TravisG
@heishe 纯函数是什么,如何检测它?编译器将执行优化,主要通过函数内联来简化复杂表达式。 - Šimon Tóth
@heishe 我相信有一个子集编译器具有纯函数的内在概念,可以实现这一点。但这显然不是大多数主流编译器的特性。 - JaredPar

1

在C语言中,函数的返回值通常表示函数是否成功执行。例如调用图形例程、转换文件等。想想你有多经常使用指针来改变函数外部的东西,或者调用另一个输出内容的函数。正如某人所说,这不是函数式编程。

如果编译器能够确定foo()会改变但不做任何事情,那么它可以简化它,但我不会指望它。

这里有一个非常简单的例子。

bool foo()
{
    std::cout << "this needs to be printed each time foo() is called, even though its called in a logical expression\n";
    return true;
}

int main()
{
    if ((foo() && !(foo()) || foo() && !(foo())))
        return 0;

    return 1;
}

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


1

由于你的前提是错误的,所以不会。

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

C(和C ++)不是函数式编程语言(如Haskell)。


1

但问题在于,一般情况下它无法以那种方式进行重构!

如果任何一个函数具有更改c()结果的副作用,则第二次调用可能会返回与第一次不同的结果。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,