共享库的cpp文件中的内联函数

Inline functions in cpp files of shared libraries

本文关键字:函数 文件 cpp 共享      更新时间:2023-10-16

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

我的问题是以下源文件,add.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?

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

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

如果你在源文件中定义了一个函数,但没有将其标记为inline,那么其他源文件中的代码可以看到它,所以他们可以调用该函数。

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

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

您可以将函数定义放入标头中。如果它是在类定义中定义的,那么它就意味着是内联的。

这个问题在这里有一个很好的答案