【C/C++】inline和#define的区别

区别

内联函数与宏具有如下区别:

  1. 宏容易出错,预处理器在拷贝宏代码时会产生意想不到的编译效应。例如:
  2. 宏不可调试,但是内联函数可以调试。虽然内联函数与宏相似,都会进行代码展开,但是在程序的Debug版本里,内联函数并未实现真正的内联,编译器会像普通函数那样为内联函数生成含有调试信息的可执行代码,而在Release版本里才会真正的内联。
  3. 宏无法操作类的私有数据成员
  4. 宏在预编译阶段展开,内联函数在编译阶段展开,且在展开前会进行类型安全检查或者自动类型转换。

使用内联函数的好处?

如下是一个C++中我们用来求两个整数的最大值的函数max。

int max(int a, int b)
{
    return a > b ? a : b;
}

将一个问题的求解方法定义为函数具有提高可阅读性、可修改性、可复用性等多种优点,但是同时也有一个缺点:调用函数比求解表达式要慢。调用函数通常需要先保存寄存器,然后在返回时恢复。

内联函数的目的就是提高函数的执行效率。

假设我们将max函数定义为内联函数:

// 此处注意:inline关键字需要加在函数定义前而非声明前
inline int max(int a, int b)
{
    return a > b ? a : b;
}

cout << max(a, b) << endl;语句,在编译时会被展开为cout << (a > b ? a : b) << endl;从而消除了执行max函数的额外开销。

宏的优点

通过以上我们可以发现,C++的内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员,所以在C++程序中应该尽量使用内联函数来取代宏。而断言assert是个例外。

assert是仅在Debug版本中起作用的宏,它用于检查“不应该”发生的情况。为了保证Debug版本和Release版本不会因为assert宏产生差别,assert不应该产生任何副作用。如果assert是函数,而函数调用会引起内存、代码的变动,那么会导致Debug版本和Release版本存在差异,这并非我们所期望的。所以assert不是内联函数,而是宏。

慎用内联

“如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。”
————《高质量程序设计指南——C++/C语言》 林锐

参考文献:
[1]《高质量程序设计指南——C++/C语言》 林锐
[2] https://www.cnblogs.com/2018shawn/p/10851779.html 余生以学

posted @   ZRK1ng  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示