C的内联函数(C99)

文章目录

  • 内联函数(C99)
  • 参考

内联函数(C99)

通常,函数调用都有一定的开销,因为函数的调用过程包括建立调用、
传递参数、跳转到函数代码并返回。使用宏使代码内联,可以避免这样的开销。

C99还提供另一种方法:内联函数(inline function)。读者可能顾名思义地认为内联函数会用内联代码替换函数调用。其实C99和C11标准中叙述的是:“把函数变成内联函数建议尽可能快地调用该函数,其具体效果由实现定义”。

因此,把函数变成内联函数,编译器可能会用内联代码替换函数调用,并(或)执行一些其他的优化,但是也可能不起作用。
创建内联函数的定义有多种方法。标准规定具有内部链接的函数可以成
为内联函数,还规定了内联函数的定义与调用该函数的代码必须在同一个文件中。因此,最简单的方法是使用函数说明符 inline 和存储类别说明符static。通常,内联函数应定义在首次使用它的文件中,所以内联函数也相当于函数原型。如下所示:

#include 
inline static void eatline() // 内联函数定义/原型
{
while (getchar() != '\n')
continue;
}
int main()
{
...
eatline(); // 函数调用
...
}

编译器查看内联函数的定义(也是原型),可能会用函数体中的代码替
换 eatline()函数调用。也就是说,效果相当于在函数调用的位置输入函数体中的代码:

#include 
inline static void eatline() //内联函数定义/原型
{
	while (getchar() != '\n')
	continue;
}
int main()
{
	...
	while (getchar() != '\n') //替换函数调用
	continue;
	...
}

由于并未给内联函数预留单独的代码块,所以无法获得内联函数的地址
(实际上可以获得地址,不过这样做之后,编译器会生成一个非内联函
数)。另外,内联函数无法在调试器中显示。
内联函数应该比较短小。把较长的函数变成内联并未节约多少时间,因
为执行函数体的时间比调用函数的时间长得多。
编译器优化内联函数必须知道该函数定义的内容。这意味着内联函数定
义与函数调用必须在同一个文件中。鉴于此,一般情况下内联函数都具有内部链接。因此,如果程序有多个文件都要使用某个内联函数,那么这些文件
中都必须包含该内联函数的定义。最简单的做法是,把内联函数定义放入头
文件,并在使用该内联函数的文件中包含该头文件即可。

// eatline.h
#ifndef EATLINE_H_
#define EATLINE_H_
inline static void eatline(){
	while (getchar() != '\n')
		continue;
}
#endif

一般都不在头文件中放置可执行代码,内联函数是个特例。因为内联函
数具有内部链接,所以在多个文件中定义同一个内联函数不会产生什么问题。

与C++不同的是,C还允许混合使用内联函数定义和外部函数定义(具
有外部链接的函数定义)。例如,一个程序中使用下面3个文件:

如下代码所示,3个文件中都定义了square()函数。
3个文件中的函数都调用了square()函数,这会发生什么情况?

//file1.c
...
inline static double square(double);
double square(double x) { return x * x; }
int main(){
	double q = square(1.3);
	...	
//file2.c
...
double square(double x) { return (int) (x*x); }
void spam(double v){
	double kv = square(v);
	
...
//file3.c
...
inline double square(double x) { return (int) (x * x + 0.5); }
void masp(double w){
	double kw = square(w);
	...
}

file1.c文件中是inline static定义;
file1.c文件中的main()使用square()的局部static定义。由于该定义也是inline定义,所以编译器有可能优化代码,也许会内联该函数。

file2.c 文件中是普通的函数定义(因此具有外部链接);
file2.c 文件中,spam()函数使用该文件中 square()函数的定义,该定义具有外部链接,其他文件也可见。

file3.c 文件中是 inline 定义,省略了static。
file3.c文件中,编译器既可以使用该文件中square()函数的内联定义,也可以使用file2.c文件中的外部链接定义。如果像file3.c那样,省略file1.c文件inline定义中的static,那么该inline定义被视为可替换的外部定义。注意GCC在C99之前就使用一些不同的规则实现了内联函数,所以GCC可以根据当前编译器的标记来解释inline。

参考

《C Primer Plus》

你可能感兴趣的:(C/C++,c语言,开发语言)