大厂面试重要C++知识(二)—— 内联函数和宏的区别与联系

内联函数和宏做为C和C++的基础,具有提高执行效率的功能。那么既然存在了宏,为什么还要内联函数?他们有什么区别和联系呢?以下展开。

一、内联函数

内联函数定义

  • 内联函数是C++为降低小型程序调用开销而采取的一种机制。
  • 函数在调用时,需要在栈中为形参和局部变量开辟空间,将实参的值赋值给形参;还有函数执行前的现场状态和返回地址都要压入栈中,以便函数返回后继续执行,这个过程带来时间和空间的开销。同理,在退出函数时也要时间的开销。
  • 因此,使用内联函数机制定义一些简单、代码短、常用到的函数。
  • 内联函数和普通函数的区别:编译器处理内联函数语句时,不会将语句编译成函数调用的指令,而是直接将整个函数体的代码嵌入调用语句处,就像整个函数体在调用处重写了一遍。
  • 个人理解,有点像编写代码时不写函数而直接书写相应的代码,只不过写内联函数是编译器替你做了这些事情(写重复的代码),而自己只需要封装好函数加上内联标志,编译器帮你完成重复代码的书写并翻译。

代码实现

在代码实现很简单,在定义函数时,在返回值类型上写inline关键字即可。

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

优缺点

优点:即可以方便我们像调用函数一样解决重复代码的问题,又不用付出函数调用时压栈、出栈的时间开销。

缺点:使用内联函数,以空间换时间,增加了编译后的代码体积。如果函数里代码量大、出现了循环、递归等,执行函数的花销远大于调用函数的开销,那么就没有必要使用内联函数,甚至使得可执行程序变得很大,浪费大量的空间。

关键

  • 调用内联函数的语句前必须已经出现内联函数的定义(即完整的函数代码),而不能只出现内联函数的声明。

  • 在函数前头加上inline声明为内联函数,但是编译器会根据函数的大小、是否有循环等判断是否满足内联条件,不满足则不是内联函数。

  • 内联一般在中使用,如get()、set()方法。

  • 内联的定义最好放在头文件,即整个函数体放在头文件里。这其实是个工程的问题,因为C++工程中的类的定义一般写在头文件中,具体实现代码在源文件中。一般来说,头文件中不允许出现函数的定义,但是由于内联函数必须在调用它的每个文本文件中被定义,所以没有在类体中定义的内联成员函数必须被放在类定义出现的头文件中。

    //这是test.h
    #pragma once
    class test
    {
    public:
    	int getValue();
    private:
    	int value;
    };
    inline int test::getValue()
    {
    	return value;
    }
    
    

二、内联函数和宏(macro)的区别

首先看看宏的定义:

  宏,也就是宏定义,是C语言三种预处理功能之一。例如:#define N 100,在预处理工作过程中,代码中出现的所有N(宏名),都会被100(替换文本)替代,并且是原地展开

  宏函数,也就是带参数的宏定义,和函数类似又不同。宏函数在预处理期间处理,而函数则在编译时处理;宏函数在上面提到是原地展开,直接将代码替换,并不需要像函数调用时的各种开销,速度更快。

不过宏函数有个缺点,宏是原地替换的,所以可能遇到运算符优先级的不同而带来错误。最好每个变量都加上括号。

比如下面这个错误案例:

#include <iostream>
using namespace std;

#define DOUBLE(x) 2 * x

int main()
{
    cout << DOUBLE(2) << endl;
    cout << DOUBLE(1 + 1) << endl;
}

  上面的代码,如果按照普通函数的思路,那么2 和 1 + 1其实是一致的,所以两者结果应该都是4,但是运行的结果却是4 和 3。原因是,宏在预处理时是原地替换,DOUBLE(1 + 1)在预处理时被替换为:2 * x + 1,自然结果就不是我们所想的。所以,宏函数中的参数都尽量带上括号,带上括号后在文本替换时就能够保证优先级顺序不出错。

  虽然上面的宏函数通过加括号后可以无误地完成需求,但是如果一个函数很复杂,每个变量都要加括号,写起来很费劲,代码看起来也很不舒服。所以,之前提到的内联函数就派上用场了。那么宏和内联函数有什么异同点呢?

内联函数和宏的区别

  • 宏是预处理时将代码原地替换(文本替换),而内联函数是在预处理的下一个步骤编译时将代码嵌入调用处。
  • 内联函数有类型检查、语法判断,而宏没有。
  • 宏和内联函数的展开还是有区别的,宏函数定义时每个参量都最好加上括号,而内联函数本质上还是函数并没有这么多的要求。
  • 内联函数通过inline关键字提醒编译器,编译器可以拒绝不符合条件的内联;而宏是在预处理时强制替换。
  • 宏不能直接访问类的私有成员,这种情况下使用内联函数会比较好,如get()、set()操作类的私有成员。
  • 因为宏在预处理时已经被原地替换了,所以宏函数不能够进入内部调试。
  • 两者相对于普通函数都有提高效率的作用,在不同场景使用根据需求使用宏或者内联,两者各有千秋。

参考文章

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
回答: C++中的内联函数函数都可以用来提高代码的运行速度,但它们在实现方式和功能上有一些区别内联函数在编译时展开,而函数在预编译时展开。内联函数会被直接嵌入到目标代码中,而函数只是简单地进行替换。内联函数具有类型检测、语法判断等功能,而函数没有这些功能。此外,内联函数满足函数的性质,比如有返回值、参数列表等,而函数没有这些限制。内联函数可以进行调试,而函数不可以。另外,函数不能访问对象的私有成员,但是定义在类内的内联函数可以访问。\[3\]因此,内联函数相对于函数来说更加安全和灵活,可以更好地解决函数调用开销的问题。 #### 引用[.reference_title] - *1* *2* [C++内联函数函数](https://blog.csdn.net/suren_jun/article/details/127243191)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C++函数内联函数(一看就明了)](https://blog.csdn.net/qq_44851228/article/details/108742194)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗夜无风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值