C/C++ 之中 inline 是一个很有意思的关键字,奇奇怪怪的用法见过不少,今天抽点时间出来聊聊这个东西。
inline 可以用在那些方面?修饰 inline 内链关键字到底有什么作用?
OK:started
1、inline 可以用在类成员函数的声明上面,如下所示:
class Foo final {
public:
inline Foo() noexcept {
printf("%s\n", ".ctor");
}
inline void Say() {
printf("%s\n", "hello world!");
}
};
上述代码没有必要在函数上显示声明,inline 内链,因为如上述代码,均会被隐式声明为 inline 函数。
无论:上述类实现,写在头文件(.h)或者是源文件(.cpp)之中。
所以:若成员函数实现在类中,不需要显示声明 inline 堆代码字节数。
2、inline 可以用在类成员函数的实现,如下所示:
#include <stdio.h>
class Foo final {
public:
Foo();
void Say();
};
inline Foo::Foo() {
printf("%s\n", ".ctor");
}
inline void Foo::Say() {
printf("%s\n", "hello world!");
}
上述代码可以写在头文件之中,也可以写在源文件之中,但如果取消了 inline,那么写在头文件之中被多个源文件 include 那么就会导致符号重定义冲突,单个源文件引入却不会。
3、inline 可以在全局函数上面修饰,如下所示:
inline int Add(int x, int y) {
return x + y;
}
上述代码可以写在头文件之中,也可以写在源文件之中,但如果取消了 inline,那么写在头文件之中被多个源文件 include 那么就会导致符号重定义冲突,单个源文件引入却不会。
inline 关键字的作用有几个方面:
1、头文件之中定义函数实现
2、建议编译器通过内嵌的方式优化代码执行能效
3、inline 函数,由调用的函数(递归链)的源文件来实现
? ? ?所以:inline 函数可以访问未被它引入的类型或函数,这取决于编译器。
inline 关键字声明并不意味着,编译器会把声明 inline 的函数内嵌到调用该函数的程序之中,这取决于函数的复杂度。
不会被优化,但被声明为?inline 的函数:
1、函数指针或函数引用
2、复杂的 inline 函数体
3、虚函数
4、递归函数
那些函数被声明为 inline 通常会被编译器优化呢?
即单个函数体内,具备少量的 for 循环,逻辑结构简单,嵌套层数少,并且函数体代码行数不多,几行以内的最佳。
例如:
一个简单的加法、乘法、除法函数。
即:
不满足下面这个条件:
inline 函数实现非常复杂,包含大量的代码逻辑、循环或递归等,编译器可能认为将其内联展开会导致代码膨胀,影响可执行文件的大小和性能。
但需要注意一点,inline 是否生效取决于编译器的代码优化级别、跟编译器对于 inline 函数展开的文件大小、及性能的评估。
一个形象的例子:
#include <stdio.h>
class Foo final {
public:
Foo();
void Say();
};
inline Foo::Foo() {
printf("%s\n", ".ctor");
}
inline void Foo::Say() {
printf("%s\n", "hello world!");
}
int main() {
Foo foo;
foo.Say();
return 0;
}
在未打开优化的情况下:
内链函数不会被编译器优化
.LC0:
.string ".ctor"
Foo::Foo() [base object constructor]:
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov edi, OFFSET FLAT:.LC0
call puts
nop
leave
ret
.LC1:
.string "hello world!"
Foo::Say():
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov edi, OFFSET FLAT:.LC1
call puts
nop
leave
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea rax, [rbp-1]
mov rdi, rax
call Foo::Foo() [complete object constructor]
lea rax, [rbp-1]
mov rdi, rax
call Foo::Say()
mov eax, 0
leave
ret
在打开优化的情况下:
内链函数被优化掉到调用方函数之中了
main: # @main
push rax
mov edi, offset .L.str.1
call puts
mov edi, offset .L.str.2
call puts
xor eax, eax
pop rcx
ret
.L.str.1:
.asciz ".ctor"
.L.str.2:
.asciz "hello world!"