
高贵的衬衫
07-30 15:29
C++
C++
# 一、内联函数
```mermaid
flowchart LR
id1[(<font color=#</font>内联函数)]
```
## 1.1.面试题
```mermaid
flowchart LR
id1[(<font color=#</font>面试题)]
```
>通过对C语言的学习,对于宏有了一定的了解,当定义一个宏常量是是非常方便的直接替换这在数据结构链表处有明显的体现,但是对于宏函数的写法就==比较容易出错有以下几种形式的错误需要提醒==:
```cpp
#define N 10//宏常量
//宏函数
#define ADD(int x , int y) {return x+y;}//宏的调用不需要return
#define ADD(x , y) (return x+y;)
#define ADD(x , y) return x+y;
#define ADD(x , y) x+y;//宏后面不需要分号
//加分号是可以的但对于有些语法是不通过的
int main()
{
ADD(1, 2);//这种是不会报错的
printf("%d\n", ADD(1, 2));//这种会报错因为宏替换后,会多出一个分号
return 0;
}
#define ADD(x , y) x+y//可能出现优先级错误
int main()
{
ADD(1, 2);
printf("%d\n", ADD(1, 2));
printf("%d\n", ADD(1, 2) * 3);//这里替换后变成了1+2*3=7显然不是想要得到的9
return 0;
}
#define ADD(x , y) (x+y)//可能出现优先级错误
int main()
{
ADD(1, 2);
printf("%d\n", ADD(1, 2));
printf("%d\n", ADD(1, 2) * 3);
int a = 1, b = 2;
ADD(a | b, a & b);//替换后变成(a|b+a&b) +号的优先级高于| &所以会先算+
return 0;
}
#define ADD(x , y) ((x)+(y)) 这是正确的
```
```mermaid
flowchart LR
id1><font color=#FFF0</font>1. 宏的优缺点]
```
>**宏的优缺点?**
**优点:**
1.增强代码的复用性。
2.提高性能。
**缺点:**
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用,语法很坑。
3.没有类型安全的检查 。
**宏函数的优点:**
> 1.没有类型的严格限制
> 2.针对频繁调用小函数,不需要再建立栈帧,提高了效率
```cpp
int Add(int left, int right)
//这种函数调用是需要建立栈帧的但是宏函数不需要直接替换了
{
return left + right;
}
```
```mermaid
flowchart LR
id1><font color=#FFF0</font>2. C++有哪些技术替代宏]
```
> **C++有哪些技术替代宏?**
> 1. 常量定义 换用const enum
> 2. 短小函数定义 换用==内联函数==
## 1.2.内联函数概念
```mermaid
flowchart LR
id1[(<font color=#</font>内联函数的概念)]
```
==以inline修饰的函数叫做内联函数==,编译时C++编译器会在调用内联函数的地方==展开==,==没有函数调用建立栈帧的开销==,==内联函数提升程序运行的效率==。
>
如果在上述==函数前增加inline关键字将其改成内联函数==,在编译期间==编译器会用函数体替换函数的调用==。
```mermaid
flowchart LR
id1><font color=#FFF0</font>查看方式:]
```
1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add
2. 在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行优化,以下给出vs2013的设置方式)
>


```mermaid
flowchart LR
id1><font color=#FFF0</font>代码示例:]
```
```cpp
inline int add(int x, int y)
{
return x + y;
}
int main()
{
int a = 1, b = 2;
int ret = add(1, 2);
//int ret = add(a | b , a & b);
//这样写也不会像宏函数一样出错了
printf("%d\n", ret);
return 0;
}
```
## 1.3.内联函数特性
```mermaid
flowchart LR
id1[(<font color=#</font>内联函数的特性)]
```
```mermaid
flowchart LR
id1><font color=#FFF0</font>特性1:]
```
>inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大(代码膨胀),优势:少了调用开销,提高程序运行效率。(不能任何情况下都用内联)
```mermaid
flowchart LR
id1><font color=#FFF0</font>特性2:]
```
>inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。下图为《C++prime》第五版关于inline的建议:
```mermaid
flowchart TD
id1[\<font color=#FFD700</font>内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求\]
```
**一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。很多编译器都不支持内联递归函数,而且一个75行的函数也不大可能在调用点内联地展开。**
```mermaid
flowchart LR
id1><font color=##FF149</font>1. 太长就不会展开:]
```
```cpp
inline int add(int x, int y)
{
return x + y;
}
inline int func()
{
int x1= 0;
int x2 = 0;
int x3 = 0;
int x4 = 0;
int ret = 0;
ret += x1;
ret *= x2;
ret /= x3;
ret /= x3;
ret /= x3;
ret += x1;
ret += x1;
return ret;
}
int main()
{
int a = 1, b = 2;
//int ret = add(1, 2);
int ret = add(a | b , a & b);
printf("%d\n", ret);
ret = func();
return 0;
}
```
>
```mermaid
flowchart LR
id1><font color=##FF149</font>2. 缩短就可能会展开]
```
```cpp
inline int add(int x, int y)
{
return x + y;
}
inline int func()
{
int x1= 0;
int x2 = 0;
int x3 = 0;
int x4 = 0;
int ret = 0;
ret += x1;
return ret;
}
int main()
{
int a = 1, b = 2;
//int ret = add(1, 2);
int ret = add(a | b , a & b);//这样写也不会像宏函数一样出错了
printf("%d\n", ret);
ret = func();
return 0;
}
```
>
```mermaid
flowchart LR
id1><font color=#FFF0</font>特性3:]
```
>==inline不建议声明和定义分离==,分离会导致==链接错误==。因为==inline被展开==,==就没有函数地址了,链接就会找不到==
```mermaid
flowchart LR
id1><font color=#FFF0</font>1. 代码示例:]
```
Comments0
Creator