内联与静态内联c

时间:2018-07-18 13:58:03

标签: c inline

以下是在x86_64上运行的一些简单测试,以显示使用内联语句时生成的汇编代码:

测试1

static inline void
show_text(void)
{
  printf("Hello\n");
}

int main(int argc, char *argv[])
{
  show_text();
  return 0;
}

和汇编程序:

gcc -O0 -fno-asynchronous-unwind-tables -S -masm=att main.c  && less main.s

        .file   "main.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello"
        .text
        .type   show_text, @function
show_text:
        pushq   %rbp
        movq    %rsp, %rbp
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        nop
        popq    %rbp
        ret
        .size   show_text, .-show_text
        .globl  main
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        call    show_text
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.1 20180312"
        .section        .note.GNU-stack,"",@progbits

测试1结果:编译器未考虑内联建议

测试2

代码与测试1相同,但带有-O1优化标志

gcc -O1 -fno-asynchronous-unwind-tables -S -masm=att main.c  && less main.s

        .file   "main.c"
        .text
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "Hello"
        .text
        .globl  main
        .type   main, @function
main:
        subq    $8, %rsp
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        movl    $0, %eax
        addq    $8, %rsp
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.1 20180312"
        .section        .note.GNU-stack,"",@progbits

测试2结果:不再在汇编器中定义show_text函数

测试3 show_text未声明为内联,-O1优化标志

测试3结果:不再有在汇编器中定义的show_text函数(带或不带inline:生成的代码相同)

测试4

#include <stdio.h>
static inline void
show_text(void)
{
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
}

int main(int argc, char *argv[])
{
  show_text();
  show_text();
  return 0;
}

产生:

gcc -O1 -fno-asynchronous-unwind-tables -S -masm=att main.c  && less main.s

       .file   "main.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello"
        .text
        .type   show_text, @function
show_text:
        pushq   %rbp
        movq    %rsp, %rbp
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        nop
        popq    %rbp
        ret
        .size   show_text, .-show_text
        .globl  main
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        call    show_text
        call    show_text
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.1 20180312"
        .section        .note.GNU-stack,"",@progbits

测试4结果: show_text在汇编器中定义,未考虑内联建议

我了解inline关键字不会强制内联。但是对于测试1 结果,什么可以防止main中的show_text代码替换?

到目前为止,我曾经在C源代码中内联一些小的静态函数。但是,从这些结果来看,它似乎毫无用处。 在使用某些现代编译器(并可能会编译优化的代码)时,为什么要声明我的一些小函数static inline

2 个答案:

答案 0 :(得分:0)

这是C语言标准人员的可疑决定之一...使用inline不能保证内联函数...该关键字仅向编译器建议该函数可以内联。

我已经与ISO WG进行了长时间的交流;这遵循了MISRA指南,该指南要求使用inline关键字在模块范围内声明所有static函数。他们的逻辑是,在某些情况下编译器不需要内联函数...同样,在某些情况下,未内联函数需要具有全局作用域!

恕我直言,如果程序员添加了inline关键字,那么建议是他们知道自己在做什么,并且该函数应该是内联的。

正如您所建议的那样,除非编译器认真对待它,否则inline关键字实际上是毫无意义的。

答案 1 :(得分:0)

在您的第一个测试中,您禁用了优化。内联是一种优化方法。不要期望它会发生。

inline关键字现在也不再像过去一样有效。我要说的唯一目的是在标头中包含函数,而不会出现有关重复符号的链接器错误(当多个cpp文件使用此类标头时)。

让您的编译器执行其工作。只需启用优化(包括LTO),就不必担心细节。