赞
踩
通常,函数调用都有一定的开销,因为函数的调用过程包括建立调用、 传递参数、跳转到函数代码并返回。使用宏使代码内联,可以避免这样的开 销。C99还提供另一种方法:内联函数(inline function)。
可能顾名思义地认为内联函数会用内联代码替换函数调用。
其实C99和C11标准中叙述 的是:“把函数变成内联函数建议尽可能快地调用该函数,其具体效果由实 现定义”。因此,把函数变成内联函数,编译器可能会用内联代码替换函数 调用,并(或)执行一些其他的优化,但是也可能不起作用。
创建内联函数的定义有多种方法。标准规定具有内部链接的函数可以成为内联函数,还规定了内联函数的定义与调用该函数的代码必须在同一个文件中。
因此,最简单的方法是使用函数说明符 inline 和存储类别说明符 static。通常,内联函数应定义在首次使用它的文件中,所以内联函数也相当于函数原型。如下所示:
#include <stdio.h>
inline static void eatline() // 内联函数定义/原型
{
while (getchar() != '\n')
continue;
}
int main()
{
...
eatline(); // 函数调用
...
}
编译器查看内联函数的定义(也是原型),可能会用函数体中的代码替换 eatline()函数调用。也就是说,效果相当于在函数调用的位置输入函数体 中的代码:
#include <stdio.h>
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个文件:
//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); ...
如上述代码所示,3个文件中都定义了square()函数。file1.c文件中是 inline static定义;file2.c 文件中是普通的函数定义(因此具有外部链接); file3.c 文件中是 inline 定义,省略了static。
3个文件中的函数都调用了square()函数,这会发生什么情况?。file1.c 文件中的main()使用square()的局部static定义。由于该定义也是inline定义, 所以编译器有可能优化代码,也许会内联该函数。file2.c 文件中,spam()函 数使用该文件中 square()函数的定义,该定义具有外部链接,其他文件也可 见。file3.c文件中,编译器既可以使用该文件中square()函数的内联定义,也 可以使用file2.c文件中的外部链接定义。如果像file3.c那样,省略file1.c文件 inline定义中的static,那么该inline定义被视为可替换的外部定义。
注意GCC在C99之前就使用一些不同的规则实现了内联函数,所以GCC 可以根据当前编译器的标记来解释inline。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。