【问题标题】:Compatibility of C89/C90, C99 and C11C89/C90、C99 和 C11 的兼容性
【发布时间】:2017-05-23 00:00:36
【问题描述】:

我刚刚读到:C Wikipedia entry。据我所知,有 3 个不同版本的 C 被广泛使用:C89、C99 和 C11。我的问题是关于不同版本源代码的兼容性。 假设我要编写一个程序(在 C11 中,因为它是最新版本)并导入一个用 C89 编写的库。根据 C11 规范编译所有文件时,这两个版本能否正常协同工作?

问题 1: 新版本的 C 即 C99、C11 是旧 C 版本的超集吗?我所说的超集是指旧代码在根据较新的 C 规范编译时将无错误地编译,并且具有相同的含义。

我刚刚读到, // 在 C89 和 C99 中具有不同的含义。除了这个特性,C99 和 C11 是 C89 的超集吗?

如果问题 1 的答案是否定的,那么我还有 2 个问题。

  1. 如何将旧代码“移植”到新版本?是否有解释此程序的文件?

  2. 使用 C89 还是 C99 还是 C11 更好?

提前感谢您的帮助。

编辑:将 ISO C 更改为 C89。

【问题讨论】:

  • 您一直在说 ISO C,但我认为您的意思是 ANSI C(或 C89 或 C90;所有这三个名称都指同一种语言)。 ISO C 本身并没有任何意义(重要的是要注意 C99 和 C11 都是由 ISO 语言体定义的)。
  • @Cornstalks 从技术上讲,每个 ISO C 标准都取代了其前身,而 ANSI 采用 ISO C 语言标准,因此“ANSI C”也意味着 C11。 (但大多数人不会那样使用它。)
  • github.com/mauke/poly.poly/blob/master/poly.poly 可以区分 C89 和 C99(通过各自编译不同的语义),所以 Q1 的答案是“否”。
  • (假设你在回复我)@user3528438:I said colloquially。当然 ANSI 和 ISO 官方将最新的标准指定为 C 语言的官方含义。
  • 至于“ISO C”是什么意思,就是现在的版本,C11。 C99 和 C90 已被 ISO 撤销,就 ISO 而言不应使用。

标签: c c99 iso c11 c89


【解决方案1】:

一般来说,新版本的标准是向后兼容的。

如果没有,您可以使用不同的标准将不同的 .c 文件编译为不同的 .o 文件,并将它们链接在一起。这确实有效。

一般来说,您应该使用可用于新代码的最新标准,如果容易的话,修复新标准确实破坏的代码,而不是使用上面的 hacky 解决方案。

编辑:除非您正在处理可能未定义的行为。

【讨论】:

  • 标准中有一些语义上的变化,导致一些使用的结构具有定义的行为(例如,在目标没有声明类型的情况下,memcpymemmove 用于类型双关语的某些用途,但将使用没有陷阱表示的类型读取)来调用未定义的行为。编译时对不同标准版本的规范可能不足以实现正确的行为,但是,如果编译器假装这些行为从未定义过,尽管旧标准中缺乏任何东西来证明这种信念是正确的。
【解决方案2】:

新版本的 C 绝对不是旧版本的严格超集。

一般来说,这种问题只有在升级编译器或切换编译器供应商时才会出现。您必须计划对代码进行大量的小改动来处理此事件。很多时候,新编译器会捕获旧编译器未诊断出的问题,以及强制执行较新的 C 标准可能发生的轻微不兼容性。

如果可以确定,最好使用的标准是编译器支持的最好的标准。

C11 wikipedia article 对它与 C99 的区别进行了冗长的描述。

【讨论】:

    【解决方案3】:

    C 的新版本(即 C99、C11)是旧 C 版本的超集吗?

    有很多不同之处,既有大的,也有细微的。大多数更改是添加新功能和库。 C99 和 C11 不是 C90 的超集,尽管为确保向后兼容做了很多努力。然而,C11 主要是 C99 的超集。

    从 C90 移植时,如果代码写得不好,旧代码可能会中断。特别是各种形式的“隐式 int”和隐式函数声明在 C99 语言中被禁止。 C11 禁止gets 功能。

    完整的更改列表可以在pdf 的 C11 草稿第 13 页中找到,其中“第三版”指的是 C11,“第二版”指的是 C99。

    如何将旧代码“移植”到新版本?是否有解释此程序的文件?

    我不知道有任何此类文件。如果你有好的代码,移植很容易。如果你有烂代码,移植会很痛苦。至于实际的移植过程,如果你了解 C99 和 C11 的基础知识就很容易了,所以最好的办法是找到一个可靠的 C99/C11 学习源。

    从 C99 移植到 C11 应该毫不费力。

    使用 C89 还是 C99 还是 C11 更好?

    最好使用 C11,因为这是当前的标准。 C99 和 C11 都包含各种“语言错误修复”并引入了新的有用功能。

    【讨论】:

    • 感谢您的帮助。我还有一个问题:您说使用C11更好。然后我读到:stackoverflow.com/questions/20600497/…为什么Linux内核使用C89的GNU方言?
    • @MichaelS 我认为那是因为 Linux 是在 90 年代后期制造的,当时 C99 和 C11 都不存在。话虽如此,Linux 内核是一个非常混乱的代码库,充满了非标准的 gcc 扩展,以至于该代码永远被 gcc 卡住了。为什么他们以某种方式做事,我不知道,但我会在别处寻找灵感,因为 Linux 内核代码库与你所获得的规范差不多。同样,Linux 内核代码风格指南也不是专业的编码标准。
    • 感谢您的回答和帮助!很抱歉,由于我没有足够的声誉,因此我无法支持您的评论和回答。
    【解决方案4】:

    在大多数情况下,较新的版本是较早版本的超集。虽然尝试使用 restrict 作为标识符的 C89 代码将被 C99 添加的具有相同拼写的保留字破坏,并且在某些情况下,使用解析器来利用某些极端情况的代码将被破坏两种语言的处理方式不同,其中大部分不太可能是重要的。

    然而,一个更重要的问题与内存别名有关。 C89包括 限制可用于访问某些指针类型的规则 对象。因为如果规则会使 malloc() 之类的函数变得无用 他们按照所写的方式应用于由此创建的对象,大多数程序员和 编译器编写者都将规则视为仅适用于有限的情况(如果人们相信规则仅适用于狭隘的情况,我怀疑 C89 是否会被广泛接受)。 C99 声称“澄清”了规则,但它的新规则在效果上比对旧规则的同时解释要广泛得多,破坏了许多在 C89 的常见解释下定义行为的代码,甚至一些代码会在 C89 下明确定义,但没有实际的 C99 等效项。

    例如,在 C89 中,memcpy 可用于将与任何类型的对象关联的位模式复制到具有相同大小的任何其他类型的对象中,只要该位模式表示有效目标类型中的值。如果memcpy 用于将某种类型 T 的对象复制到没有声明类型的存储(例如从malloc 返回的存储),则 C99 添加的语言允许编译器以任意方式运行,然后该存储被读取为与 T 不兼容别名的类型——即使原始对象的位模式在新类型中具有有效含义。此外,适用于 memcpy 的规则也适用于将对象复制为字符类型数组的情况——没有明确说明这意味着什么——因此不清楚究竟需要做什么代码才能实现与 C89 匹配的行为memcpy.

    在许多编译器上,此类问题可以通过在命令行中添加-fno-strict-aliasing 选项来解决。请注意,指定 C89 模式可能不够,因为编译器编写者通常使用相同的内存语义,而不管他们应该实现哪个标准。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 2020-07-22
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      相关资源
      最近更新 更多