C89/C90、C99 和 C11 的兼容性

Compatibility of C89/C90, C99 and C11

我刚刚阅读: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. 如何'port'旧代码到新版本?是否有解释此过程的文件?

  2. C89好还是C99好还是C11好?

提前感谢您的帮助。

编辑:将 ISO C 更改为 C89。

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

如果没有,您可以将不同的.c 文件编译成不同的.o 文件,使用不同的标准,然后link 将它们放在一起。确实有效。

通常,您应该使用适用于新代码的最新标准,并且如果容易的话,修复新标准确实破坏的代码,而不是使用上面的 hacky 解决方案。

编辑:除非你正在处理潜在的未定义行为。

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

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

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

C11 wikipedia article 详细描述了它与 C99 的区别。

Are the newer versions of C i.e. C99, C11 supersets of older C versions?

有很多差异,有大有小。大多数更改是添加新功能和库。 C99 和 C11 不是 C90 的超集,尽管为确保向后兼容性做出了大量努力。然而,C11 主要是 C99 的超集。

从 C90 移植时,旧代码可能会中断,以防代码编写不当。特别是各种形式的 "implicit int" 和隐式函数声明在 C99 语言中被禁止。 C11 禁止了 gets 函数。

可以在 pdf 的 C11 草案第 13 页中找到完整的更改列表,其中 "the third edition" 指的是 C11,"the second edition" 指的是 C99。

How to 'port' old code to the new versions? Is there a document which explains this procedure?

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

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

Is it better to use C89 or C99 or C11?

最好使用 C11,因为这是当前的标准。 C99 和 C11 都包含各种 "language bug fixes" 并引入了新的有用功能。

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

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

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

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