编译器或链接器内联函数的区别?
我想知道链接器级别或编译器级别的内联函数在执行速度方面是否有任何区别?
例如,如果我将所有函数都放在 .cpp 文件中,并依赖链接器进行内联,那么这种内联可能会比在头文件中定义一些函数以在编译器级别或统一构建中选择内联而没有任何链接和所有的效率低吗?内联由编译器完成?
如果链接器同样高效,为什么还要在编译器级别显式地内联函数呢?这是否只是为了方便,假设只有一个单行构造函数,因此不必担心 .cpp 文件?
我想这可能取决于编译器,在这种情况下我对 Visual C++ (Windows) 和 gcc (Linux) 最感兴趣。
谢谢
I am wondering whether there is any difference between inlining functions on a linker level or compiler level in terms of execution speed?
e.g. if I have all my functions in .cpp files and rely on the linker to do inlining, will this inlining potentially be less efficient than say defining some functions in the headers for selected inlining on the compiler level or unity builds without any linking and all inlining done by the compiler?
If the linker is just as efficient, why would one then still bother inlining functions explicitly on the compiler level? Is that just for convenience, say there is just a one line constructor hence one can't be bothered with a .cpp file?
I suppose this might depend on the compiler, in which case I would be most interested in Visual C++ (Windows) and gcc (Linux).
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一般规则是在其他条件相同的情况下,越接近执行(编译->链接->(可能是 JIT)->执行),优化器拥有的数据越多,可以执行的优化就越好。因此,除非优化器很愚蠢,否则当链接器完成内联时,您应该期待更好的结果 - 链接器将 了解更多有关调用上下文的信息并进行更好的优化。
The general rule is all else being equal the closer to execution (compiling->linking->(maybe JIT)->execution) the optimization is done the more data the optimizer has and the better optimization it can perform. So unless the optimizer is dumb you should expect better results when inlining is done by the linker - the linker will know more about the invokation context and do better optimization.
一般来说,当链接器运行时,您的源代码已经被编译成机器代码。链接器的工作是获取所有代码片段,然后链接在一起(可能一路上修复地址)。在这种情况下,没有空间进行内联。
但一切并没有失去。 Gcc 确实提供了编译和链接时链接时间优化的机制(使用 -flto)选项。这会导致 gcc 生成字节代码,然后链接器可以将其编译并链接到单个可执行文件中。由于字节码比优化的机器码包含更多的信息。链接器现在可以对整个代码库执行彻底优化。编译器无法执行的操作。
有关 gcc 的更多详细信息,请参阅此处。但不确定 VC++。
Generally, by the time the linker is run, your source has already been compiled into machine code. The linkers job is to take all the code fragments and link then together (possibly fixing addresses along the way). In such a case, there is no room for performing inlining.
But all is not lost. Gcc does provide a mechanism for link time optimization (using the -flto) option when compiling and linking. This causes gcc to produce a byte code that can then be compiled and linked by the linker into a single executable. Since the byte code contains more information than optimized machine code. The linker can now perform radical optimization on the whole codebase. Something that the compiler cannot do.
See here for more details on gcc. Not to sure about VC++ though.
内联通常在单个翻译单元(.cpp 文件)内执行。当您调用另一个文件中的函数时,它们永远不会被内联。
链接时间优化 (LTO) 改变了这一点,允许内联跨翻译单元工作。就生成代码的效率而言,它应该始终等于或优于常规链接(有时非常非常显着)。
这两个选项仍然可用的原因是 LTO 可能会占用大量 RAM 和 CPU – 我之前曾让 VC++ 花费几分钟来链接大型 C++ 项目。有时在发货之前不值得启用。对于足够大的项目,您也可能会耗尽地址空间,因为它必须将所有字节码加载到 RAM 中。
为了编写高效的代码,没有任何改变——所有相同的规则都适用于 LTO。在头文件中显式定义内联函数可能比依赖 LTO 内联函数更有效。 inline 关键字仅提供提示,因此无法保证,但它可能会将其推入内联,而通常情况下(无论有或没有 LTO)它不会内联。
Inlining is normally performed within a single translation unit (.cpp file). When you call functions in another file, they’re never inlined.
Link Time Optimization (LTO) changes this, allowing inlining to work across translation units. It should always be equal or better (sometimes very very significantly) to regular linking in terms of how efficient the generated code is.
The reason both options are still available is that LTO can take a large amount of RAM and CPU – I’ve had VC++ take several minutes on linking a large C++ project before. Sometimes it’s not worth it to enable until you ship. You could also run out of address space with a large enough project, as it has to load all that bytecode into RAM.
For writing efficient code, nothing changes – all the same rules apply with LTO. It is potentially more efficient to explicitly define an inline function in a header file versus depending on LTO to inline it. The inline keyword only provides a hint so there’s no guarantee, but it might nudge it into being inlined where normally (with or without LTO) it wouldn’t be.
如果函数内联,则不会有任何区别。
我相信在标题中定义内联函数的主要原因是历史。另一个是便携性。直到最近,大多数编译器都没有进行链接时代码生成,因此必须在标头中包含函数。这当然会影响几年前开始的代码库。
另外,如果您仍然以某些不支持链接时代码生成的编译器为目标,那么您别无选择。
顺便说一句,在一种情况下,我被迫添加一个编译指示,要求某个特定编译器不内联一个 .cpp 文件中定义的 init() 函数,但可能会从多个地方调用该函数。
If the function is inlined, there would be no difference.
I believe the main reason for having inline functions defined in the headers is history. Another is portability. Until resently most compilers did not do link time code generation, so it having the functions in the headers was a necessity. That of course affects code bases started on more than a couple of years ago.
Also, if you still target some compilers that don't support link time code generation, you dont have a choice.
As an aside, I have in one case been forced to add a pragma to ask one specific compiler not to inline an init() function defined in one .cpp file, but potentially called from many places.