【问题标题】:Is it possible to compile C89 code on MS Windows?是否可以在 MS Windows 上编译 C89 代码?
【发布时间】:2019-05-22 14:11:07
【问题描述】:

我正在尝试使用一些遗留的 C89 代码,但在构建它时遇到了麻烦。我常用的环境是 Visual Studio,但它似乎只支持 C99,并且一些 C99 功能(例如 stdio 等不一定是恒定的)会破坏代码 - 很多。在我开始篡改代码之前,我想编写一些测试,这样我就不会破坏旧的行为,但可以说,在我可以构建代码之前,我无法测试这些测试。

那么还有什么办法可以在 Windows 上编译 C89 代码吗?

编辑:Steve Summit 已确定 stdio 等从未得到保证;它只是我的遗留代码碰巧依赖的一些编译器的一个特性,以一种相当深入的嵌入方式。所以我的问题转移到是否有任何 Windows C 编译器可用(最好是免费的!)支持该假设的 Windows。或者,我在虚拟机中安装了 Ubuntu,尽管我几乎没有使用它的经验 - Ubuntu 中有这样的编译器吗?

【问题讨论】:

  • 您能否出示您遇到问题的 C89 minimal reproducible example
  • 如果有的话,那应该是相反的——VS 不完全支持 C99,所以它可能无法使用 C99 功能构建代码,但它应该在 C89 代码上坚如磐石。你得到什么构建错误?你确定它被编译为 C 而不是 C++?你确定你有你需要的所有代码吗?
  • MSVC 不是符合 C99 的编译器。它也不完全符合 C89,但它在这方面的偏差很小而且有些模糊。如果在 MSVS(在 C 模式,而不是 C++ 模式)中构建 puported-C89 代码失败或产生行为异常的可执行文件,那么很有可能是程序坏了,而不是编译器。
  • "比如stdio等不一定是恒定的"阙?
  • 好消息:微软比市场上所有其他 C 编译器落后 20 年。他们仍然只部分支持 C99。他们的 C 编译器大多遵循 C90。坏消息:Visual C 不符合任何 C 标准。它被认为是一个 C++ 编译器,对 C 的支持有些草率,部分支持。

标签: c windows c89


【解决方案1】:

MSVC 是一个 C++ 编译器,最近刚刚获得 C99 支持。以前它只支持带有一些 MS 扩展的 C89。要在严格的 C89 模式下编译,请使用 /Za 选项。确保还启用 /Tc 以使用 C 模式

/Za, /Ze (Disable Language Extensions)

/Za 编译器选项会禁用与 ANSI C89/ISO C90 不兼容的 Microsoft 对 C 的扩展并发出错误。已弃用的 /Ze 编译器选项启用 Microsoft 扩展。默认情况下启用 Microsoft 扩展。

Enforce ANSI C Standard in Visual Studio 2015

大多数其他编译器使用其他选项,例如 -ansi, -std=c90 or -std=iso9899:1990


但是,如果这只是在静态初始化列表中使用时 stdin/stdout 不恒定,那么它与 C89 完全无关,实际上是 XY problem。以下sn-p在VS2019 C++模式下编译没有问题,所以如果你没有任何可能的冲突,只需在C++模式下编译代码

#include <stdio.h>
FILE* ifp = stdout;
int main()
{
    fprintf(ifp, "test\n");
    return 0;
}

否则很容易通过将初始化移动到main()来修复以C模式编译的问题

FILE* ifp = NULL;
int main()
{
    ifp = stdout;
    fprintf(ifp, "test\n");
    return 0;
}

【讨论】:

  • 我看不出它有什么问题,但它并没有解决我的问题,因为标准流是恒定的假设贯穿于遗留代码中,并且很难解开。
  • @phuclv 是否有 Visual Studio 在 C99 中支持的 C99 扩展列表?
【解决方案2】:

[这不是一个真正的答案,但它过于详尽,无法发表评论。]

如果你的代码可以做类似的事情

#include <stdio.h>
FILE *ifp = stdin;
int main() { ... }

如果您遇到的问题是错误指出 stdin 不是适合静态初始化程序的编译时常量,我认为您将不得不重写代码的这方面。我可能是错的,但如果我没记错的话,stdin 等人的想法。编译时常量从来都不是保证,只是最早的 Unix 实现的一个有用属性。并非所有旧实现都是如此,因此明确表示它们不一定是不变的标准的“更改”并不是更改本身,而是或多或少编纂现有实践的分歧。

(换句话说,如果您有一个拒绝代码的编译器,并且即使它具有向后兼容模式,如果向后兼容模式将 stdin 转换为编译器,我也会感到惊讶-时间常数。)

【讨论】:

  • 无法保证 stdin 在任何版本的 C 中都是编译时常量,并且自 C90 以来它没有改变。标准只是说它的类型是FILE*
  • 这正是我遇到的主要问题 - 很多次,跨越多个文件并隐藏在数据结构中,所以重写可能不是一个好主意 - 我没有什么可以测试重写.看来我需要找到一个支持该假设的编译器。
  • @digitig:某些平台可能会使用与FILE* 很好映射的数据结构进行文件处理,但在程序执行之前无法确定stdin 的位置。虽然针对此类平台的实现可以使FILE* 成为实现内部类型的包装器,但这样做意味着使用该实现编译的模块将与使用其他实现编译的模块不兼容。出于某些目的,这可能是值得的权衡,但不是我特别希望实现支持的。
【解决方案3】:

所有受支持(甚至更早)的 Visual Studio 版本都完全能够编译 C89 代码。此外,C99 向后兼容该语言的先前版本,因此 C99 编译器应该能够编译出恰到好处的 C89 代码。

虽然您可能会收到一些警告,但如果代码是可移植的,那么代码应该可以编译并正常工作。

【讨论】:

  • “完全有能力”->“有点能力,也许”。但是,嘿,我们也支持 gcc。
  • 替代 Windows 编译器的更好选择是 clang,因为它与 MS 库的二进制兼容性。 :) 另外我还没有遇到 MS 编译器无法编译的 C89 可移植代码。
猜你喜欢
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-28
  • 2012-03-14
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
相关资源
最近更新 更多