避免 if 语句的内联函数指针

Posted

技术标签:

【中文标题】避免 if 语句的内联函数指针【英文标题】:Inline function pointer to avoid if statement 【发布时间】:2014-04-07 03:24:11 【问题描述】:

在我的 jpg 解码器中,我有一个带有 if 语句的循环,根据图像,该语句将始终为真或始终为假。我可以创建两个单独的函数来避免 if 语句,但出于好奇,我想知道使用函数指针而不是 if 语句会对效率产生什么影响。如果为真,它将指向内联函数,如果为假,它将指向一个空的内联函数。

class jpg
  private:
    // emtpy function
    void inline nothing();
    // real function
    void inline function();
    // pointer to inline function
    void (jpg::*functionptr)() = nullptr;


jpg::nothing()

main()

  functionptr = &jpg::nothing;
  if(trueorfalse)
    functionptr = &jpg::function;
  

  while(kazillion)

    (this->*functionptr)();

    dootherstuff();

  

这会比 if 语句更快吗? 我的猜测是否定的,因为内联将毫无用处,因为编译器在编译时不知道要内联哪个函数并且函数指针地址解析比 if 语句慢。

我已经对我的程序进行了概要分析,虽然我在运行我的程序时预计会有明显的不同...但我没有遇到明显的不同。所以我只是出于好奇而想知道。

【问题讨论】:

你知道branch prediction吗?这是给你的吗? 我意识到我应该完全避免使用 if 语句,因为它始终为真或永远为假。 @deanresin,你应该按照你的命名约定:trueorfalsedootherstuff @deanresin 我并不是在争论避免 if 语句或将循环放入其中,正如 mbonneau 所建议的那样;我只是建议分支预测可以解释为什么你没有看到太大的差异。 (嗯,这可能是if 语句和指针解析比您所描述的函数体轻量级的事实。) @Mike 我认为你对我的 if 语句/指针解析相对于函数体的其余部分的重要性是正确的。另外.. 并且解释一下.. 我没有注意到差异可能是因为 CPU 的分支预测正在减轻任何潜在的减速。 【参考方案1】:

if 语句很可能比调用函数更快,因为 if 将只是一个短跳转而不是函数调用的开销。

这里已经讨论过了:Which one is faster ? Function call or Conditional if Statement?

“inline”关键字只是提示编译器告诉它在汇编时尝试将指令内联。如果使用指向内联的函数指针,无论如何都不能使用内联优化:

阅读:Do inline functions have addresses?

如果你觉得 if 语句太慢了,你可以通过使用单独的 while 语句来完全消除它:

if (trueorfalse) 
    while (kazillion) 
        trueFunction();
        dootherstuff();
    
 else 
    while (kazillion) 
        dootherstuff();
    

【讨论】:

【参考方案2】:

警告 1:我并不是故意回答上述问题。如果想知道上例中通过指针的 if 语句和函数调用之间哪个更快,那么 mbonneau 给出了一个很好的答案。

注意2:以下为伪代码。

除了好奇之外,我真的认为人们不应该问自己在 if 语句和函数调用之间哪个更快以优化他的代码。收益肯定会非常小,并且生成的代码可能会被扭曲,从而影响可读性和维护。

对于我的研究,我确实关心性能,这是我必须坚持的基本概念。但是我更关心代码维护,如果我必须在一个好的结构和轻微的优化之间做出选择,我肯定会选择好的结构。然后,如果是我,我会编写上面的代码如下(避免使用 if 语句),通过 Strategy Pattern 使用组合。

class MyStrategy 
  public:
    virtual void MyFunction( Stuff& ) = 0;
;

class StrategyOne : public MyStrategy 
  public:
    void MyFunction( Stuff& ); // do something
;

class StrategyTwo : public MyStrategy 
  public:
    void MyFunction( Stuff &stuff )   // do nothing, and if you 
                                        // change your mind it could
                                        // do something later.
;

class jpg
  public:
    jpg( MyStrategy& strat) : strat(strat)  
    void func( Stuff &stuff )  return strat.MyFunction( stuff ); 
  private:
    ...
    MyStrategy strat;


main()

  jpg a( new StrategyOne );
  jpg b( new StrategyTwo );
  vector<jpg> v  a, b ;

  for( auto e : v )
  
    e.func();

    dootherstuff();

  

【讨论】:

我的印象是virtual methods are essentially the same as function pointers 在这个意义上;两者都需要解决,而解决方案会减慢速度。这不是真的吗? @Mike 是的,这是真的。实际上,我并没有真正回答这里提出的问题,我应该在我的回答中指定这一点(现在会这样做)。我的观点是,即使有人真的关心性能(就像我一样),我不确定在优化代码时寻找 if 语句和函数指针之间更快的问题是正确的问题。这不是这里的情况,因为 deanresin 明确表示这是为了满足他/她的好奇心。

以上是关于避免 if 语句的内联函数指针的主要内容,如果未能解决你的问题,请参考以下文章

C语言-内联函数递归函数指针函数

gcc 可以通过函数指针的常量数组内联间接函数调用吗?

谜团:将 GNU C 标签指针转换为函数指针,并使用内联 asm 在该块中放置一个 ret。块被优化掉?

C++初阶extern C,引用,内联函数,auto和指针空值

使用函数指针和多态代替冗长的if-else或者switch-case

使用功能指针的STL映射