何时可以/将在 C++ 中内联函数?可以强制内联行为吗?

Posted

技术标签:

【中文标题】何时可以/将在 C++ 中内联函数?可以强制内联行为吗?【英文标题】:When can/will a function be inlined in C++? Can inline behavior be forced? 【发布时间】:2015-06-13 22:23:39 【问题描述】:

当我使用关键字inline 时,我试图获得预期的行为。 我尝试在不同的文件中调用函数,对函数进行模板化,使用内联函数的不同实现,但无论我做什么,编译器都不会内联函数。

那么在哪种情况下编译器会选择在 C++ 中内联函数呢?

这是我尝试过的代码:

inline auto Add(int i) -> int 
  return i+1;


int main()   
  Add(1);  
  return 0;

在这种情况下,我得到:

Add(int):
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    addl    $1, %eax
    popq    %rbp
    ret
main:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    $1, %edi
    call    Add(int)
    movl    $0, %eax
    popq    %rbp
    ret

再一次,

template<typename T>
inline auto Add(const T &i) -> decltype(i+1) 
  return i+1;


int main()   
  Add(1);  
  return 0;

我得到了:

main:
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp
    movl    $1, -4(%rbp)
    leaq    -4(%rbp), %rax
    movq    %rax, %rdi
    call    decltype (parm#1+(1)) Add<int>(int const&)
    movl    $0, %eax
    leave
    ret
decltype (parm#1+(1)) Add<int>(int const&):
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rax
    movl    (%rax), %eax
    addl    $1, %eax
    popq    %rbp
    ret

我使用https://gcc.godbolt.org/ 在这里获取汇编代码,但我也尝试在我的机器上使用 clang 和 gcc(有和没有优化选项)。

编辑:

好的,我在优化选项方面遗漏了一些东西。如果我设置GCC使用o3优化级别,我的方法是inlined。

但还是这样。 GCC 或其他编译器如何知道何时内联函数更好?

【问题讨论】:

你不应该在意。优化编译器在内联决策方面比你更聪明。 inline 是一个经常被忽略的提示(尽管您通常可以使用编译器选项强制它返回),编译器在绝大多数情况下更清楚如何内联。该关键字还有一些其他用途,但实际上并非如此。 Related. 在 Debian/Sid/x86-64 和 GCC 4.9.2 上调用 g++ -fverbose-asm -std=c++14 -O3 -S e.cc 编译器 is 内联您的第一个示例并且 main 变为空 -.e.g.像return 0; 一样编译(因为没有明显的副作用) 另外,请注意:有时使用 inline 关键字会降低性能。有很多关于内联的信息,但并非所有信息都是准确的,仅仅是因为它的使用在很大程度上取决于情况的细节。一些简单的阅读:isocpp.org/wiki/faq/inline-functions#inline-and-perf @SamuelMS:可悲的是,该常见问题解答完全忽略了inline 作为关键字在现代和时代中实际上没有影响一个功能是否应该是内联。 (因此,我希望几乎永远不会使用它来“降低性能”)。 【参考方案1】:

通常,您的代码总是只有在您指定时才内联:

__attribute__((always_inline))

例如(来自 gcc 文档):

inline void foo (const char) __attribute__((always_inline));

尽管强制编译器内联代码几乎从来都不是一个好主意。

您可以设置高优化级别(通过 O 标志)以实现最大内联,但更多详细信息请参阅gcc documentation

内联实际上是由许多参数控制的。您可以使用 -finline-* 选项设置它们。你可以看看他们here

【讨论】:

【参考方案2】:

顺便说一句,你实际上并没有声明一个函数。您声明了一个仿函数,一个可以调用但也可以存储状态的对象。而不是使用语法: 内联自动添加(int i)-> int

你的意思很简单: 内联 int Add(int i)

【讨论】:

这不是函子,只是另一种指定函数返回类型的方法。 C++11 不允许你推断函数的返回类型,但它允许你在函数签名之后指定类型。这对模板特别有用。欲了解更多信息:cprogramming.com/c++11/… Thibaut Mattio 是正确的。我被 lambda 表达式的语法相似性弄糊涂了。

以上是关于何时可以/将在 C++ 中内联函数?可以强制内联行为吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该啥时候为函数/方法编写关键字“内联”?

C++内联函数详解

C++ 为啥要引入内联函数、、

强制函数在Clang / LLVM中内联

内联函数和宏

C++基础语法梳理:inline 内联函数!虚函数可以是内联函数吗?