c/c 优化脱离检查以查看是否已经运行了一个函数

C/C++ optimizing away checks to see if a function has already been run before

本文关键字:运行 函数 一个 是否 优化 检查      更新时间:2023-10-16

假设您在C/C 中具有一个函数,这是在第一次运行时以某种方式行为。然后,所有其他时间的行为是另一种方式(例如,请参见下文)。第一次运行后,IF语句变为多余,如果速度很重要,则可以优化。有什么方法可以进行此优化?

bool val = true; 
void function1() {
   if (val == true) {
      // do something
      val = false; 
   }
   else {
      // do other stuff, val is never set to true again 
   }
}

gcc具有内置功能,可让您告知有关分支预测的实现:

 __builtin_expect 

http://gcc.gnu.org/onlinedocs/gcc/other-builtins.html

例如,在您的情况下:

bool val = true; 
void function1()
{
    if (__builtin_expect(val, 0)) {
       // do something
       val = false; 
    }
    else {
      // do other stuff, val is never set to true again 
    }
}

只有在确定它确实是瓶颈的情况下,才应该进行更改。通过分支预测,if语句可能是即时的,因为它是一个非常可预测的模式。

也就是说,您可以使用回调:

#include <iostream>
using namespace std;
typedef void (*FunPtr) (void);
FunPtr method;
void subsequentRun()
{
    std::cout << "subsequent call" << std::endl;
}
void firstRun()
{
    std::cout << "first run" << std::endl;
    method = subsequentRun;  
}
int main()
{
    method = firstRun;
    method();
    method();
    method();
}

产生输出:

首次运行
后续呼叫
随后的调用

您可以使用功能指针,但是在任何情况下都需要间接调用:

void (*yourFunction)(void) = &firstCall;
void firstCall() {
 ..
 yourFunction = &otherCalls;
}
void otherCalls() {
 ..
}
void main()
{
  yourFunction();
}

一种可能的方法是编译两个不同版本的函数(这可以通过模板中的源中的一个函数完成),并使用功能指针或对象在运行时决定。但是,除非您的功能真的很昂贵,否则指针开销可能会超过任何潜在的收益。

您可以使用static成员变量而不是全局变量。

或,如果您要运行的代码第一次更改所有以后用途的内容(例如,打开文件?),则可以使用该更改来确定是否运行代码(即,检查文件是否打开)。这将为您节省额外的变量。另外,它可能有助于检查错误 - 如果由于某种原因,另一个操作将初始更改不变(例如,该文件在可移动的媒体上被不适当地删除),则您的检查可能会尝试重新进行更改。

编译器只能优化编译时已知的内容。

在您的情况下,val的值仅在运行时已知,因此无法优化。

if测试非常快,您不必担心优化它。

如果您想使代码有点清洁,则可以使用static局部变量局部。

void function() {
    static bool firstRun = true;
    if (firstRun) {
        firstRun = false;
        ...
    }
    else {
        ...
    }
}

首次输入该函数时,firstRun是正确的,并且它将持续存在,因此每次调用函数时,firstRun变量将与之前的实例相同(并且将为每个后续时间为错误)。

这可以与 @ouah的解决方案一起使用。

诸如G (和我敢肯定MSVC)的编译器支持在第一次运行时生成配置文件数据,然后使用该数据更好地猜测最有可能遵循哪些分支,并相应地优化。如果您使用的是GCC,请查看-fprofile-generate选项。

预期的行为是编译器将优化,如果语句将首先订购,从而避免在所有后续呼叫上进行JMP操作,从而使其速度差不多,就像它不在那儿一样,尤其是尤其是如果您返回其他地方(因此避免了必须跳过"如果"语句)

进行此优化的一种方法是将函数分为二。而不是:

void function1()
{
    if (val == true) {
        // do something
        val = false; 
    } else {
       // do other stuff
    }
}

这样做:

void function1()
{
    // do something
}
void function2()
{
   // do other stuff
}

您可以做的一件事就是将逻辑放入对象的构造函数中,然后将其定义为static。如果这样的 static对象发生在块范围中,则该构造器在执行该范围的执行时间内运行。编译器发出曾经的一次检查。

您还可以将static对象放在文件范围,然后在调用main之前初始化它们。

我给出了这个答案,因为也许您没有有效利用C 类。

(关于C/C++,没有这样的语言。有C,并且有C 。您在C中工作是否也必须编译为C (有时是非正式地称为" Clean C"),还是您真的在工作在C ?)


什么是"清洁c&quot"它与标准C?

有何不同

要保持编译器独立,您可以在一个函数中对if()的零件进行编码,而另一个函数中的 else{}则可以在另一个函数中进行编码。几乎所有编译器都优化了if() else{}-因此,一旦最有可能是else{}-因此,代码if()中的偶尔可执行代码,其余代码在else

中称为单独的函数中。