编译器如何处理内联导出函数?

时间:2010-01-26 07:57:34

标签: c++ compiler-construction export inline

如果头文件包含函数定义,则编译器可以内联它。如果导出该函数,则在链接期间还必须使客户端可以使用该函数的名称和实现。编译器如何实现这一目标?它是否内联函数并为外部调用者提供实现?

考虑Foo.h:

class Foo
{
    int bar() { return 1; }
};

Foo :: bar可以在库foo.so中内联或不内联。如果另一段代码包含Foo.h它是否总是创建自己的Foo :: bar副本,无论是否内联?

4 个答案:

答案 0 :(得分:2)

标题文件只是复制粘贴到源文件中 - 这都是#include所做的。如果使用该关键字声明或在类定义中定义函数,则函数仅为inline,并且inline仅为提示;它不会强制编译器生成不同的代码或禁止您执行任何其他操作。

您仍然可以使用inline函数的地址,或者等效地提及,导出它。对于这些用途,编译器只是将其视为非inline并使用One Definition Rule(表示用户不能将两个定义应用于同一函数,类等的规则)来“确保” “该函数定义一次,只导出一个副本。通常,您只能在所有来源中使用一个定义;内联函数必须有一个定义,该定义在每个使用的源中都会重复。

以下是关于inline extern函数(7.1.2 / 4)的标准:

  

应在中定义内联函数   每个翻译单元   使用过,并且应该完全相同   每种情况下的定义(3.2)。 [注意:   对内联函数的调用可能是   在定义之前遇到过   出现在翻译单元中。 ]如果   具有外部链接的功能是   在一个翻译中声明内联   单位,应在内联合宣布   所有翻译单位   出现;无需诊断。一个   具有外部链接的内联函数   总共应具有相同的地址   翻译单位。一个静态的本地   外部内联函数中的变量   总是指同一个对象。一个   外部内联中的字符串文字   函数是同一个对象   不同的翻译单位。

答案 1 :(得分:1)

这通常意味着它最终会为链接时使用它的每个obj文件创建一个单独的内联方法。它也可能失败或拒绝内联很多东西,因此这可能会导致问题,因为你可以结束膨胀的obj而不会获得内联的性能。虚拟方法内联可能会发生同样的情况,因此值得强制内联和设置内联失败的警告(关于编译器提供的唯一有用的警告消息)。

答案 2 :(得分:0)

通过导出,我猜你的意思是获得指向函数的指针,然后通过指针调用函数。

是的,在这种情况下,编译器将生成一个常规函数,以便可以从指针调用它。

执行此操作的一种方法是使用链接一次部分。这个想法是在翻译单元中获取特殊类型的部分中的代码,该部分具有基于函数名称的名称。在链接期间,链接器将只保留一个具有相同名称的一次性链接的实例。

答案 3 :(得分:-1)

在编译的二进制文件中不存在内联函数:这是因为它们被直接放在调用站点(所谓的IN-LINE)。内联函数的每次使用都会导致在该位置引入完整的代码。

因此无法导出内联函数,因为它们不存在。但是如果你在一个标题中有一个定义,你仍然可以使用它们。是的,你必须提供内联函数的定义,否则你不能使用它。

如果您设法导出内联函数,那么它确定它不再内联:inline不是严格的语义元素。根据编译器和编译器设置,一个编译器可能选择内联,另一个不是,有时提供警告,有时甚至是错误(我更喜欢这是默认行为,因为它显示了意外事件发生的地方)< / p>