Hello~,欢迎大家来到我的博客进行学习!
目录
- inline
- 为什么不能加分号?
- 为什么要加外面的括号?
- 为什么要加里面的括号?
inline
- 用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率。
- inline对于编译器而言只是⼀个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。
- C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调试,C++设计了inline目的就是替代C的宏函数。
- vs编译器 debug版本下面默认是不展开inline的,这样方便调试,debug版本想展开需要设置⼀下以下两个地方。
- inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。
C++弄内联函数是为了替代宏,我们在写宏的时候非常容易写错,所以C++中不太推荐宏这个东西。例如:
// 实现⼀个ADD宏函数的常⻅问题
//#define ADD(int a, int b) return a + b;
//#define ADD(a, b) a + b;
//#define ADD(a, b) (a + b)// 正确的宏实现
#define ADD(a, b) ((a) + (b))
这里有3个问题:
- 为什么不能加分号?
- 为什么要加外面的括号?
- 为什么要加里面的括号?
为什么不能加分号?
首先在这个情况下,是可以加分号的:
#include<iostream>
using namespace std;
#define ADD(a,b)((a)+(b));int main()
{int ret = ADD(1, 2);return 0;
}
但是这个场景中,就不可以:
#include<iostream>
using namespace std;
#define ADD(a,b)((a)+(b));int main()
{int ret = ADD(1, 2);cout << ADD(1, 2) << endl;return 0;
}
这里我们加了分号以后,宏替换以后就会有两个分号,就会被识别为两个语句,一个分号代表一个语句,被替换后的形式为这样:
#include<iostream>
using namespace std;
#define ADD(a,b)((a)+(b));int main()
{int ret = ADD(1, 2);//int ret =((1)+(2));cout <<((1)+(2)); << endl;return 0;
}
所以不能加分号。
为什么要加外面的括号?
#include<iostream>
using namespace std;
#define ADD(a,b)(a)+(b)int main()
{int ret = ADD(1, 2);cout << ADD(1, 2) * 5 << endl;return 0;
}
这里就是运算符优先级的问题,如果不加就是11。
为什么要加里面的括号?
#include<iostream>
using namespace std;
#define ADD(a,b)(a+b)
int main()
{int ret = ADD(1, 2);int x = 1, y = 2;ADD(x & y, x | y); // -> (x&y+x|y)return 0;
}
这里也是运算符优先级的问题,这里是一种替换,传给a的不一定是变量表达式,也可能是运算表达式。这里我们本来希望&和|先运算,但是+的优先级高。
在这里我们体会到了,宏会出现各种问题所以C++推荐内联。宏的好处是快一些,因为它的本质是替换,假设我们写一个add函数,要调用是要建立栈帧的。用内联函数就不需要建立栈帧了,可以提高效率,使用内联可以避开宏的坑。
#include<iostream>
using namespace std;
inline int ADD(int x, int y)
{int ret = x + y;return ret;
}int main()
{int ret = ADD(1, 2);cout << ADD(1, 2) << endl;cout << ADD(1, 2) * 5 << endl;int x = 1, y = 2;ADD(x & y, x | y); // -> (x&y+x|y)return 0;
}
inline对于编译器而言只是⼀个建议,我们并不会用内联去写递归或一些比较长的代码,我们只会用它去写一些比较短的代码。函数被编译完之后,会变为一串指令,这里肯定会有很多很多的指令,这里和数组类似,是第一句指令的地址。
inline不建议声明和定义分离到两个文件,分离会导致链接错误。链接错误就是找不到定义就会出现。
F.h
#include <iostream>
using namespace std;
inline void f(int i);
F.cpp
#include "F.h"
void f(int i)
{cout << i << endl;
}
main.cpp
#include "F.h"
int main()
{// 链接错误:⽆法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z)f(1);return 0;
}
普通函数是不可以放到.h里面的,也会报链接错误。这里报错不是报错找不到,而是冲突。
F.h
#include <iostream>
using namespace std;
inline void f(int i);void Func()
{cout << "Func()" << endl;
}
加一个静态就可以解决:
#include <iostream>
using namespace std;
inline void f(int i);static void Func()
{cout << "Func()" << endl;
}
好了,我们的知识就讲到这里。如果文章内容有误,请大佬在评论区斧正!谢谢大家!