内联函数和宏定义的区别
内联函数和宏定义的区别
内联函数
定义
某度百科中对内联函数是这样定义的:内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展)。
由其定义我们可以看出,内联函数其本质是一个函数, 只不过其调用方式和普通函数有区别而已。普通函数在编译时期是通过函数调用机制(下面会简单讲到)对其进行调用,而内联函数是通过将函数体直接插入调用处来实现的,这样可以大大减少由函数调用带来的开销,从而提高程序的运行效率。
用法
一般来说inline用于定义类的成员函数。
对于一个类来说,其成员函数有两种定义的方式:一种是在类内定义和声明,一种是在类内声明,类外定义。具体如下:
- 类内定义和声明
class A
{
A(){}
void func()
{
cout << "hello" << endl;
}
~A(){}
};
- 类内声明,类外定义
class A
{
A();
void func();
~A();
};
A::A()
{
cout << "A::A()" << endl;
}
void A::func()
{
cout << "A::func()" << endl;
}
A::~A()
{
cout << "A::~A()" << endl;
}
其中类内定义和声明的成员函数默认是内联函数。 对于类内声明类外定义的成员函数来说,需要在声明或者定义处(或两处同时)加上inline关键字才能声明为内联函数。
如下:
class A
{
inline A(); // 声明处添加inline关键字
void func();// 定义处添加inline关键字
inline ~A();// 声明处和定义处添加inline关键字
};
A::A()
{
cout << "A::A()" << endl;
}
inline void A::func()
{
cout << "A::func()" << endl;
}
inline A::~A()
{
cout << "A::~A()" << endl;
}
宏定义
定义
宏定义在 C 语言源程序中允许用一个标识符来表示一个字符串,称为“宏/宏体” ,被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为“宏替换”或“宏展开”。 宏定义是由源程序中的宏定义命令完成的,宏代换是由预处理程序自动完成的。
由其定义我们可以看出,宏定义本质是未字符串取了一个简单的别名, 当程序中要使用某个比较复杂的原字符串的时候就可以用简单的别名把它替换掉。
用法
在 C 语言中,宏分为 有参数和无参数两种。
- 无参宏的宏名后不带参数,其定义和使用的一般形式为:
#include <iostream>
#define M "hello word" // 无参数宏定义
#define MAX 10 //无参数宏定义
using namespace std;
int main()
{
cout << M << endl; // 无参数宏使用
cout << MAX << endl; // 无参数宏使用
return 0;
}
有参宏的宏名后带参数,其定义和使用的一般形式为:
#include <iostream>
#define M(y) (y)*3+(y)*3 // 有参数宏定义
using namespace std;
int main()
{
cout << M(5) << endl;
return 0;
}
内联函数和宏定义的区别以及使用场景
内联函数
内联函数优点
- inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高。
- 类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
- inline函数可以作为一个类的成员函数,与类的普通成员函数作用相同,可以访问一个类的私有成员和保护成员。内联函数可以用于替代一般的宏定义,最重要的应用在于类的存取函数的定义上面。
内联函数缺点
- 内联函数的函数体一般来说不能太大,如果内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。
宏定义
宏定义优点
- 方便程序的修改。使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时, 我们可以用较短的有意义的标识符来写程序,这样更方便一些。
宏定义缺点
- 嵌套定义过多可能会影响程序的可读性,而且很容易出错,不容易调试。
- 对带参的宏而言,由于是直接替换,并不会检查参数是否合法,存在安全隐患。
使用场景
- 一般来说,用宏来代表简短的表达式比较合适。
- 还有一些任务根本无法用函数实现,但是用宏定义却很好实现。比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。
- C++的inline的提出就是为了完全取代宏定义,因为inline函数取消了宏定义的缺点,又很好地继承了宏定义的优点。
- 内联函数一般用于类的成员函数,且函数体比较简单的情况下(不包含复杂的控制语句,如循环,switch等)。
补充:C++中函数调用机制
一般来说,当任何一个函数调用发生时,系统都要作以下工作:
(1)建立栈空间;
(2)保护现场:主调函数运行状态和返回地址入栈;
(3)为被调函数中的局部变量分配空间,完成参数传递;
(4)执行被调函数函数体;
(5)释放被调函数中局部变量占用的栈空间;
(6)回复现场:取主调函数运行状态及返回地址,释放栈空间;
(7)继续主调函数后续语句。
上一篇: 搬砖:面试---内联函数和宏定义的区别