【问题标题】:Can/do compilers simplify logical expressions involving functions?编译器可以/是否简化涉及函数的逻辑表达式?
【发布时间】:2011-09-01 18:23:32
【问题描述】:

一些计算布尔值的函数:

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

【问题讨论】:

  • 可以写成只知道函数是pure functions
  • 我不这么认为,除非它可以证明 c 每次调用都返回相同的结果,并且它可能还必须尝试内联 c。
  • bool c() { static bool r=true; r = !r; return r;} 例如。
  • 如果你使用变量而不是函数调用,那么,是的,编译器会优化。
  • 我认为值得尝试简化它。如果它那么复杂,您如何期望您的代码的读者(包括您自己)以后能够理解它?也许还尝试将条件提取到单独的函数中?

标签: c++ c compiler-optimization


【解决方案1】:

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

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

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() 永远不会执行,即使用户明确尝试这样做。这可以并且将会导致错误。

    【讨论】:

    • 我相信,一个函数也有可能没有副作用但仍然不纯。
    • 但是在这种情况下编译器会检测到纯函数并对其进行优化吗?
    • @heishe 什么是纯函数,如何检测它?是的,编译器会进行优化,主要是通过函数内联来简化复杂的表达式。
    • @heishe 我确信有一个编译器子集有一个固有的纯函数概念可以做到这一点。不过,这当然不是大多数主流编译器的功能。
    【解决方案3】:

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

    (a()&&b()&&c()) || (a()&&b()&&!c())绝对不能改写成(a()&&b())

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

        在 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;
        }
        

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

        【讨论】:

          猜你喜欢
          • 2022-06-23
          • 2011-11-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-20
          相关资源
          最近更新 更多