欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++中内联函数和宏定义

程序员文章站 2024-03-21 10:17:58
...

内联函数

C++ 内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。

如果已定义的函数多于一行,编译器会忽略 inline 限定符。它能修饰任意函数,此关键字是一个建议,告诉编译器应该把此函数实现为内联函数。

最先进的现代编译器是优化的编译器,它们自己决定要内联的对象,所以一度被认为很重要的关键字,现在只是一个对编译器的建议。

特点:

  • 以空间换时间,提高函数调用的效率。
  • 递归函数不能被内联
  • 一般不要超过10行
  • 替换发生在编译时期
  • 在类中定义的函数都是内联函数,即使没有使用inline修饰
  • inline只是给编译器的建议,具体需不需要内联取决于编译器

内联函数和普通函数的区别:

1. 内联函数和普通函数的参数传递机制相同,但是编译器会在每处调用内联函数的地方将内联函数内容展开,这样既避免了函数调用的开销又没有宏机制的缺陷。

2. 普通函数在被调用的时候,系统首先要到函数的入口地址去执行函数体,执行完成之后再回到函数调用的地方继续执行,函数始终只有一个复制。内联函数不需要寻址,当执行到内联函数的时候,将此函数展开,如果程序中有N次调用了内联函数则会有N次展开函数代码,虽然提高了调用效率,但是增加了内存空间的使用。

3. 内联函数有一定的限制,内联函数体要求代码简单,不能包含复杂的结构控制语句。如果内联函数函数体过于复杂,编译器将自动把内联函数当成普通函数来执行

宏定义

在很多方面十分的方便,比如 “ #define MAX(x,y)  x > y ? x : y ” 取最大值是十分方便的,但是由于它是预处理时的简单替换,所以会发生一些无法察觉的问题:

#define ADD(x,y) x+y
void test(){
    int a= ADD(10, 20) * 10; //希望的结果是300
    cout << "a:" << a << endl; //所得的结果却是210
}
//-----------------其实质就是--------------------
void test(){
    int a= x + y * 10;  //编译器并不会给其加括号
    cout << "a:" << a << endl; 
}
#define mul(N) N*N

int main()
{
	mul(2+2);
	//mul("hello");	//不会进行类型检查
} 

执行结果为:8
因为展开成了:2+2*2+2

因此在宏定义时应该定义为:
#define mul(N) (N)*(N)	
此时运行结果为:16
展开后为:(2+2)*(2+2)

 

宏定义和内联函数的区别

  1. 1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率。内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。
  2. 宏定义是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换,内联函数则是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提高效率
  3. 宏定义是没有类型检查的,无论对还是错都是直接替换。内联函数在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表等
  4. 宏定义和内联函数使用的时候都是进行代码展开。不同的是宏定义是在预编译的时候把所有的宏名替换,内联函数则是在编译阶段把所有调用内联函数的地方把内联函数插入。这样可以省去函数压栈退栈,提高了效率。
  5. inline函数允许读取私有数据,宏替换不行

  6. 宏替换和inline函数都不能进行复杂循环操作(递归)

  7. 内联函数与宏定义一样是以消耗内存为代价的,过度使用内联函数会导致程序过于耗费内存空

相关标签: CPP c++