文档章节

第16章 C预处理器和C库 16.7 内联函数

idreamo
 idreamo
发布于 2017/07/26 06:49
字数 1110
阅读 7
收藏 0

通常函数调用需要一定的时间开销。这意味着执行调用时花费了时间用于建立调用、传递参数、跳转到函数代码段并返回。使用类函数宏的一个原因就是减少执行时间。C99还提供了另一种方法:内联函数(inline function)。

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标准警告程序员,不要编写依赖于所选函数版本的代码。前面提到,任何带有内联函数定义的文件使用获取该函数地址的代码后(例如,传递函数外作为实际参数),编译器都会产生外部函数定义。

© 著作权归作者所有

idreamo
粉丝 18
博文 139
码字总数 224743
作品 0
青岛
产品经理
私信 提问
C Primer Plus 第11章 11.7 ctype.h字符函数和字符串

第7章“C控制语句 分支和跳转”介绍了ctype.h系列字符相关的函数。这些函数不能被 应用于整个字符串,但是可以被应用于字符串中的个别字符。程序清单11.26定义了一个函数,它把toupper( )函数...

idreamo
2016/08/27
29
0
C Primer Plus 第12章 12.3 存储类和函数

函数也具有存储类。函数可以是外部的(默认情况下)或者静态的(C99增加了第三种可能性,即在第16章“C预处理器和C库"中将讨论的内联函数)。外部函数可以被其他文件中的函数调用,而静态函数...

idreamo
2016/11/19
15
0
[编程语言]C陷阱与缺陷

内容摘要 作者以自己1985年在Bell实验室时发表的一篇论文为基础,结合自己的工作经验扩展成为这本对C程序员具有珍贵价值的经典著作。写作本书的出发点不是要批判C语言,而是要帮助C程序员绕过...

21gprs
2014/05/23
0
0
c语言编译预处理和条件编译执行过程的理解

  在C语言的程序中可包括各种以符号#开头的编译指令,这些指令称为预处理命令。预处理命令属于C语言编译器,而不是C语言的组成部分。通过预处理命令可扩展C语言程序设计的环境。 一.预处理...

文艺小青年
2017/10/12
0
0
#define 中的“ # 运算符”和“ ## 运算符”

利用宏参数创建字符串:# 运算符 在类函数宏(function-like macro)的替换部分中,“#”符号用作一个预处理运算符,它可以把语言符号(token)转化为字符串。例如,如果 x 是一个宏参量,那...

TMDJoJo
2012/07/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mongodb安装、连接,mongodb用户管理、创建集合、数据管理、备份恢复,副本集介绍、搭建、测试,分片介绍、搭建、测试,php的mongodb扩展、mongo扩展

21.26 mongodb介绍 21.27 mongodb安装 21.28 连接mongodb 21.29 mongodb用户管理 21.30 mongodb创建集合、数据管理 21.31 php的mongodb扩展 21.32 php的mongo扩展 21.33 mongodb副本集介绍 ...

tobej
39分钟前
2
0
C++的变量初始化

C++中变量的初始化有很多种方式,如:默认初始化,值初始化,直接初始化,拷贝初始化,列表初始化。 1、默认初始化:默认初始化是指定义变量时没有指定初值时进行的初始化操作。 如:int a;...

天王盖地虎626
今天
2
0
MySQL-入门(一)

一、SQL的分类 DDL(Data Definition Language):数据定义语言,用来操作数据库对象:库、表、列等; DML(Data Manipulation Language):数据操作语言,用来增删改数据库中的数据; DCL(...

潜行-L
今天
2
0
微服务架构在Kubernetes上的实现

我们讨论了最近的微服务趋势,以及伴随微服务架构可能出现的一些复杂问题。在接下来的几周内,我们将深入探讨这个问题。我们将探讨不同设计选择中固有的权衡,以及可以采取哪些措施来缓解这些...

别打我会飞
今天
8
0
IDEA2018导入eclipse web项目

看别人的攻略:https://blog.csdn.net/qq_33229669/article/details/83751316 完成之后,出现了IDEA编译java报错:找不到符号_的解决方法错误, 然后百度出来是编码问题, 1.更改editor的文件编码...

流光韶逝
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部