编译器内联函数是否没有实体?

时间:2015-07-01 11:20:54

标签: c++

让我们想象一个包含以下内容的blah.h头文件:

#include "blah.h"

// The code of the inline function
void inline_func() {
    ...
}

// Use the inline function
void foo() {
    inline_func();
}

包含以下内容的blah.cpp源文件:

inline_func()

问题是,编译器是否实际内联inline_func()?代码应该与声明一起使用还是可以分开?

  • 假设没有LTO
  • 请注意{{1}}
  • 中的(GCC)强制内联装饰

3 个答案:

答案 0 :(得分:2)

内联分为两个步骤: * 可能吗? *值得吗?

第一步相当简单地由编译器决定,第二步是更复杂的启发式。因此,仅考虑可能的优化的好处是有意义的。

always_inline表示忽略第二步。它不会影响第一个考虑因素。现在,您还表示LTO已被禁用,这意味着首先考虑的内联能力受到限制。这表明LTOalways_inline非常不相关,因为它们会影响两种不同的内联注意事项。

不管LTO对你的例子是否重要。正在考虑的两项职能属于同一翻译单位。似乎没有其他限制,例如递归,库调用或其他可观察的副作用。这意味着应该可以内联,并且因为这是唯一的考虑因素,所以应该内联。

答案 1 :(得分:1)

嗯,这取决于。在您的示例中,它将被内联,因为函数的定义位于使用它的相同转换单元中。

否则,如果没有LTO是可能的,并且在编译时编译器无法使用该函数的定义,那么不会,该函数将不会内联。

事先答复

答案是:这取决于。这取决于编译器,它也可能依赖于编译器的配置(1) (2)

另请参阅inline description at cppreference.com(引用如下):

  

inline关键字的意图是作为优化器的指示器,该函数的内联替换优先于函数调用,即而不是执行调用CPU指令以将控制转移到函数体,执行函数体的副本而不生成调用。这避免了函数调用(复制参数和检索结果)所产生的额外开销,但它可能导致更大的可执行文件,因为函数的代码必须重复多次。   由于关键字内联的这种含义是非约束性的,编译器可以自由地使用内联替换任何未标记为内联的函数,并且可以自由地生成对内联标记的任何函数的函数调用 。这些选择不会改变有关上面列出的多个定义和共享静态的规则。

答案 2 :(得分:1)

在内联应该发生的时候,你需要让身体可用。

即。如果您有以下文件:

inlineFunc.h
inlineFunc.c
main.c

你编译:

compile inline.c
compile main.c
link innline.o mcompile inline.c

编译main.c 链接innline.o main.o yourCoookProgramain.o yourCoookProgram

inlineFunc无法main.c内联,但inlineFunc中对inlineFunc.c的调用可以内联。

正如Paolo所提到的,inline只是对编译器的暗示,但是一些编译器也有办法强制内置,即对于gcc,你可以使用__attribute__(always_inline)。请点击此处讨论gcc如何处理内联。

An interesting sitenote

  

在这种情况下发出警告,因为foo()的定义不是   编译main()时可用。但是,使用-O2或更好   优化,gcc执行一种“向后内联”,意思是   甚至在源中进一步领先的函数定义   文件可以嵌入到调用者中。因此,警告   一旦使用至少-O2优化就会消失。在那儿   任何特定的选项负责这种行为?我想要   即使使用-O1或-O0也能启用“向后内联”。