2010-01-26 30 views
4

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

考虑了foo.h:

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

富::酒吧可以在库名字叫foo.so的内联与否如果另一段代码包含Foo.h,它是否始终创建它自己的Foo :: bar副本,无论是否内联?

回答

2

头文件只是复制粘贴到源文件 - 这一切都#include呢。如果使用该关键字声明或在类定义内部定义,则函数仅为inline,而inline仅为提示;它不会强制编译器产生不同的代码或禁止你做其他任何事情。

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

下面是标准的不得不说的inline extern功能(7.1.2/4):

内联函数应 定义每个翻译单元中,它是用来 ,并应具有完全相同在每种情况下定义相同的 (3.2)。 [注意: 在翻译单元中出现其定义 之前遇到的对内联函数的调用可能是 。 ]如果 具有外部链接功能 在一个转换 单元中声明为 ,则应在 内部声明它在其中出现 的所有转换单元;不需要诊断。具有外部链接 的内联函数 在所有的 翻译单元中应具有相同的地址。外部内联函数 中的一个静态局部变量 总是指向同一个对象。 A extern inline 函数中的字符串文字是 中不同翻译单元中的同一个对象。

+0

我前段时间正在阅读,我没有得出结论,编译器会忽略'inline'关键字。它仍然可以在所有调用位置内联编码,但生成非内联版本并将其用于地址。当然,这只是个人的结论,我不确定它是否适用于任何编译器。还有一件事是,我知道没有编译器实际上强制执行de ODR,他们大多假定它 - 链接器将删除除了一个定义以外的所有定义,并假定所有其他定义完全相同。 – 2010-01-26 08:52:07

+0

顺便说一下,* inline *关键字确实会使编译器的行为不同,在段落末尾引用7.1.2 [dcl.fct.spec]/2:'在该位置执行此内联替换时不需要实现呼叫;但是,即使省略了这种内联替换,对于7.2.1中定义的内联函数的其他规则仍应遵守。',基本上是指您已经引用的内容 - 函数将在所有翻译单元中定义,并且不会违反ODR。使用模板和内联函数,ODR规则与常规函数不同 – 2010-01-26 09:06:03

+0

@David:我怀疑任何编译器都会直接忽略“内联”,但是可以自行决定是否正常调用“内联”或者内联定义的“外部”是内联的。 7.1.2实际需要的唯一东西是允许多个相同定义的替代ODR。内联函数的地址很常见,所以我想大多数编译器在这个问题上都是100%兼容的。但是,这只是重申我已经说过的话......你不同意或有一个问题......? – Potatoswatter 2010-01-26 09:47:43

1

它通常意味着它最终会为每个在链接时使用它的obj文件创建一个单独的内联方法。它也可能会失败或拒绝内联许多事情,所以这可能会导致一个问题,因为您可以结束臃肿的对象而不会获得内联的性能优势。虚方法内联也会发生同样的情况,所以值得强制插入并为内联失败设置警告(关于唯一有用的警告消息编译器给出的内容)。

+0

该标准要求extern内联函数在所有翻译单元中具有相同的地址,即在不同的obj文件中没有单独的副本。 – Potatoswatter 2010-01-26 08:22:10

+0

*地址*运算符的结果在所有翻译单元中返回相同地址的事实并不意味着该函数不能被内联。实际上,链接器可以内联没有声明为“inline”的函数,并且运算符的地址仍应工作并在所有转换单元中报告相同(单个)地址。 – 2010-01-26 08:54:56

+0

在完成内联操作时,我不是100%诚实的,但我确实知道在某些情况下,特别是在虚拟内联失败时,您可以结束内联操作,这些内联操作对于每个obj都是单独的副本。 – 2010-01-26 10:40:30

-1

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

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

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

+0

当然还有内联函数。你可以将地址作为一个,'extern inline'完全有效且定义明确。看到我的答案。 – Potatoswatter 2010-01-26 08:26:07

+0

-1误导性;例如,如果从DLL中导出内联函数,则编译器_will_会生成它的外联版本。 – 2010-01-26 08:55:31

+0

@Martin,这实际上是我的意思,“如果你设法导出一个内联函数,那么它肯定它不是内联了”! :-) – jdehaan 2010-01-26 09:39:43

0

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

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

做到这一点的一种方法是链接一次部分。这个想法是,在翻译单元获取代码的特殊类型的部分,其名称基于函数名称。在链接期间,链接程序将只保留一个名称相同的链接一段的实例。

相关问题