没有“静态”或“外部”的“内联”在C99中是否有用?

时间:2011-06-10 22:14:31

标签: c inline c99

当我尝试构建此代码时

inline void f() {}

int main()
{
    f();
}

使用命令行

gcc -std=c99 -o a a.c

我收到链接器错误(对f的未定义引用)。如果我使用static inlineextern inline而不是inline,或者我使用-O进行编译(因此函数实际内联),则错误消失。

这种行为似乎在C99标准的第6.7.4(6)段中定义:

  

如果翻译单元中函数的所有文件范围声明都包含inline函数说明符而没有extern,则该翻译单元中的定义是内联定义。内联定义不提供函数的外部定义,也不禁止另一个转换单元中的外部定义。内联定义提供了外部定义的替代,翻译器可以使用该定义在同一翻译单元中实现对该功能的任何调用。未指定对函数的调用是使用内联定义还是使用外部定义。

如果我理解了这一切,如上面的例子中一个函数定义为inline的编译单元只有一个具有相同名称的外部函数才能一致地编译,我永远不知道我自己的函数或者调用外部函数。

这种行为不是完全愚蠢吗?在C99中定义没有inlinestatic的函数extern是否有用?我错过了什么吗?

答案摘要

当然我错过了什么,行为并不愚蠢。 :)

作为Nemo explains,我们的想法是将定义放在函数

inline void f() {}

在头文件中,只有声明

extern inline void f();

在相应的.c文件中。只有extern声明才会触发生成外部可见的二进制代码。确实在.c文件中没有使用inline - 它只在标题中有用。

rationale of the C99 committee quoted in Jonathan's answer表示时,inline完全是关于编译器优化的,它需要在调用的站点上看到函数的定义。这只能通过将标题放在标题中来实现,当然,标题中的定义在编译器每次看到它时都不能发出代码。但由于编译器不是强制实际内联函数,因此必须在某处存在外部定义。

3 个答案:

答案 0 :(得分:37)

实际上,这个优秀的答案也回答了你的问题,我想:

extern inline

这个想法是“inline”可以在头文件中使用,然后在.c文件中使用“extern inline”。 “extern inline”就是如何指示编译器哪个目标文件应包含(外部可见)生成的代码。

[更新,详细说明]

我认为.c文件中没有“内联”(没有“静态”或“外部”)的用法。但是在头文件中它是有意义的,它需要在某些.c文件中使用相应的“extern inline”声明来实际生成独立代码。

答案 1 :(得分:24)

答案 2 :(得分:0)

>我收到链接器错误(对f的未定义引用)

在这里工作:Linux x86-64,GCC 4.1.2。可能是编译器中的错误;我没有在禁止给定程序的标准中引用的段落中看到任何内容。请注意使用 if 而不是iff

  

内联定义提供替代外部定义,翻译者可能用于在同一翻译单元中实现对该功能的任何调用。

因此,如果您知道函数f的行为并且想要在紧密循环中调用它,则可以将其定义复制粘贴到模块中以防止函数调用; ,您可以提供一个定义,就当前模块而言,它是等效的(但跳过输入验证,或者您可以想象的任何优化)。但是,编译器编写器可以选择优化程序大小。