第16章 C预处理器和C库 16.7 内联函数
2017-07-26 00:00
134 查看
通常函数调用需要一定的时间开销。这意味着执行调用时花费了时间用于建立调用、传递参数、跳转到函数代码段并返回。使用类函数宏的一个原因就是减少执行时间。C99还提供了另一种方法:内联函数(inline function)。
C99这样叙述:把函数变成内联函数将建议编译器尽可能快速地调用该函数。上述建议的效果由实现来定义。因此,使函数变为内联函数可能会简化函数的调用机制,但也可能不起作用。
创建内联函数的方法是在函数声明中使用函数说明符inline。通常,首次使用内联函数前在文件中对该函数进行定义。因此该定义也作为函数原型。也就是说代码应像下面这样:
编译器看到内联声明后会用eatline()函数体代替函数调用,其效果如果您在此处键入了函数体的代码。
因为内联函数没有预留给它的单独的代码块,所以无法获得内联函数的地址。(实际上可以获得地址,但这样会使编译器产生非内联函数)。另外,内联函数不会在调试器中显示。
内联函数应该比较短小。对于很长的函数,调用函数的时间少于执行函数主体的时间;此时,使用内联函数不会节省多少时间。
编译器在优化内联函数时,必须知道函数定义的内容。这意味着内联函数的定义和对该函数的调用必须在同一文件中。正因为这样,内联函数通常具有内部链接;因此,在多文件程序中,每个调用内联函数的文件都要对该函数进行定义。达到这个目标的最简单方法:在头文件中定义内联函数,并在使用该函数的文件中包含该头文件。一般不在头文件中放置可执行的代码,但内联函数是个例外。因为内联函数具有内部链接,所在在多个文件中定义同一内联函数不会产生什么问题。
C提供了几种方法用于在多文件程序中使用内联函数。通常,C只允许对函数进行惟一的一次定义,但是对内联函数却放松了这个原则。因此,最简单的方法是在使用内联函数的文件中都定义该函数。要达到这一目标的最简单方式为:在头文件中定义内联函数,并在使用该函数的源代码文件中包含该头文件。
与C++不同的是,C允许混合使用内联函数定义和外部函数定义(具有外部链接的函数定义)。例如,考虑下面的设置:
这里file1a.c使用file1a.c中定义的内联函数square( )。但是,file2a.c和file3a.c则使用file2a.c中的外部函数定义。
C甚至还允许在包含内联函数定义的文件中放置外部函数声明:
此时,在file1b.c对square()的调用中,编译器可随意使用该函数的内部定义或外部定义。甚至再次调用所使用的定义可以不致。C标准警告程序员,不要编写依赖于所选函数版本的代码。前面提到,任何带有内联函数定义的文件使用获取该函数地址的代码后(例如,传递函数外作为实际参数),编译器都会产生外部函数定义。
C99这样叙述:把函数变成内联函数将建议编译器尽可能快速地调用该函数。上述建议的效果由实现来定义。因此,使函数变为内联函数可能会简化函数的调用机制,但也可能不起作用。
创建内联函数的方法是在函数声明中使用函数说明符inline。通常,首次使用内联函数前在文件中对该函数进行定义。因此该定义也作为函数原型。也就是说代码应像下面这样:
#include <stdio.h> inline void eatline() //内联函数的定义/原型 { while(getchar()!='\n') continue; } int main() { ... eatline(); //函数调用 ... }
编译器看到内联声明后会用eatline()函数体代替函数调用,其效果如果您在此处键入了函数体的代码。
因为内联函数没有预留给它的单独的代码块,所以无法获得内联函数的地址。(实际上可以获得地址,但这样会使编译器产生非内联函数)。另外,内联函数不会在调试器中显示。
内联函数应该比较短小。对于很长的函数,调用函数的时间少于执行函数主体的时间;此时,使用内联函数不会节省多少时间。
编译器在优化内联函数时,必须知道函数定义的内容。这意味着内联函数的定义和对该函数的调用必须在同一文件中。正因为这样,内联函数通常具有内部链接;因此,在多文件程序中,每个调用内联函数的文件都要对该函数进行定义。达到这个目标的最简单方法:在头文件中定义内联函数,并在使用该函数的文件中包含该头文件。一般不在头文件中放置可执行的代码,但内联函数是个例外。因为内联函数具有内部链接,所在在多个文件中定义同一内联函数不会产生什么问题。
C提供了几种方法用于在多文件程序中使用内联函数。通常,C只允许对函数进行惟一的一次定义,但是对内联函数却放松了这个原则。因此,最简单的方法是在使用内联函数的文件中都定义该函数。要达到这一目标的最简单方式为:在头文件中定义内联函数,并在使用该函数的源代码文件中包含该头文件。
与C++不同的是,C允许混合使用内联函数定义和外部函数定义(具有外部链接的函数定义)。例如,考虑下面的设置:
//file1a.c ... inline double square(double); double square(double x){return x*x;} int main() { double q = square(1.3); ... //file2a.c ... extern double square (double); double square (double x){int y; y=x*x; return y;} void spam(double v) { double kv = square(v); ... //file3a.c ... extern double square(double); void masp(double w) { double kw = square(w); ...
这里file1a.c使用file1a.c中定义的内联函数square( )。但是,file2a.c和file3a.c则使用file2a.c中的外部函数定义。
C甚至还允许在包含内联函数定义的文件中放置外部函数声明:
//file1b.c --小心! ... extern double square(double); //把square()声明为外部函数 inline double square(double); //把square()声明为内联函数 double square(double x){ return x*x;} int main(void) { double q = square(1.3)+square(1.5); //哪一个square()? ... //file2b.c ... extern double square(double); double square(double x){int y; y=x*x; return y;} ...
此时,在file1b.c对square()的调用中,编译器可随意使用该函数的内部定义或外部定义。甚至再次调用所使用的定义可以不致。C标准警告程序员,不要编写依赖于所选函数版本的代码。前面提到,任何带有内联函数定义的文件使用获取该函数地址的代码后(例如,传递函数外作为实际参数),编译器都会产生外部函数定义。
相关文章推荐
- 第16章 C预处理器和C库 16.2 明显常量:#define
- 第16章 C预处理器和C库 编程练习
- 第16章 C预处理器和C库 16.8 C库
- 第16章 C预处理器和C库 16.4 宏,还是函数
- 第16章 C预处理器和C库 16.3 在#define中使用参数
- 第16章 C预处理器和C库 16.9 数学库
- 第16章 C预处理器和C库 16.5 文件包含: #include
- 第16章 C预处理器和C库 16.11 诊断库
- 第16章 C预处理器和C库 16.10 通用工具库
- c cprimer plus 第16章 c预处理器和c库
- 第16章 C预处理器和C库 16.12 string.h库中的memcpy()、memmove()
- 第16章 C预处理器和C库 16.1 翻译程序的第一步
- 第16章 C预处理器和C库 16.6 其他指令
- 第16章 C预处理器和C库 16.13 可变参数:stdarg.h
- c primer plus第16章总结:C预处理器和C库
- 《高质量程序设计指南——C/C++》第16章 内存管理
- C# 预处理器指令
- inline内联函数
- inline 内联函数
- 细嚼慢咽C++primer(3)——引用形参,内联函数,重载函数,指向函数的指针