【问题标题】:Which C version is used in the Linux kernel?Linux内核中使用的是哪个C版本?
【发布时间】:2013-12-15 22:11:37
【问题描述】:

Linux 内核是仅使用旧的 C90 语法还是已针对 C99 / C11 特性进行了优化?

我想知道是否尽可能使用最新版本的 C。

【问题讨论】:

    标签: linux-kernel


    【解决方案1】:

    请参阅此答案的底部以获取更新。

    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 下编译”。

    【讨论】:

    • 另请参阅this commit - 他们现在明确使用带有 GNU 扩展的 C90,因为立即过渡到 C99/C11 可能不会产生完全可靠的结果。
    • 这个答案似乎不是最新的。请参阅 Marc 的回答 stackoverflow.com/a/58313785/9305398
    • @Acorn 怎么不是最新的? (我在您发表评论之后但在我看到它之前编辑了最后一段,但我相信它已经是最新且正确的。Marc 的回答确实添加了指向我以前从未见过的文档的链接。
    • @KeithThompson 答案开始链接一个并不真正相关的文档(样式指南),然后继续尝试从 Makefile、提交和电子邮件中推断出答案。该信息是一个很好的分析,但如果记录了某些内容,则应参考该信息,而不是实施细节或尝试从其他信息来源推断事物。
    • @KeithThompson 它已经过时了,因为该文档似乎是新的,所以这个答案之前还可以。
    【解决方案2】:

    截至目前,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 特性)。

    【讨论】:

      【解决方案3】:

      在检查为什么内核在 22 年多之后不需要 C99 时偶然发现了这一点。 C99 used 的部分在内核中随处可见,但由 #ifdefs 保护。

      无论如何,Linus 和一些 GCC 人员之间的以下discussion(2021 年 9 月)给出了一些相关的上下文,尽管它主要是关于标准规定的 header-includes(如&lt;stdint.h&gt;),而不是关于 C语言特征。

      我觉得很遗憾线程逐渐消失,特别是具有固定宽度整数类型的 C99-&lt;stdint.h&gt; 案例对 IMO 非常有帮助。

      更一般地说,既然内核也支持由 Clang 构建,那么转向标准(我的意思是 ISO C)基线而不是 effectively 基于 GNU 的基线会很棒。一个超过 20 年的标准应该已经足够 IMO,即使是内核......

      【讨论】:

        【解决方案4】:

        没有真正的答案,因为您的问题做出了错误的假设。 C 语言版本假定存在一个平台,但像 Linux 之类的操作系统内核平台(或至少是平台的很大一部分),因此它们没有那个意义上的“版本” .

        就解析器对语言的定义而言,Linux 是用任何并发的 gcc/icc/etc 编写的。将支持,截至目前为C99。但就像我说的,C90 和 C99 之间的差异是基于内核和库的,所以它们一开始并不真正适用于内核。 (我能想到的唯一例外是匿名函数,内核不使用它。)

        您所了解的关于 C 的大部分日常内容实际上都来自库,这取决于内核。因此,当您编写内核时,您实际上处理的设置与编写普通 C 程序时大不相同。

        【讨论】:

        • 这是不正确的。 C90 和 C99 之间有许多语言变化,例如可变长度数组、long long、混合声明和语句、_Bool 等等。而且我不确定您所说的“匿名函数”是什么意思; C90、C99 或 C11 中没有这样的功能。
        • @Keith 你能回答我的问题吗?
        • @Keith,内核必须自己进行输入,因为所有这些“语言”功能都是在库中实现的,而不是在编译器中(有时检查源代码树中的 typedef)。而且,是的,我想到的匿名函数是 gcc 扩展;哎呀。
        • 我提到的所有功能都没有在库中实现。它们都不是 typedef。
        • 这是错误的和误导性的。 C90 和 C99 之间存在许多与标准库无关的差异。此外,该标准不依赖于“平台”。它描述了语法和抽象语义。 Linux 是用 C99 编写的也不是真的,因为它依赖于相当多的非标准 GNU 扩展。
        猜你喜欢
        • 1970-01-01
        • 2019-10-11
        • 2023-03-27
        • 2017-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-17
        相关资源
        最近更新 更多