C++编程之内联函数,需要看编译器心情的函数,你知道吗?

题记,你知道的编程语言中有哪些类型的函数呢?如果你学过C++的,你知道内联函数吗?这个优秀又隐蔽的存在,本文将带你初步了解一下内联函数。


系列文章

C++编程之命名空间、const常量
C++编程之引用的详细总结
C++中引用的本质到底是什么?
C++中类的构造函数和析构函数(一)
C++编程之运算符重载


常规函数

    在程序的运行中,函数调用时,程序会跳到另一个地址(函数地址)中,执行到函数调用指令时,程序将在函数调用后存储该指令的内存地址,并将函数参数复制到堆栈中,跳到标记函数起点的内存单元,执行函数代码(可能还需要将返回值放入寄存器中),然后跳回到地址被保存的指令处。这样来回跳跃以及入栈等频繁操作,会消耗系统内存,增加系统开销。因此在C/C++中,一般将短小精悍的函数写成宏函数。

宏函数

    一般建议将短小、频繁使用的函数封装成宏函数,调用时,直接宏展开,跑源码,减少入栈出栈的系统开销。

#define ADD(x,y) x+y

int main()
{
	int a = 100;
    int b = 200;
    int c = ADD(a+b);
    // c=300
}

    但是宏函数还是有很多缺陷,比如:

int ret = ADD(10 + 20) * 20;  
// 按照常识一般是600,但运行结果其实是410.因为宏展开是这样的 10+20*20  按照运算符优先级,计算出是410

    那如何避免如上问题呢?最简单的办法是在每个操作符之间加入括号。
    但是如下示例,比较两个数的大小,我们使用宏函数表示,每个该加括号的地方都加入括号

#define MyCompare(a,b) (((a)<(b))?(a):(b))

// 调用

int a=10;
int b=20;
MyCompare(a,b); // 正常
MyCompare(++a,b); //应该是多少呢?结果令人吃惊,居然是12.原因是宏展开后(((++a)<(b)?(++a):(b))),即发生了2次++。

    同样示例如下


#define Square(x)(x)*(x)

int main()
{
	int a = 10;
    int b = Square(++a); // 结果不是预期
}

    因此,总结以下宏函数的缺点:

  • 运算完整性无法保证,需要加小括号;
  • 即使加入括号修饰符,有些情况依然会出现和预期不一样的结果
  • 宏函数不重视作用域

基于以上缺点,在C++中引入了一个新的函数,那就是内联函数。

内联函数

    内联函数具有普通函数的所有特性,但是还具有在适当的时候内类似宏展开,不会有入栈出栈的系统开销。

内联函数定义如下

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

注意点:

  • 函数的声明和实现必须同时加inline关键字,否则会按照普通方式处理
// TestInline.h

inline int MyCompare(int a, int b);

// TestInline.cpp

inline int MyCompare(int a, int b)
{
	return a > b ? a : b;  
}
  • 成员函数的前面隐藏的加了inline。
  • 内联函数实现了空间换时间,提高效率。

    说到这里,很多人可能会想,既然这么好,那我以后所有的函数都写内联函数,那我要遗憾的告诉你,这就错了!!!

    内联函数并不是一直都有效的,还要看编译器的心情。以下情况编译器可能不考虑:

  1. 不能有任何形式的循环
  2. 不能存在过多的条件判断语句
  3. 函数体不能过于庞大
  4. 不能对函数进行取址操作

    内联仅仅是给编译器的一个建议,编译器不一定会按照你的建议,如果你没将函数声明为内联函数,编译器可能会给你设置为inline,好的编译器会自动将一些频繁调用短小的函数自动设置为内联函数。

发布了19 篇原创文章 · 获赞 283 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/Marble_ccp/article/details/105130310