作者 | 梁唐
大家好,我是梁唐。
这是EasyC 系列的第31篇,来聊聊内联函数。
内联函数
内联函数是C 当中为了提高程序运行效率的设计,老实讲我没有在其他语言当中看到类似的设计。它和常规函数之间的主要区别不在于编写的方式,而是在于C 编译器会将内联函数组合到程序当中执行。
要解释这个过程会稍稍有些复杂,我们需要从编译的过程说起。对于编译型语言而言,编译器做的事情是把人类写出来人能读懂的代码翻译成机器能够识别、执行的机器语言,一般是一串十六进制的指令。随后计算机逐步执行这些指令,完成我们想要的功能。
当我们调用函数时,其实本质上是指令跳转,先记录下当前运行的指令位置,跳转到函数所在的指令位置进行执行,执行完成之后再跳转回来。这个当中除了跳转之外,还会发生一些参数的传递和拷贝,需要一定的开销。
而使用内联函数,本质上可以理解成使用相应的函数代码代替了函数调用。可以简单理解成把函数当中的代码拷贝了一份粘贴到了函数调用的位置,代替了函数跳转。举个例子,比如说我们有一个函数来计算坐标到原点的距离:
代码语言:javascript复制include<cmath>
double distance(double x, double y) {
return sqrt(x * x y * y);
}
double x = 3.0, y = 4.0;
double d = distance(x, y);
当我们使用了内联函数之后,它相当于把函数的代码拷贝了一份粘贴到了调用的位置:
代码语言:javascript复制double x = 3.0, y = 4.0;
double d = sqrt(x * x y * y);
这也就是内联的含义,使用了内联函数之后,程序无须跳转到另外一个位置进行执行,可以节省掉跳转所带来的开销。因此运行效率要比普通函数更快,但代价是需要占用更多的内存。比如我们调用了10次内联函数,相当于代码拷贝了十份。
内联函数的使用非常简单,就是在函数定义之前加上inline
关键字。
需要注意的是,有的时候我们虽然加上了inline
关键字但编译器并不一定会遵照执行。有些编译器会有函数规模的限制,并且会限制内联函数禁止调用自己,也就是不能递归。
还有一点是内联函数虽然有内联机制,但是函数的传参依然是值传递,也就是说会发生拷贝,和普通函数一致。
在C语言当中没有inline
特性,C语言是使用宏定义来实现类似的功能。但宏定义并不是通过参数传递,而是代替机械替换实现的。
比如:
代码语言:javascript复制#define SQUARE(x) x*x
double a = SQUARE(3.4 3.5);
这样我们得到的结果会是3.4 3.5 * 3.4 3.5
,也就是说宏定义只是机械地替换代码,并不是函数式的调用。所以要实现类似inline
函数的效果,可以使用括号:
#define SQUARE(x) ((x) * (x))