【C++】内联函数

在了解内联函数之前,得先说一下c语言中的宏函数,下面就来实现一个宏函数:

#include <iostream>
using namespace std;

#define ADD(a,b) ((a)+(b))//这就是一个宏函数

int main()
{
	int x = 2;
	int y = x * 2;
	int ret = ADD(x, y);
	cout << ret << endl;
	system("pause");
	return 0;
}

宏函数虽然看起来很简单,但是有很多细节还是要注意的,比如

  • 宏定义注意事项

1.宏函数定义时要特别注意格式,尤其是括号,能加的时候就尽量加上,否则容易出现优先级错误。

2.宏函数的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。

3.宏函数往往会导致较低的代码执行效率,甚至导致预料外的结果。

  • 宏的优点

1.没有函数压栈的开销,效率高;

2.增强了代码的复用性;

  • 宏的缺点

1.不能调试(在预处理阶段已经被替换);

2.没有类型安全的检查;

3..宏的代码长度很长(除去非常小的宏),每次使用时,宏代码都被插入到程序中,使得程序的长度大幅度增加,就导致代码可读性差,还容易误用。

因为宏有这么多缺点,c++中为了解决这种问题,使用enum(枚举)、const代替宏的常量定义,用inline(内联函数)去代替宏函数。

  • 内联函数与宏的区别

1.内联函数在编译时展开,可以做一些类型检测处理。宏在预编译时展开;内联函数直接嵌入到目标代码中,宏是简单的做文本替换。

2.C++中引入了类及类的访问控制,在涉及到类的保护成员和私有成员就不能用宏定义来操作。

  • inline相比宏的优点

1内联函数代码是被放到符号表中,使用时像宏一样展开,没有调用的开销效率很高; 
2内联函数是真正的函数,要进行一系列的数据类型检查; 
3.内联函数作为类的成员函数,可以使用类的保护成员及私有成员;

  • 内联函数概念

以inline修饰的函数叫做内联函数。编译时C+ +编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升了程序运行的效率。

#include <iostream>
using namespace std;

int Add(int left, int right)
{
	return left + right;
}

int main()
{
	
	int ret = 0;
	ret=Add(1, 2);
	cout << ret << endl;
	system("pause");
	return 0;
}

 

如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

#include <iostream>
using namespace std;

inline int Add(int left, int right)//使用inline修饰
{
	return left + right;
}

int main()
{
	
	int ret = 0;
	ret=Add(1, 2);
	cout << ret << endl;
	system("pause");
	return 0;
}

查看方式:
1.在release模式下,查看编译器生成的汇编代码中是否存在call Add
2.在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进
行优化,以下给出vs2013的设置方式)

具体是:解决方案资源管理器---->main.cpp----->右击属性,就进入下面的配置了:

因为我的vs有点挫,就不给大家展示那个反汇编代码了!

  • 特点

1. inline是一种以空间换取时间的做法,它省去了调用函数的额外开销。所以代码很长或者有循环/递归的函数不适宜
使用内联函数;
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为intine的函数体内有循环/递归等
等,编译器优化时会忽略掉内联。

3.inline不建议声明和定义分离,分离会导致链接错误。因为内联函数在编译时C+ +编译器会在调用内联函数的地方展开,展开之后就没有函数地址了,链接就找不到,如下面的代码,就会出现链接错误:

//f.h

#include <iostream>
using namespace std;
inline void f(int i);

//f.cpp
#include "f.h"
void f(int i)
{
	cout << i << endl;
}

//main.cpp
#include "f.h"
int main()
{
	f(10);
	return 0;
}
//出现链接错误:error LNK2001: 无法解析的外部符号 "void __cdecl f(int)"

这样就会运行出来:

//main.cpp

#include <iostream>
using namespace std;
inline void f(int i);

inline void f(int i)
{
	cout << i << endl;
}
int main()
{
	f(10);
	system("pause");
	return 0;
}

运行结果:

  • 为什么不能把所有的函数写成inline函数?

内联函数以代码复杂为代价,它省去了函数调用的开销来提高代码的执行效率。一方面,如果内联函数体内代码执行时间比函数调用开销大时,使用内联函数就没有太大的意义;另一方面,每一处内联函数的调用都要复制代码,消耗更多的内存空间。以下情况不宜使用内联函数:
1.函数体内的代码比较长,将导致内存消耗代价; 
2.函数体内有循环,函数执行时间要比函数调用开销大;

还需要注意的是: 
1.内联函数时无法获取其地址的;
2.内联函数不可以做为虚函数(内联函数,构造函数,静态函数时都不能为虚函数的)

  • 为什么inline能够很好的取代预定义?

1.inline定义的内联函数,函数的代码在使用时直接被替换,没有函数调用的开销,提高了效率。

2.类的内联函数也是函数,编译器在调用时会检查它的参数,消除隐患

3.定义在类内的成员函数默认定义为内联函数。可以使用所在类的保护成员和私有成员。
 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值