0

首先,对不起我的英语。

由于 GCC 完全忽略了内联说明符,所以我很难知道一个函数何时被我标记为内联。我想了解的是,当您对相同的函数进行一些重新声明(在相同的翻译单元或不同的翻译单元中)时,您的函数何时或在何种情况下被标记为内联(不管编译器会做什么)用你的提示)。

例如:

inline void print();

void print();

或者:

void print();
inline print();

用不同的内联说明符重新声明函数是什么意思?一个更复杂的例子:

#include <iostream>

void print();

int main()
{
    print(); // (1)
}

inline void print() { std::cout << "HELLO" << std::endl; }

从 C++ 的排他性角度而不是从编译器的角度来看,print函数是 inline 的(1)吗?

我无法简明扼要地提出我的问题,但我认为该消息已收到:) 我试图了解何时应该将函数标记为内联,何时不从 C++ 和程序员的角度来看(无论将编译器使用您的函数生成)。

4

2 回答 2

1

inline允许在两个或多个翻译单元中定义(基本上相同)外部链接功能。

这意味着在标题中定义它。

当一个函数是它时inline,它必须在每个使用它的翻译单元中定义,inline并且本质上1)相同。


inline只是积累。函数不能变为 un- inline


除了这些考虑因素之外,inline还可以作为优化提示,编译器可以随意忽略。在这种情况下,它声明您希望内联对该函数的机器代码调用。通常,编译器可以更好地确定哪里是一个好主意。


1 C++17 10.1.6/5 (dcl.inline/5):“内联函数或变量应在使用 odr 的每个翻译单元中定义,并且在每种情况下都应具有完全相同的定义”< /支持>

于 2014-05-11T17:35:46.027 回答
1

这个句子:

由于 GCC 完全忽略了内联说明符,所以我很难知道一个函数何时被我标记为内联。

是一个不正确的开始。(当然,我们可以用任何其他现代编译器替换 GCC 来进行讨论)。

当然,编译器可能会忽略inline关键字来决定函数是否内联 - 它肯定可以内联未标记为内联的函数。然而,编译器inline在生成最终输出时确实使用了关键字[它相当于“在结构内声明的主体”],以避免在不同的编译单元中多次定义一个函数的多个定义。例如:

 foo.h:
    inline int foo() { return 42; }

 a.cpp:
    #include "foo.h"

    ...

 b.cpp:
    #include "foo.h"

    ... 

如果函数foo没有被声明,如果我们将 a.cpp 和 b.cpp 的结果链接到一个可执行文件中inline,链接器会抱怨函数的多个定义。foo

但是,你是对的,编译器不会根据inline关键字来决定内联函数,而是根据其他方面,比如函数被调用了多少次,函数的源代码是否“可见”编译器等

作为一个简单的规则:

  1. 编译器不会内联它没有源代码的函数。
  2. 编译器不会内联虚函数(除非它可以确定虚函数所属对象的类型)
  3. 编译器内联小的和/或只调用一次的函数,特别是如果函数是静态的。

由于内联发生在编译结束时(当所有源代码都被解析并以某种 AST(抽象语法树)或类似形式放置时),所以函数是在使用点之前还是之后通常并不真正问题 - 当然,如果调用的是不属于 AST 的函数(源代码不可用),编译器别无选择,只能不内联它。

“源不可用时无法内联”的例外是所谓的 LTO“链接时间优化”。传统的链接器只会获取一组机器代码指令,并以它们列出的任何顺序将它们粘贴在一起,而不知道函数是什么[简化视图,足以进行讨论],然后修复函数和变量的任何地址编译器无法直接解析。相比之下,LTO 将“目标文件”存储为中间表示,最终的机器代码生成由链接器阶段完成。这意味着链接器有足够的信息来例如移动代码以将一个函数中的代码内联到另一个函数中。该技术在最新版本中可用,例如 gcc(4.9.0 具有 LTO 作为完整功能,

于 2014-05-11T17:46:30.030 回答