inline
在我们一般的函数调用中,都会有一个jmp指令去跳转到函数处,但是 inline 可以改变这种方式,直接将函数内容嵌入到调用方。例如:
#include <stdio.h>
// 使用 __attribute__((always_inline)) 强制编译器内联
inline int add(int a, int b) __attribute__((always_inline));
// inline 定义
inline int add(int a, int b)
{
return a + b;
}
int main()
{
int a = 10, b = 20;
int result = add(a, b);
printf("The result is: %d\n", result);
return 0;
}
上面的C语言,在一般情况下,在main
函数中会调用 add
函数,那么会产生一个 jmp
跳转,但是当我们使用了 inline
关键字后,编译器会将 add
函数中的功能附加到 main
函数中去。这里使用了 __attribute__((always_inline))
属性,用以设置强制内联。
但是,在我们反编译后,出现的结果如下:
在+8
和+15
处时上述代码中的向a
和b
分别赋值10
和20
。在之后应该向result
赋值add
后的结果,但是这里并没有看到对连续栈空间的操作,按道理来说result
应该在栈的0xc
处,但是饭汇编代码直接在0x10
处开始了操作,所以可以得出,add()
已经被内联至main
函数中。
注意事项
在使用inline关键字时,需要注意以下几点:
-
大部分情况下,inline关键字可以提高代码的执行效率,但并不是所有情况下都可以使用inline关键字。对于复杂的函数或包含循环、递归等特性的函数,使用inline关键字可能导致代码膨胀,反而降低执行效率。
-
inline关键字将函数的定义嵌入到函数调用的位置,会增加代码的长度。如果频繁调用的函数体较大,很可能导致代码膨胀,使得可执行文件的大小增大。
-
使用inline关键字修饰函数时,编译器默认会将函数的定义展开,而不管函数的规模大小。所以,不要滥用inline关键字,需要根据实际情况灵活选择是否使用inline关键字。
-
当函数作为inline函数进行内联展开时,编译器会将函数的参数和返回值在调用点进行替换。这就意味着,如果函数的参数和返回值是指针或复杂的数据结构,内联展开可能会导致代码的长度增大,进而影响执行效率。
在某些情况下,编译器可能会忽略inline关键字,即使将其添加到函数声明或定义处。这是因为编译器根据自身的规则和策略,判断是否将函数作为内联函数展开。这个时候就会将这里设置为一个函数调用,以便后续链接器进行重定位链接。链接器会去尝试寻找函数的地址,但是因为我们这里给了函数内联,所以函数不会被插入到编译后的对象文件中去,当链接器去寻找函数地址时,会出现函数未定义的情况。