一、内联函数
内联函数是C++的增强特性之一,它是为了提高程序运行的速度而做的改进。当编译器发现某段代码在调用一个内联函数的时候,首先是不会直接去调用这个函数,而是将该函数的整段代码插入到当前的位置。
在了解内联函数原理的前提下,我们需要先了解常规函数调用的过程。在程序中编译过程的最终产物是可执行程序,在程序运行时,操作系统将指令载入到计算机的内存中。每条指令都有特定的内存位置,计算机根据这些指令逐步依次执行,当计算机程序执行到常规函数调用的指令时,程序会在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈中,跳转到函数内存地址并执行函数代码,当执行结束后跳回原来保存的地址处。这样来回跳转并进行参数复制会降低程序运行的速度。
所以C++推出了内联函数,内联函数是将编译代码与其他代码“内联”起来,编译器在使用函数代码直接代替函数的调用(这种替换行为发生的编译阶段而非程序运行阶段),对于内联函数,程序不需要跳转执行代码,没有函数压栈的开销,因此程序运行速度会稍快,但是会占用更多的内存空间。
1.1 内联函数的使用原则
1. 定义内联函数时,使用inline关键字在函数的最前面声明函数,称为内联声明函数。
2. 内联函数首先是函数,函数的很多性质都适用于内联函数,如内联函数可以重载。
3. 内联函数体中,不能有循环语句、if语句或switch语句,否则,函数定义时即使有inline关键字进行声明,编译器也会把该函数作为非内联函数进行处理。
4. 内联函数的定义性声明应该出现函数调用之前。
#include <stdio.h>
// 声明一个使用 inline 关键字修饰的函数
inline int sub(int a, int b);
int main() {
int result = sub(3, 4);
printf("Result: %d\n", result);
return 0;
}
// 定义使用 inline 关键字修饰的函数
inline int sub(int a, int b) {
return a - b;
}
1.2 内联函数的优缺点
缺点:
1. 由于代码的扩展,内联函数增大了可执行程序的体积。
2. C++内联函数的展开是在编译阶段,意味着如果内联函数发生改动,就需要重新编译代码。
3. 内联函数不受嵌入式系统的青睐,由于嵌入式系统的存储约束可能不允许体积很大的可执行程序。
优点:
1. 提高了程序的运行速度。
2. 函数调用时,节省了变量压栈,弹栈的开销。
3. 避免一个函数执行完返回原来位置的开销。
二、宏
#define是C语言中提供的宏定义命令,目的是为程序员在编写程序时提供方便。
2.1 #define概念
#define是C语言中的一个宏定义命令,用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。
该命令存在两种格式:简单的宏定义和带参数的宏定义。
(1)简单的宏定义
#define <宏名> <字符串>
例: #define PI 3.1415926
(2)带参数的宏定义
#define <宏名> (<参数表>) <宏体>
例: #define A(x) x
2.2 宏替换发生的时机
当我们在一个集成的开发环境如Turbo C中将编写好的源程序进行编译时,实际经过了预处理、编译、汇编和连接几个过程。其中预处理器产生编译器的输出,主要实现以下的功能:
(1)文件包含
可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。
(2)条件编译
预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。
(3)宏展开
预处理器将源程序文件中出现的对宏的引用展开成相应的宏定义,即本文所说的#define的功能,由预处理器来完成。
经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。
三、内联函数和宏的区别
1. inline在编译阶段进行参数类型检查和安全检查。宏处理在预编译期间,不进行参数类型检查和安全检查。
2. inline是一种安全的宏。
3. 内联函数直接被潜入到目标代码中去。宏只是简单的文本替换。
4. 宏定义不是真正的函数,没有参数类型检查,不安全。