C++内联函数与宏函数

总结
宏函数的使用不仅仅是为了炫技,而是一种高效的手段,同样C++提供的内联函数,也是非常有效的手段,这里来详细说明一下宏函数和内联函数的区别与相同点。


废话说到这里,开始直接上干货


宏函数

为什么要使用宏函数

因为很装X,emmmmm,开个小玩笑。

在C程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但使用起来像函数。

预处理阶段,预处理器就将以替换的方式将宏函数的内容进行替换,省去了参数压栈,生成汇编语言的CALL调用,返回参数,执行return等过程,从而提高了程序的效率。

但是使用宏函数有个致命的缺点就是可能出现边际效应,即宏函数,无脑的替换你的代码,导致替换的代码可能和周围的代码加载一起出现问题,比如。

#include<iostream>
using namespace std;

#define A 1+2

int main()
{
    cout << A * 3 << endl;
    return 0;
}

> 7

一般我们希望的是(1+2)*3,最后的结果是9,但是define则是在预编译阶段,无脑的替换而已,如果只是简单的宏函数还好,如果你要定义复杂的宏函数,那么很可能出现边际效应。

带参数的宏函数

不带参的宏,一般都是定义常量,如果需要使用宏函数,基本都是带参的。不过这里是假参数,不是真正的参数,只是替换而已。

#define offsetof2(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

这里以linux内核中的一段宏函数作为讲解。首先定义宏函数offsetof2(TYPE, MEMBER)

里面有两个参数,分别是TYPE,和MEMBER。

后面()中的内容则是函数体。((TYPE*)0)->MEMER,这句话表示的是将0(地址),强转成TYPE*类型,然后这个类型(一般指结构体),这个结构体调用了MEMER这个成员。

然后 (size_t)&则是将结构体中的这个成员取地址,在转换成size_t类型(在32位系统中,是无符号int,在64位系统中是无符号long)

所以这里的意思就是将地址为0的结构体,得到他的成员地址,这样成员的地址到结构体指针之间的偏移量就计算出来了。

下面这段测试代码,你讲彻底了解他的意思

#include<iostream>
using namespace std;

#define offsetof2(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

struct user_info {
	int a;
	int b;
};

int main()
{
	cout << ((user_info*)0) << endl;
	cout << &(((user_info*)0)->b) << endl;
	cout << (size_t)&(((user_info*)0)->b) << endl;
	cout << offsetof2(user_info, b) << endl;;
	return 0;
}

输出结果

00000000
00000004
4
4

这样实现的效率很高,如果你要实现的函数体中代码很少,但是需要重复使用,那么使用宏函数,可以大大节省函数调用的时间。

不仅如此, 如果宏函数和函数名相同,那么优先使用宏定义。

其实也很好理解,因为宏函数是在预编译阶段起作用。

内联函数

这里我们在讲一下函数的调用过程。

函数调用在执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,还需要将函数的返回地址放入栈中,最后才跳转到函数内部执行。因此如果函数内部代码消耗时间很短的话,那么相关而言,函数调用时间就非常耗费时间。

另外,函数执行return语句返回时,需要从栈中回收形参和局部变量占用的空间,然后从栈中取出返回地址,在跳转到该地址继续执行,这个过程也是耗时的。

在C中,我们常用宏函数来解决这个问题,但是宏函数用不好容易出现边际效应,因此C++中常用inline(内联)函数来解决函数的调用开销问题。即:

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

内联函数在编译器处理调用内联函数的语句时,不会将该语句编译成函数调用的指令,而是直接将整个函数体的代码插入调用语句处,就像整个函数体在调用处被重写了一遍一样。

因此内联函数也可以省去调用函数的额外开销,但是代码量会增加,因为它是将函数体调用处的地方重写了,增加了代码的冗余,有点用空间换时间的感觉。

特性
  • 内联函数必须是和函数体声明在一起才有效。不建议将声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

内联函数和宏函数的异同点

相同点:
  • 都可以节省函数调用的开销
不同点
  • 内联函数在编译时执行,而宏函数在预处理时执行。
  • 宏定义不检查函数参数,返回值,只是展开;内联函数会检查参数类型
  • 内联函数是真正的函数,只是在需要的时候,内联函数像宏一样展开,所以取消了函数的参数压栈。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值