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

内联函数与宏定义函数

程序员文章站 2024-03-23 14:37:10
...

面试时被问到了这个问题,当时突然懵了,所以来整理一下。如有疏漏,还望指摘。

内联函数与宏定义的函数很相似,都是在运行前,先将一些简短的函数,直接替换为实现代码,以此来省去函数调用时,参数入栈、程序跳转等的时间开支。

宏定义的函数:
使用宏定义#define定义的函数。其在预编译阶段就被进行简单的替换,因为只是简单的替换,所以无需定义参数和返回值的类型,也不会对参数进行临时拷贝以及析构。如下宏定义函数:

#define ADD(a, b) a+b
void main(){
    int x=1, y=2, z;
    z = ADD(x,y);
}

这段代码就会被替换为如下代码:

void main(){
    int x=1, y=2, z;
    z = x+y;
}

宏定义函数使用时值得注意以下三点:

  • 首先,宏定义函数不会进行类型检查,它不会检查传入的参数类型是否正确,传出的参数类型是否正确,因为在定义时,就不需要规定这些。

  • 其次,因为只是进行简单的替换,所以如果不注意的话,执行顺序可能会和预想的不一样。比如还是上面的宏定义函数,如果我想计算

    z=3 * ADD(x,y);
    

    就会被替换为

    z = 3 * x + y;
    

    这样在执行时,其实会先计算3*x,在计算+y,而与我们预想的逻辑不同。

  • 最后,因为不会制作传入参数的临时拷贝,而只是进行简单的替换,所以如果传入的参数是一个表达式(如x++),或者是一个函数(func())的话,这个表达式或者函数可能会被多次执行。如下:

    #define ADD(a) a+a
    void main(){
        int x=1, y;
        y = ADD2(x++);
    }
    

    这段代码在执行时就会被替换为:

    void main(){
        int x=1, y;
        y = x++ + x++;
    }
    

    其中x++就会被多次执行。

内联函数:
使用关键词inline修饰的函数为内联函数。内联函数是指在编译阶段,编译器将内联函数展开,替换为等效的实现代码,而不是进行函数调用。内联函数在使用上,在程序员看来,和一般函数无二,需要定义入参类型,返回值类型等,执行完毕会对函数内部的临时变量进行析构等。如下内联函数:

inline int addint(int a, int b){
    return a+b;
}
void main(){
    int x = 1, y = 2, z;
    z = addint(x ,y);
}

这段代码,在编译时就会被替换下面这样:

void main(){
    int x = 1, y = 2, z;
    {
        int _a = x;	//制作传入参数的临时拷贝
        int _b = y;
        int temp;	//制作传出参数的临时拷贝
        temp = _a + _b;	//函数体
        z = temp;	//传出返回值
    }//代码块结束,析构一些临时变量
}

编译器将函数替换为实现代码,并加入一些处理,使得其执行起来在程序员看来,与一般函数无二。
内联函数在使用时需要注意几点:

  • 首先,类内定义的函数,会被默认为内联函数。
  • 其次,即使定义了内联函数,编译器也会进行检查,如果函数太复杂,也不会进行替换。
  • 再有,内联函数关键字和函数声明写在一起是无效的,必须与函数的定义写在一起才能生效。
  • 最后,如果内联函数需要在其他源文件中进行调用,那么内联函数的定义必须写在头文件中,写在源文件中会造成编译出错。
  • 最后的最后,在多个源文件中可以定义相同的内联函数,但是在一个源文件中,只能有一个定义相同的内联函数。

从上面的介绍,我们可以看出以下几个相同点和不同点。
相同点:

  • 都是代码的替换。
  • 代码的逻辑都应该是简短的。

不同点:

  • 内联函数的替换是在编译阶段,宏定义的替换是在预编译阶段。
  • 内联函数会进行类型检查,宏定义函数不会进行类型检查。
  • 内联函数的参数中,表达式和函数只会被执行一次,宏定义函数中可能会被执行多次。
  • 内联函数的执行顺序和正常函数一样,宏定义函数替换后,表达式的执行顺序可能会有不同。

上一篇: Java面试基础宝典

下一篇: