C语言里面的内联函数(inline)与宏定义(#define)探讨
先简明扼要,说下关键:
1、内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。
2、内联函数可以调试,而宏定义是不可以调试的。
内联函数与宏本质上是两个不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline。下面详细介绍一下探讨一下内联函数与宏定义。
一、内联函数是什么?
内联函数是代码被插入到调用者代码处的函数。如同 #define 宏(但并不等同,原因见下文),内联函数通过避免被调用的开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。
二、 内联函数是如何在安全和速度上取得折衷?
在 C 中,你可以通过在结构中设置一个 void* 来得到“封装的结构”,在这种情况下,指向实际数据的 void* 指针对于结构的用户来说是未知的。因此结构的用户不知道如何解释void*指针所指内容,但是存取函数可以将 void* 转换成适当的隐含类型。这样给出了封装的一种形式。
不幸的是这样做丧失了类型安全,并且也将繁琐的对结构中的每个域的访问强加于函数调用。(如果你允许直接存取结构的域,那么对任何能直接存取的人来说,了解如何解释 void* 指针所指内容就是必要的了;这样将使改变底层数据结构变的困难)。
虽然函数调用开销是很小的,但它会被累积。C++类允许函数调用以内联展开。这样让你在得到封装的安全性时,同时得到直接存取的速度。此外,内联函数的参数类型由编译器检查,这是对 C 的 #define 宏的一个改进。
三、为什么我应该用内联函数?而不是原来清晰的 #define 宏?
因为#define宏定义函数是在四处是有害的:
和 #define 宏不同的是,内联函数总是对参数只精确地进行一次求值,从而避免了那声名狼藉的宏错误。换句话说,调用内联函数和调用正规函数是等价的,差别仅仅是更快:
// 返回 i 的绝对值的宏
#define unsafe(i) \
( (i) >= 0 ? (i) : -(i) )
// 返回 i 的绝对值的内联函数
inline
int safe(int i)
{
return i >= 0 ? i : -i;
}
int f();
void userCode(int x)
{
int ans;
ans = unsafe(x++); // 错误!x 被增加两次
ans = unsafe(f()); // 危险!f()被调用两次
ans = safe(x++); // 正确! x 被增加一次
ans = safe(f()); // 正确! f() 被调用一次
}
和宏不同的,还有内联函数的参数类型被检查,并且被正确地进行必要的转换。
宏定义复杂函数是有害的;非万不得已不要用。
四、如何告诉编译器使非成员函数成为内联函数?
声明内联函数看上去和普通函数非常相似:
void f(int i, char c);
当你定义一个内联函数时,在函数定义前加上 inline 关键字,并且将定义放入头文件:
inline
void f(int i, char c)
{
// ...
}
注意:将函数的定义({...}之间的部分)放在头文件中是强制的,除非该函数仅仅被单个 .cpp 文件使用。尤其是,如果你将内联函数的定义放在 .cpp 文件中并且在其他 .cpp文件中调用它,连接器将给出 “unresolved external” 错误。
五、如何告诉编译器使一个成员函数成为内联函数?
声明内联成员函数看上去和普通函数非常类似:
class Fred {
public:
void f(int i, char c);
};
但是当你定义内联成员函数时,在成员函数定义前加上 inline 关键字,并且将定义放入头文件中:
inline
void Fred::f(int i, char c)
{
// ...
}
通常将函数的定义({...}之间的部分)放在头文件中是强制的。如果你将内联函数的定义放在 .cpp 文件中并且在其他 .cpp 文件中调用它,连接器将给出“unresolved external”错误。
六、 有其它方法告诉编译器使成员函数成为内联吗?
有:在类体内定义成员函数:
class Fred {
public:
void f(int i, char c)
{
// ...
}
};
尽管这对于写类的人来说很容易,但由于它将类是“什么”(what)和类“如何”(how)工作混在一起.
小结
总之,在嵌入式C(或C++)编程里面,懂得使用内联函数(inline)与宏定义(#define),并使用好它们,对我们是大有裨益的。(注:本文部分内容来源于网络整理,上述探讨属于个人意见,仅供参考。错误之处也是难免!)
胡恩伟
于重庆大学A区一舍
2011年2月19日
专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们
相关推荐
TDA2320 (电视机)红外线遥控接收前置放大电路
SkyEye硬件模拟平台
为何不马上使用MEMS麦克风呢?
ADI在线研讨会:差分驱动ADC的最新发展:第一部分
在您的下一个设计中使用实验室电路
ADI在线研讨会:您不知道的关于DAC的五件事
中国芯海科技上调MCU与NOR Flash价格15%–50%
刚刚,特斯拉交出“极寒”财报:利润暴跌61%,营收创纪录首次负增长!
YN5201 (电风扇)红外线遥控译码电路
SMT工作流程
TDA3048 (电视机)红外线遥控接收电路
2002年研华嵌入式论坛演讲稿大全,需要请排队!!
Molex莫仕发布了在人工智能对主要行业的深远影响推动下2026年连接和电子设计领域的十大预测
SPWM逆变电源直流偏磁的DSP控制研究
“热力学计算”能将人工智能图像生成的能源消耗削减一百亿倍
Robotiq推出适用于2F自适应夹爪的触觉传感指尖
X-fest 2012 ADI公司技术展示预览
难题!!
YN 5203 (防盗系统)无线电或红外线遥控译码电路
Lisatek推出嵌入式处理器设计工具(摘自www.embed.com.cn)
是德科技针对电子出行中兆瓦充电测试的挑战
Tageos-Wiliot合作目标是实现可扩展环境物联网
中国沐曦发布GPU路线图,目标在2027年超越Rubin架构
三星拟将iPhone用LPDDR价格环比上调超80%
SPWM铃流信号发生器的设计
推荐几个好的下载电子书的****^-^(摘自bbs.sjtu.edu.cn)
samsung S3C4510B之DMA实战篇
TDK铁氧体磁芯(电源供应器适用)
TDA3047 (电视机)红外线遥控接收电路
IonQ将收购SkyWater Technology