导航

C 关键字解析

发布时间:5 个月前 更新时间:4 months ago
开发

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)) 属性,用以设置强制内联。

但是,在我们反编译后,出现的结果如下:

alt text

+8+15处时上述代码中的向ab分别赋值1020。在之后应该向result赋值add后的结果,但是这里并没有看到对连续栈空间的操作,按道理来说result应该在栈的0xc处,但是饭汇编代码直接在0x10处开始了操作,所以可以得出,add() 已经被内联至main函数中。

注意事项

在使用inline关键字时,需要注意以下几点:

  1. 大部分情况下,inline关键字可以提高代码的执行效率,但并不是所有情况下都可以使用inline关键字。对于复杂的函数或包含循环、递归等特性的函数,使用inline关键字可能导致代码膨胀,反而降低执行效率。

  2. inline关键字将函数的定义嵌入到函数调用的位置,会增加代码的长度。如果频繁调用的函数体较大,很可能导致代码膨胀,使得可执行文件的大小增大。

  3. 使用inline关键字修饰函数时,编译器默认会将函数的定义展开,而不管函数的规模大小。所以,不要滥用inline关键字,需要根据实际情况灵活选择是否使用inline关键字。

  4. 当函数作为inline函数进行内联展开时,编译器会将函数的参数和返回值在调用点进行替换。这就意味着,如果函数的参数和返回值是指针或复杂的数据结构,内联展开可能会导致代码的长度增大,进而影响执行效率。

在某些情况下,编译器可能会忽略inline关键字,即使将其添加到函数声明或定义处。这是因为编译器根据自身的规则和策略,判断是否将函数作为内联函数展开。这个时候就会将这里设置为一个函数调用,以便后续链接器进行重定位链接。链接器会去尝试寻找函数的地址,但是因为我们这里给了函数内联,所以函数不会被插入到编译后的对象文件中去,当链接器去寻找函数地址时,会出现函数未定义的情况。