我曾经认为编译器会在编译时决定是否内联函数。
但后来我在“Effective C ++”中找到了这个代码示例:
inline void f() {} // assume compilers are willing to inline calls to f
void (*pf)() = f; // pf points to f
f(); // this call will be inlined, because it's a "normal" call
pf(); // this call probably won't be, because it's through a function pointer
现在我很困惑,这是否意味着决定是否内联函数是在运行时完成的,具体取决于您使用该函数的方式?
答案 0 :(得分:4)
不,它仍然在编译时完成。在您的示例中,实际上有两个版本的函数由编译器创建,一个是内联版,另一个不是。
有时编译器有足够的信息来通过静态分析知道指针指向哪个函数,并且无论如何都可以内联它。
答案 1 :(得分:4)
内联是在编译时或链接时完成的(似乎编译器已经确定它们在链接时确定了某些内联可能性并且跨翻译单元这样做了。)
不清楚pf()
是否会导致内联的原因尚不清楚,如果pf
可以证明pf
将指向pf()
,那么编译器可能会内联void simple()
{
void (*pf)() = f;
pf();
}
指向的内容每次调用pf
时都会执行某个功能!在某些设置中,这可以通过基于常量表达式确定值来完成。例如:
f
证明f
始终指向{{1}}相对简单。如果{{1}}可以内联,则可以安全地执行。如果事情变得更复杂,例如,某些条件或涉及其他功能的调用,事情变得非常复杂,以至于决定肯定不再容易。
答案 2 :(得分:1)
内容是否内联是代码生成的一部分。这是编译器的工作。问题,内联是在编译时完成的。但仅仅因为函数在某些地方被内联,并不意味着它必须在所有地方内联。因此,f()
来电的内联完全没问题,而pf()
的来电则不然。
但是,请注意,如果编译器能够证明pf
在特定的调用点始终指向f
,那么即使该调用也可以内联。我不知道任何编译器是否走得这么远,但肯定是允许的。
答案 3 :(得分:0)
我的理解是内联是在编译时完成的。然而,它也有一个链接器阶段部分。
内联是对编译器的“请求”。哪个可以忽略。
时间:当功能太复杂时。 或者在以下情况:有人获取函数的地址(正如您给出的示例所做的那样)。
当有人获取该函数的地址时,则表示该函数必须占用存储空间。编译器会为它创建存储空间。
然后出现了内联函数在头文件中的问题,这些头文件包含在许多地方。 它应该在链接时导致“多重定义”错误。
但在这种情况下,链接器“被忽略”多个定义。
来源:用C ++思考,第434页,最后一段。