本文共 2176 字,大约阅读时间需要 7 分钟。
C++深度解析 内联函数分析(5)
宏
#define
宏定义会经过预处理器,只是进行文本替换,缺点在于不会进行语法和语义检查的,仅仅是复制、粘贴的过程,编译器根本不知道宏的存在。
所以,C++中,当需要某个类型的常量时,可以使用const常量 来代替 宏常数,如:
const int A = 3 <<<-------替代------->>> #define A 3
内联函数 inline
使用内联函数 替代 宏代码片段。
使用inline关键字声明内联函数。
内联函数没有普通函数调用的时候的额外开销(参数的入栈,函数的返回,跳转)。
内联函数会被编译器优化,编译器直接将内联函数的函数体进行扩展,扩展到调用内联函数的地方。
C++编译器不一定满足函数的内联请求!
示例代码一:(宏)
#include//宏代码块#define FUNC(a, b) ((a) < (b) ? (a) : (b))inline int func(int a, int b){ return a < b ? a : b;}int main(int argc, char *argv[]){ int a = 1; int b = 3; //FUNC(++a, b)会被预处理器展开为:((++a) < (b) ? (++a) : (b)) int c = FUNC(++a, b); //((++a) < (b) ? (++a) : (b)); printf("a = %d\n", a); // 3 printf("b = %d\n", b); // 3 printf("c = %d\n", c); // 3 return 0;}
结果如下:
因为FUNC是一个宏定义,文本替换。比较时候++a:a=2。如果条件成立++a:a=3。(从而a被加了两次)由此看来,使用宏定义是有副作用的。
示例代码二:(内联函数)
#include#define FUNC(a, b) ((a) < (b) ? (a) : (b))inline int func(int a, int b){ return a < b ? a : b;}int main(int argc, char *argv[]){ int a = 1; int b = 3; int c = func(++a, b); printf("a = %d\n", a); // 2 printf("b = %d\n", b); // 3 printf("c = %d\n", c); // 2 return 0;}
结果如下:
内联函数直接将函数体插入到调用的地方。示例中,int c = func(++a, b)调用了内联函数,所以把函数体直接扩展到func(++a, b)。
内联函数总结:
内联函数具有普通函数的特征(参数检查,返回类型等)
函数的内联请求可能被编译器拒绝(通过配置的方式,让编译器接受内联请求)
函数被内联编译后,函数体直接扩展到调用的地方。
(宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程,因此可能出现副作用)
因此,在C++编程中,首选内联函数,而不是宏代码片段。
对函数进行强制内联
g++:__attribute__((always_inline))属性,当一个函数拥有这个属性后,这个函数就会被g++编译器强制内联
MSVC:__forceinline
示例代码一:
#include//__forceinline //MSVC__attribute__((always_inline)) // g++//inlineint add_inline(int n);int main(int argc, char* argv[]){ int r = add_inline(10); printf("r = %d\n", r); return 0;}inline int add_inline(int n){ int ret = 0; for(int i = 0; i < n; i++) { ret += i; } return ret;}
注意:C++中inline内联编译的限制:
总的来说,函数体不能过于复杂。
- 不能存在任何形式的循环语句
- 不能存在过多的条件判断语句
- 函数体不能过于庞大
- 不能对函数进行取址操作
- 函数内联声明必须在调用语句之前
内联函数和普通函数的区别:
- 普通函数:每次调用前,CPU都会保存现场(入栈),调用完后还要恢复现场(出栈)等额外开销。
- 内联函数:就会在每次调用的地方,将内联函数里的代码段“内联地”展开,所以省去了额外的开销
小结:
C++中可以通过inline声明内联函数
编译器直接将内联函数扩展到函数调用的地方
inline只是一种请求,编译器不一定允许这种请求
内联函数省去了函数调用时压栈,跳转和返回的开销
转载地址:https://blog.csdn.net/xiaodingqq/article/details/85014210 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!