内联函数inline
- 概念:
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 从而能够提升程序运行的效率。
- 特性:
- inline是一种以空间换时间的做法,省去调用函数的开销。所以代码很长或者有循环/递归的函数不适宜作为内联函数。
- inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等 ,编译器优化时会忽略掉内联。
- inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
- 内联函数不能是虚函数。(原因:inline是通过编译器将函数内容替换到函数调用处,是静态编译的。而虚函数是动态调用的,在编译器并不知道需要调用的是父类还是子类的虚函数,所以不能够inline声明展开,因此编译器会忽略)
- 使用:
- 在C++中,在类的内部定义了函数体的成员函数默认是内联函数,不管是否有inline关键字。
- 在内联函数内不允许用循环语句、开关语句和递归调用等,且函数体不宜过长,否则作为普通函数处理。
- 内联函数的定义必须出现在第一次被调用之前。如果在前面声明为普通函数,而在调用代码后面才定义为一个inline函数,程序可以通过编译,但该函数没有实现inline。
- 如果一个inline函数会在多个源文件中被用到,那么必须把它定义在头文件中。解析:如果内联函数fun()定义在某个编译单元A中,那么其他编译单元中调用fun()的地方时,可以编译通过(此时并没有展开,结合第三条,此时虽然头文件声明了该inline函数,但此时调用时,还没定义,所以作为普通函数处理)。当链接时将无法解析该符号,出现链接错误。 因为inline函数是作为内部连接存在的,只能够被本模块访问。
- 特点:
inline函数是函数,有类型,要做类型检查,因此安全可靠,可以得到一定效率的提升,这个是以增加空间的消耗为代价。
宏替换#define
- 概念:
定义预编译时处理的宏,只是简单的字符串替换,无类型检查。
- 特性:
- 在宏扩展时,只对宏名做简单的代换,不做任何计算,也不做任何语法检查。
- 宏由编译预处理程序处理。
- 宏定义可出现在程序的任何位置。
- 在宏定义中可以使用已定义的宏名。
- 使用:
- 不带参数的宏定义格式:#define 标识符 字符或字符串
- 带参数的宏定义格式: #define 宏名(参数表) 使用参数的字符或字符串
- 特点:
define无类型,不做检查就直接替换,因此并不安全,会带有副作用;宏不能调试,会使得代码变得庞大。
区别
- 内联函数在编译时展开,宏在预编译时由预处理器进行展开。
- 内联函数会检查参数类型,宏定义不检查函数参数 ,所以内联函数更安全。
- inline函数是函数,宏不是函数。
- 宏在定义时要小心处理宏参数(一般情况是把参数用括弧括起来),否则易出现二义性,而内联定义不会出现。
- 编译内联函数可以嵌入到目标代码,宏只是简单文本替换。
基于上述区别中的第2点,为了保证安全性在C++中尽量使用inline代替宏。