【问题标题】:inline vs static inline c内联与静态内联c
【发布时间】:2018-07-18 13:58:03
【问题描述】:

以下是在 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 函数,有或没有内联:生成的代码相同

测试 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 关键字不会强制内联。但是对于 Test 1 结果,什么可以防止 show_text 在 main 中替换代码?

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

【问题讨论】:

标签: c inline


【解决方案1】:

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

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

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

正如您所建议的,在当前形式下,inline 关键字实际上毫无意义,除非编译器认真对待它。

【讨论】:

  • 多么奇怪。 Linux 内核中的某些地方不遵守内联会导致错误的代码生成。
  • @Joshua:Linux 内核不是通用的 C 程序。它在某些地方依赖于 GNU C 编译器——除非 C 编译器与 GCC 兼容,否则它不会编译。 GCC 早在标准 C 之前就有了inline。它的版本有不同的语义。不过,它现在遵循 (C99) 标准语义,适用于 inline
【解决方案2】:

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

另外,inline 关键字现在不像过去那样有效。我想说它的唯一目的是在头文件中包含函数,而不会出现关于重复符号的链接器错误(当多个 cpp 文件使用这样的头文件时)。

让你的编译器完成它的工作。只需启用优化(包括 LTO),无需担心细节。

【讨论】:

  • 这是对 C 问题的 C++ 答案。 C 中的 inline 与 C++ 中的 inline 的工作方式不同。
猜你喜欢
  • 1970-01-01
  • 2012-05-09
  • 1970-01-01
  • 1970-01-01
  • 2010-12-28
  • 2014-09-19
  • 2016-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多