【问题标题】:Inline functions in cpp files of shared libraries共享库的 cpp 文件中的内联函数
【发布时间】:2015-12-10 17:28:47
【问题描述】:

据我了解,内联函数可以放在头文件中,也可以放在源文件中(使用 inline 关键字),默认情况下,头文件中定义的成员函数会被编译器尝试内联。

我的问题是以下源文件, 添加.h

#ifndef ADD_H
#define ADD_H
class Add {
    public:
        int add(int a, int b);
};
#endif  /* ADD_H */

添加.cpp

#include <iostream>
#include "add.h"

inline int Add::add(int a, int b) {
    std::cout << "FUNC: " << __func__ << std::endl;
    return a + b;
}

main.cpp

#include "add.h"

int main() {
    Add a;
    a.add(6,7);
    return 0;
}

如果我编译 add.cpp 和 main.cpp

g++ -c add.cpp
g++ -c main.cpp
g++ main.o add.o

它抱怨

main.o: In function `main':
main.cpp:(.text+0x1a): undefined reference to `Add::add(int, int)'
collect2: error: ld returned 1 exit status

查看add.o中的符号,

     U __cxa_atexit
                 U __dso_handle
000000000000003d t _GLOBAL__sub_I_add.cpp
0000000000000000 t __static_initialization_and_destruction_0(int, int)
                 U std::ios_base::Init::Init()
                 U std::ios_base::Init::~Init()
0000000000000000 r std::piecewise_construct
0000000000000000 b std::__ioinit

它没有添加函数,我认为这是因为该函数在 .cpp 中是内联的。我的问题是,当我们有共享库时,是否需要在头文件中定义内联函数(示例中为 add.h),以便使用该库的源文件(示例中为 main.cpp)在创建 obj 时获得内联函数? 在链接时使用 -flto 没有区别,因为 add.o 中不存在函数?

【问题讨论】:

  • 不,不,不。如果一个函数是内联的 - 它是内联的。函数是定义在 .h 头文件还是 .cpp 源文件中都没有关系;它是 .dll/.so 共享库还是 .exe 可执行文件并不重要。一个警告:Why am I getting LNK2019 unresolved external for my inline function?
  • 您也必须在编译时使用 -flto。你试过了吗?

标签: c++ optimization shared-libraries inline compiler-optimization


【解决方案1】:

如果您在头文件中定义一个函数,则每个#includes 该头文件的源文件都会获得该函数的副本。您会收到来自链接器的投诉,指出存在重复定义。

如果您在头文件中定义一个函数将其标记为inline,则#includes 该头文件的每个源文件都会获得该函数的副本,但您已经告诉编译器没关系,链接器不会抱怨。

如果您在源文件中定义了一个函数并且没有将其标记为inline,则它对其他源文件中的代码可见,因此他们可以调用该函数。

如果您在源文件中定义函数并将其标记为inline,则其他源文件中的代码不可见。这就是问题所在:Add 定义在add.cpp 中,并标记为inline,因此main.cpp 看不到它。您可以删除inline 或将定义从add.cpp 移动到add.h。如果将其移至add.h,则可以保持原样并将其放在类定义之后,或者将其直接写在类定义中而不标记inline

链接器优化与此完全分开。正式地,inline 的意思是“如果可以的话,将这个函数扩展成一行”,但是编译器通常比你更清楚应该做什么。链接器优化可以内联扩展函数,而不考虑 inline 关键字,也不考虑其他文件的可见性。但是代码一开始就必须是正确的,所以你必须通过修复代码来解决丢失的符号,而不是试图强制一些链接器优化。

【讨论】:

  • 我认为“链接器优化”是指链接时优化,它是由编译器执行的,而不是链接器。此外,您提到的inline 的“正式”定义远非正式。
【解决方案2】:

您可以将函数定义放在标题中。如果在类定义中定义,则暗示它是内联的。

这个问题有一个很好的答案here

【讨论】:

  • 这就是我现在正在做的事情,这是我的问题,只有这样吗?
  • 啊,我的错,我一定是略过了那部分。在这种情况下,这里有一个类似的问题,有一个很好的解释:stackoverflow.com/questions/3992980/…
  • 感谢链接,我是这么认为的,那么我的问题的第二部分是 -flto 链接时间优化,可以选择吗?
  • 我相信 lto 只能内联它确定可以内联的正常功能。作为次要来源,维基百科关于内联函数的引用似乎表明函数定义必须可用于任何使用声明为内联函数的编译单元。 “在 C++ 中,必须在使用它的每个模块(编译单元)中定义一个内联函数,而普通函数必须仅在单个模块中定义。否则将无法独立于所有模块编译单个模块其他模块。”
猜你喜欢
  • 1970-01-01
  • 2011-04-28
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多