当我尝试构建此代码时
inline void f() {}
int main()
{
f();
}
使用命令行
gcc -std=c99 -o a a.c
我收到一个链接器错误(对的未定义引用f
)。如果我使用static inline
或extern inline
而不是just inline
,或者使用进行编译,则该错误消失-O
(因此该函数实际上是内联的)。
这种行为似乎在C99标准的6.7.4(6)段中定义:
如果翻译单元中某个函数的所有文件范围声明都包含
inline
不带的函数说明符extern
,则该翻译单元中的定义为内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中使用外部定义。内联定义提供了外部定义的替代方法,翻译器可以使用该替代方法在同一翻译单元中实现对该函数的任何调用。未指定对函数的调用是使用内联定义还是使用外部定义。
如果我正确理解了所有这些内容,则具有inline
上面示例中定义的功能的编译单元仅在存在相同名称的外部函数的情况下一致地编译,并且我永远不知道自己的函数还是外部函数被调用。
这种行为不是完全愚蠢吗?在inline
不使用C99的情况下static
或extern
在C99中定义功能是否有用?我想念什么吗?
答案摘要
当然,我错过了一些东西,而且行为也不愚蠢。:)
正如Nemo解释的那样,想法是放置函数的定义
inline void f() {}
在头文件中,只有一个声明
extern inline void f();
在相应的.c文件中。仅extern
声明触发外部可见的二进制代码的生成。inline
在.c文件中确实没有使用-仅在标头中有用。
正如乔纳森回答中所引用的C99委员会的基本原理所阐明的那样,inline
所有内容都与编译器优化有关,该优化要求函数定义在调用现场可见。这只能通过将定义放在标头中来实现,当然,标头中的定义一定不能在每次编译器看到它时都发出代码。但是由于没有强制编译器实际内联函数,因此外部定义必须存在于某处。