C ++内联函数和重新声明

时间:2014-05-11 17:23:11

标签: c++ inline declaration redeclaration

首先,对不起我的英语。

由于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函数是第(1)行的内联函数吗?

我无法简洁地提出我的问题,但我认为已收到消息:)我试图了解函数何时应该内联标记,何时不是从C ++和程序员的角度来看#39; s(无论编译器对你的函数做什么)。

2 个答案:

答案 0 :(得分:1)

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

表示在标题中定义它。

当函数为inline时,必须在每个转换单元中定义,inline,基本上 1) #39;已使用。


inline只是积累。一个函数不能成为inline


除了这些注意事项inline用作优化提示之外,编译器可以自由忽略。在该容量中,它声明您希望内联函数代码调用此函数。一般来说,编译器可以更好地决定哪个是好主意。


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

答案 1 :(得分:1)

这句话:

  

由于GCC完全忽略了内联说明符,因此有点困难   让我知道函数何时被我内联标记。

是一个错误的基础。 (当然,我们可以用任何其他现代编译器替换GCC进行此讨论)。

当然,编译器可能会忽略inline关键字以确定函数是否内联 - 并且它只能内联未标记为内联的函数。但是,在生成最终输出时,编译器会使用inline关键字[并且它等同于“在struct中声明的body”],以避免在不同的编译单元中多次生成代码的函数的多个定义。例如:

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

 a.cpp:
    #include "foo.h"

    ...

 b.cpp:
    #include "foo.h"

    ... 

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

但是,你是对的,编译器不会根据inline关键字决定内联函数,而是基于其他方面,例如调用函数的次数,是否为该函数对编译器等是“可见的”

作为一个简单的规则:

  1. 编译器内联函数,它没有源代码。
  2. 编译器将内联虚拟函数(除非它可以确定虚函数所属对象的类型)。
  3. 编译器 内联函数很小和/或只调用一次,特别是如果函数是静态的。
  4. 由于内联在编译结束时发生(当所有源代码都被解析并放置在某种AST(抽象语法树)或类似形式中)时,无论函数是在使用点之前还是之后,通常都不会真的很重要 - 当然,如果调用的函数不是AST的一部分(源代码不可用),编译器别无选择,只能不内联它。

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