共享库的 cpp 文件中的内联函数
Inline functions in cpp files of shared libraries
根据我的理解,内联函数可以进入 headers 以及源文件(使用 inline 关键字)并且默认情况下 headers 中定义的 memeber 函数会被编译器尝试内联。
我的问题是关于以下源文件,
add.h
#ifndef ADD_H
#define ADD_H
class Add {
public:
int add(int a, int b);
};
#endif /* ADD_H */
add.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 中是内联的。我的问题是当我们有共享库时,是否需要在 headers(示例中的 add.h)中定义内联函数,以便使用库的源文件(示例中的 main.cpp)获取obj 创建本身内联的功能?
在链接时使用 -flto 没有任何区别,因为 add.o?
中不存在函数
您可以将函数定义放在 header 中。如果它是在 class 定义中定义的,则暗示它是内联的。
这个问题有很好的答案here
如果您在头文件中定义一个函数,#include
该头文件的每个源文件都会获得该函数的副本。您会收到链接器的投诉,指出存在重复定义。
如果您在头文件中定义一个函数 并且 标记它 inline
,每个 #include
该头文件的源文件都会获得该头文件的副本功能,但你已经告诉编译器那没关系,链接器不会抱怨。
如果您在源文件中定义了一个函数并且没有标记它inline
它对其他源文件中的代码可见,因此他们可以调用该函数。
如果您在源文件中定义一个函数并对其进行标记inline
,它对其他源文件中的代码不可见。这就是这里的问题:Add
定义在 add.cpp
中,它被标记为 inline
,所以它对 main.cpp
不可见。您可以删除 inline
或将定义从 add.cpp
移动到 add.h
。如果你把它移动到add.h
你可以保持原样放在class定义之后,或者你直接写在class定义里面而不标记它inline
.
链接器优化与此完全分开。形式上,inline
表示 "expand this function in line if you can",但编译器通常比您更了解应该做什么。链接器优化可以内联扩展函数,无需考虑 inline
关键字,也无需考虑其他文件的可见性。但是代码一开始就必须是正确的,因此您必须通过修复代码来解决丢失的符号,而不是通过尝试强制进行某些链接器优化。
根据我的理解,内联函数可以进入 headers 以及源文件(使用 inline 关键字)并且默认情况下 headers 中定义的 memeber 函数会被编译器尝试内联。
我的问题是关于以下源文件, add.h
#ifndef ADD_H
#define ADD_H
class Add {
public:
int add(int a, int b);
};
#endif /* ADD_H */
add.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 中是内联的。我的问题是当我们有共享库时,是否需要在 headers(示例中的 add.h)中定义内联函数,以便使用库的源文件(示例中的 main.cpp)获取obj 创建本身内联的功能? 在链接时使用 -flto 没有任何区别,因为 add.o?
中不存在函数您可以将函数定义放在 header 中。如果它是在 class 定义中定义的,则暗示它是内联的。
这个问题有很好的答案here
如果您在头文件中定义一个函数,#include
该头文件的每个源文件都会获得该函数的副本。您会收到链接器的投诉,指出存在重复定义。
如果您在头文件中定义一个函数 并且 标记它 inline
,每个 #include
该头文件的源文件都会获得该头文件的副本功能,但你已经告诉编译器那没关系,链接器不会抱怨。
如果您在源文件中定义了一个函数并且没有标记它inline
它对其他源文件中的代码可见,因此他们可以调用该函数。
如果您在源文件中定义一个函数并对其进行标记inline
,它对其他源文件中的代码不可见。这就是这里的问题:Add
定义在 add.cpp
中,它被标记为 inline
,所以它对 main.cpp
不可见。您可以删除 inline
或将定义从 add.cpp
移动到 add.h
。如果你把它移动到add.h
你可以保持原样放在class定义之后,或者你直接写在class定义里面而不标记它inline
.
链接器优化与此完全分开。形式上,inline
表示 "expand this function in line if you can",但编译器通常比您更了解应该做什么。链接器优化可以内联扩展函数,无需考虑 inline
关键字,也无需考虑其他文件的可见性。但是代码一开始就必须是正确的,因此您必须通过修复代码来解决丢失的符号,而不是通过尝试强制进行某些链接器优化。