【问题标题】:g++ doesn't inline functionsg++ 不内联函数
【发布时间】:2011-12-13 14:09:59
【问题描述】:

有这样的代码:

int fun1(){
   return 2 + 3;
}

inline int fun2(){  
   return 4 + 5;
}

int main(){
    int a = fun1();
    int b = fun2();
    return 0;
}

及对应的汇编代码:

    .file   "prog47.cpp"
    .text
.globl _Z4fun1v
    .type   _Z4fun1v, @function
_Z4fun1v:
.LFB0:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    movl    $5, %eax
    popl    %ebp
    ret
    .cfi_endproc
.LFE0:
    .size   _Z4fun1v, .-_Z4fun1v
    .section    .text._Z4fun2v,"axG",@progbits,_Z4fun2v,comdat
    .weak   _Z4fun2v
    .type   _Z4fun2v, @function
_Z4fun2v:
.LFB1:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    movl    $9, %eax
    popl    %ebp
    ret
    .cfi_endproc
.LFE1:
    .size   _Z4fun2v, .-_Z4fun2v
    .text
.globl main
    .type   main, @function
main:
.LFB2:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $16, %esp
    call    _Z4fun1v
    movl    %eax, 12(%esp)
    call    _Z4fun2v        # why fun2 is called?
    movl    %eax, 8(%esp)
    movl    $0, %eax
    leave
    ret
    .cfi_endproc
.LFE2:
    .size   main, .-main
    .section    .note.GNU-stack,"",@progbits

为什么函数 fun2 没有像普通函数一样被内联和调用?我读过 inline 关键字只是对编译器的提示,它不必内联函数,但是 fun2 的定义非常简单,因此可以内联。如何强制 g++ 内联函数?

【问题讨论】:

  • [您确定需要内联函数吗?还是只是出于兴趣才问这个问题?]
  • 所有代码都应该消失,因为它没有有用的副作用。不要忘记启用优化器。
  • 开启一些优化并将你的内联函数声明为静态将是一个好的开始。
  • 注意函数内联只在-O3模式下有效linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/…
  • @cyco130,好主意。如果总是“静态内联 T f(...)”,它可以改变内联的内容吗?

标签: c++ inline


【解决方案1】:

开启优化。这就是使用 -O2 (x86_64) 的 main 函数得到的结果:

0000000000400560 <main>:
  400560:   31 c0                   xor    %eax,%eax
  400562:   c3                      retq   

它不仅是内联的,它被移除了。

如果没有优化,编译器就不太可能内联。 (内联使代码更难调试,因此使用默认的非优化选项只进行非常中等级别的内联是个好主意。)

【讨论】:

    【解决方案2】:

    GCC 有一个强制内联的属性:always_inline

    inline int fun2()  __attribute__((always_inline));
    inline int fun2() {  
       return 4 + 5;
    }
    

    将使其适用于任何优化设置。

    【讨论】:

    • 我想说永远不要强迫编译器内联。在决定内联什么时,编译器总是会比人类做得更好。一个更简单的想法是打开将执行内联的优化。
    • 我还建议不要强制编译器内联。但我不同意编译器会总是比人类做得更好。有时人类会赢,而那种会赢的人也是那种知道什么时候可以无视这个建议的人。对于我们其他人,相信编译器:)
    • @LokiAstari 在某些情况下应该强制内联。它在调试中非常有用,在用于给函数起别名时也非常有用。除了类型安全之外,与宏的功能相同。
    • @ObscureRobot:不幸的是,人类分为三种类型:1) 知道自己对编译器一无所知的人。 2) 认为自己了解编译器的人 3) 对编译器有足够了解的人知道他们不了解编译器。非程序员属于 (1) 大多数程序员属于 (2)
    • IIRC,“always_inline”中的“always”指的是编译器的优化级别。也就是说,即使关闭优化,函数也会被内联。
    【解决方案3】:

    inlinecompiler hint。编译器可能实际上内联您的代码。

    【讨论】:

      猜你喜欢
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 2014-08-29
      • 2017-01-05
      • 1970-01-01
      • 1970-01-01
      • 2020-06-02
      相关资源
      最近更新 更多