当我try 构建此代码时

inline void f() {}

int main()
{
    f();
}

使用命令行

gcc -std=c99 -o a a.c

我得到一个链接器错误(未定义对f的引用).如果使用static inlineextern inline而不是inline,或者使用-O编译(因此函数实际上是内联的),错误就会消失.

C99标准第6.7.4(6)段似乎对这种行为进行了定义:

如果翻译单元中某个函数的所有文件范围声明都包含不带externinline函数说明符,则该翻译单元中的定义是内联定义.内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中使用外部定义.内联定义提供了外部定义的替代方案,翻译器可以使用外部定义在同一翻译单元中实现对函数的任何调用.未指定对函数的调用是使用内联定义还是外部定义.

如果我正确理解了所有这些,那么在上面的示例中,一个函数定义为inline的编译单元只有在存在同名外部函数的情况下才能进行一致编译,而且我永远不知道是否调用了我自己的函数或外部函数.

这样的行为不是很愚蠢吗?在C99中定义一个没有staticextern的函数inline有用吗?我是不是遗漏了什么?

答案摘要

当然,我错过了什么,而且这种行为并不愚蠢

作为Nemo explains,我们的 idea 是将函数的definition

inline void f() {}

在头文件中,只有declaration

extern inline void f();

在相应的.c文件.只有extern声明触发外部可见二进制代码的生成.事实上,inline在计算机中是没有用的.c文件——它只在标题中有用.

正如这rationale of the C99 committee quoted in Jonathan's answer篇文章所解释的那样,inline都是关于编译器优化的,这些编译器优化要求函数的定义在调用点是可见的.这只能通过将定义放在头中来实现,当然头中的定义不能在编译器每次看到它时都发出代码.但是,由于编译器没有被强制实际内联函数,因此必须在某个地方存在外部定义.

推荐答案

其实这个很好的回答也回答了你的问题,我想:

What does extern inline do?

其思想是可以在头文件中使用"inline",然后在.c文件中使用"extern inline"."外部内联"就是如何指示编译器哪个目标文件应该包含(外部可见)生成的代码.

[更新,详细说明]

我不认为"inline"(没有"static"或"extern")在应用程序中有任何用处.c文件.但在头文件中,它是有意义的,在某些情况下,它需要相应的"extern inline"声明.c文件来实际生成独立代码.

C++相关问答推荐

为什么这个gcc迂腐的人忽视了扩展?

两个看似相同的代码的不同行为

什么C代码将确定打开的套接字正在使用的网络适配器?

编译SDL 2时缺少SDL_ttf

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

C/SDL程序,渲染不使用我的渲染器

__VA_OPT__(,)是否可以检测后面没有任何内容的尾随逗号?

为什么在4.9.37版的内核中,kfio还需要smp_wmb呢?

将指针作为参数传递给函数

无效指针值在函数调用之间莫名其妙地改变

是什么让numpy.sum比优化的(自动矢量化的)C循环更快?

SSH会话出现意外状态

如何使解释器存储变量

从BIOS(8086)中读取刻度需要多少?

为什么我的半数组测试和奇数组测试不起作用?(我使用Assert进行调试)

我编写这段代码是为了判断一个数字是质数、阿姆斯特朗还是完全数,但由于某种原因,当我使用大数时,它不会打印出来

C中的空指针是什么(_N)?

System V 消息队列由于某种原因定期重置

SSE 向量与 Epsilon 的比较

与 C 相比,C++ 中无副作用的无限循环的好处是 UB?