【问题标题】:C++ - When function inlining is not possible?C++ - 当函数内联是不可能的?
【发布时间】:2011-11-04 13:59:57
【问题描述】:

伙计们,

我在阅读“Thinking in C++"(Chap - 内联函数)时遇到了这个语句。

"编译器也不能执行内联,如果 函数被隐式或显式采用”。

taking address of function implicitly or explicitly”是什么意思?
为什么在这种情况下不能内联?

谢谢。

【问题讨论】:

  • 如果函数是“内联”的,它的地址在哪里?

标签: c++ inline-functions object-address


【解决方案1】:

实际上,报价可能会产生误导。

如果取了函数地址,那么就需要在库/可执行文件中生成函数,因为函数的地址执行在于将指令指针跳转到描述函数的代码块。

但是,当直接调用时,它当然不会阻止编译器在其他地方内联函数。

首先,回顾一下:

// Explicit:
void foo();

void (*func_ptr)() = foo;


// Implicit
struct Foo { virtual void bar() {} }; // address used in V-Table

二、内联示例:

int main() {
  (*func_ptr)(); // probably not inlined as the compiler can difficultly assert
                 // that nobody may modified it... since it's non-const.

  foo(); // might be inlined

  Foo f;
  f.bar(); // might be inlined (the exact type of `f` is known)
           // this is called, "devirtualizing"

  Foo& g = accessSomeFoo();
  g.bar(); // probably not inlined unless the compiler can assert
           // the type returned by accessSomeFoo
           // (which requires knowing its definition)
}

【讨论】:

    【解决方案2】:

    我不确定这是否完全正确。但是,如果您获取函数的地址,则该函数需要存在于内存中,并带有函数的前导码和清理代码。内联时省略了这个序言和清理。内联时,您会获得大量优化可能性。

    但是现代编译器仍然应该能够内联函数,只要有可能内联它。考虑:

    int compare (int a, int b)
    {
      return a compared to b
    }
    
    int main ()
    {
      a = array of ints
    
      qsort (a, compare); // take address of compare function, thus compare function exists in
                          // app as a proper function
    
      compare (value1, value2); // there's no reason why this can't be inlined
    }
    

    我认为引用应该更明确地说明不能内联的内容:

    通过函数指针调用的函数不能内联。

    这是因为在编译时无法确定在间接调用(通过函数指针的调用)处内联哪个函数。这并不是说函数指针指向的函数不能在任何直接调用的地方内联。

    【讨论】:

    • 你答案的最后一点不一定是真的。请参阅我对@Peter 的回答的评论。
    • @Oli:是的,我想一个可以在编译时推导出来的函数指针肯定可以被内联,尽管我想不出为什么有人会费力地创建一个函数指针,为其分配一个函数并通过它进行间接调用,而不是直接调用该函数。也许如果你使用模板。
    【解决方案3】:

    获取函数地址意味着assigning it to a function pointer。这可以显式发生,如链接示例中所示。我不确定作者所说的“隐式”是什么意思——也许是把一个函数作为参数传递给另一个函数。

    如果函数的地址被占用,它必须首先有一个地址。由于内联意味着基本上用函数体的副本替换对函数的调用,在这样的转换之后,函数不再存在,因此没有地址 - 只有 n 个不同的相同代码副本在使用的地方调用该函数。因此,如果一个函数的地址以任何方式被使用,它就不能被内联。

    【讨论】:

    • 嗯,理论上可以。 void foo(void); void (*p)(void) = &foo; p(); 之类的代码可以由编译器优化。
    • 这是否意味着对速度进行了优化的编译器将内联我不使用函数指针做任何事情的所有内容?
    • @heishe:编译器有启发式方法来尝试猜测是否内联更好。这是一个复杂的主题(您需要推理缓存/寄存器/等......)并且高度特定于架构。不要太担心它;)
    • @heishe :如果你的函数有一个循环,那么它被内联的可能性很小甚至没有。所以你知道,编译器对内联是有选择性的,即使我们提示它内联某个函数。
    猜你喜欢
    • 2017-01-05
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 2011-03-20
    • 2011-04-18
    • 2011-08-23
    • 1970-01-01
    相关资源
    最近更新 更多