【发布时间】:2013-12-15 22:11:37
【问题描述】:
Linux 内核是仅使用旧的 C90 语法还是已针对 C99 / C11 特性进行了优化?
我想知道是否尽可能使用最新版本的 C。
【问题讨论】:
标签: linux-kernel
Linux 内核是仅使用旧的 C90 语法还是已针对 C99 / C11 特性进行了优化?
我想知道是否尽可能使用最新版本的 C。
【问题讨论】:
标签: linux-kernel
请参阅此答案的底部以获取更新。
Linux kernel coding style 文档并没有详细说明 C90 与 C99 的使用。
它建议对“在某些特殊情况下与标准 C99 类型相同的新类型”使用 typedef,而在大多数情况下不鼓励使用 typedef。请注意,这实际上并不意味着依赖于 C99 标准,因为此类类型定义可以在纯 C90 中定义。
在后面对 typedef 的讨论中,它说:
在某些对用户空间可见的结构中,我们不能 需要 C99 类型,不能使用上面的
u32形式。因此,我们使用__u32和所有与之共享的结构中的类似类型 用户空间。
这意味着内核必须使用用 C90 编写的用户代码。
对 C99 的唯一引用是:
cmets 的 Linux 样式是 C89 "/* ... */" 样式。
不要使用 C99 样式的 "// ..." cmets。
顶级kernel documentation web page将C99标准称为“C编程语言的当前版本”(写的时候可能是正确的;现在的正式版本是C11)。
查看内核源代码,目录树中有 1766 个Makefiles(截至我上次从 git 中检查出来的)。其中,只有 3 个引用 -std=gnu99 gcc 选项,这些是用于工具的,而不是用于主内核本身的(还有 2 个引用 -std=gnu89,这是当前的默认值)。这意味着绝大多数 Linux 内核源代码都被编写为使用使其(大部分)符合带有一些 GNU 特定扩展的 C89/C90 标准的选项进行编译。 其中一些扩展是 C99 功能。
Linux 内核的编码约定主要由 Linus Torvalds 控制。 2012 年 4 月的This message of his 表明了他对(某些)C99 特定功能的个人态度:
On Wed, Apr 11, 2012 at 9:28 PM, Oleg Nesterov <oleg@redhat.com> wrote:
>
> Agreed. But,
>
> error: 'for' loop initial declaration used outside C99 mode
>
> we should change CFLAGS, I guess. BTW, personally I'd like very much
> to use "for (type var; ...")" if this was allowed.
The sad part is that if we allow that, we also get that *other* insane
C99 variable thing - mixing variables and code.
I *like* getting warnings for confused people who start introducing
variables in the middle of blocks of code. That's not well-contained
like the loop variable.
That said, most of the stuff in C99 are extensions that we used long
before C99, so I guess we might as well just add the stupid flag. And
discourage people from mixing declarations and code other ways (sparse
etc).
Linus
Bandrami's answer部分正确地指出 C99 添加的许多功能都在库中。在大多数情况下,库特性与 Linux 内核无关。内核不在“托管”环境中运行,也无法访问大部分 C 标准库;例如,您不能在内核中使用printf(有一个类似的printk 函数用于记录和调试)。但这只是图片的一部分。 C99 添加的许多功能都采用了适当的语言(即 ISO C 标准第 6 节描述的部分),并且至少可能适用于内核源代码。
更新:
RudolfW 指出 this commit,这使得 -std=gnu89 配置(带有 GNU 扩展的 C 89/90)明确。
最终结果:我们或许可以升级到更新的 stdc 模型 最终,但现在较新的型号有些烦人 缺陷,因此传统的“gnu89”模型最终成为 首选。
这是对 gcc 第 5 版中的更改的响应,该更改将默认标准选项从 -std=gnu90 更改为 -std=gnu11(跳过 -std=gnu99)。截至 2020 年 9 月 18 日星期五,linux git 存储库中的顶级 Makefile 仍然指代 -std=gnu89。 (-std=gnu89 和 -std-gnu90 是等价的。)
Marc.2377's answer 引用 a document 这可能更直接相关。它明确表示“内核通常使用 gcc 在-std=gnu89 下编译”。
【讨论】:
截至目前,https://www.kernel.org/doc/html/latest/process/programming-language.html 的文档说:
内核是用C编程语言[c-language]编写的。更多的 准确地说,内核通常在编译时使用 gcc [gcc] 下 -std=gnu89 [gcc-c-dialect-options]:ISO C90 的 GNU 方言(包括一些 C99 特性)。
【讨论】:
在检查为什么内核在 22 年多之后不需要 C99 时偶然发现了这一点。 C99 used 的部分在内核中随处可见,但由 #ifdefs 保护。
无论如何,Linus 和一些 GCC 人员之间的以下discussion(2021 年 9 月)给出了一些相关的上下文,尽管它主要是关于标准规定的 header-includes(如<stdint.h>),而不是关于 C语言特征。
我觉得很遗憾线程逐渐消失,特别是具有固定宽度整数类型的 C99-<stdint.h> 案例对 IMO 非常有帮助。
更一般地说,既然内核也支持由 Clang 构建,那么转向标准(我的意思是 ISO C)基线而不是 effectively 基于 GNU 的基线会很棒。一个超过 20 年的标准应该已经足够 IMO,即使是内核......
【讨论】:
没有真正的答案,因为您的问题做出了错误的假设。 C 语言版本假定存在一个平台,但像 Linux 之类的操作系统内核是平台(或至少是平台的很大一部分),因此它们没有那个意义上的“版本” .
就解析器对语言的定义而言,Linux 是用任何并发的 gcc/icc/etc 编写的。将支持,截至目前为C99。但就像我说的,C90 和 C99 之间的差异是基于内核和库的,所以它们一开始并不真正适用于内核。 (我能想到的唯一例外是匿名函数,内核不使用它。)
您所了解的关于 C 的大部分日常内容实际上都来自库,这取决于内核。因此,当您编写内核时,您实际上处理的设置与编写普通 C 程序时大不相同。
【讨论】:
long long、混合声明和语句、_Bool 等等。而且我不确定您所说的“匿名函数”是什么意思; C90、C99 或 C11 中没有这样的功能。