Windows 上的 C 编译器之间的实际区别是啥?

Posted

技术标签:

【中文标题】Windows 上的 C 编译器之间的实际区别是啥?【英文标题】:What are the practical differences between C compilers on Windows?Windows 上的 C 编译器之间的实际区别是什么? 【发布时间】:2008-11-17 09:23:05 【问题描述】:

使用 Visual C/C++ 2005/2008 编写的程序可能无法使用其他编译器(例如 GNU C/C++)编译,反之亦然。例如,当尝试重用为特定编译器编写的使用 windows.h 的代码时,需要注意哪些差异?

是否有任何关于如何生成与一种编译器或另一种编译器兼容的代码的信息,例如使用 GC/C++ 还是 MSVC/C++?尝试这样做会导致什么问题?

其他编译器呢,例如 LCC 和 Digital Mars?

【问题讨论】:

【参考方案1】:

当尝试将 MSVC 编写的代码编译到其他编译器时,首先要做的是在关闭 Microsoft 扩展的情况下对其进行编译。 (我认为使用 /Za 标志)。这会消除 GCC 和其他编译器会抱怨的很多东西。

下一步是确保特定于 Windows 的 API(MFC、Win32 等)在特定于 Windows 的文件中隔离,从而有效地将您的代码划分为“通用”和“特定于 Windows”的模块。

【讨论】:

【参考方案2】:

还记得如果您希望您的网页在不同的浏览器上工作,那么您应该编写符合标准的 html 吗?

编译器也是如此。

在语言级别,如果您的代码在 GCC 上使用 -std=c89(或对于 C++ 的 -std=c++98)、-pedantic -Wall 以及 -Wextra (如果您觉得勇敢的话)编译时没有警告,并且只要您没有使用 -pedantic 允许的任何更明显的 GNU 扩展(这很难意外地做到),那么它很有可能在大多数 C89 编译器上工作。 C++ 不太确定,因为您可能依赖于目标编译器对该标准的支持程度。

编写正确的 C89 有一定的限制(没有 // cmets,声明必须在块中的语句之前,没有 inline 关键字,没有 stdint.h,因此没有 64 位类型等),但是一旦你习惯了它并不算太糟糕它。如果你只关心 GCC 和 MSVC,你可以打开一些你知道 MSVC 有的语言特性。否则,您可以编写自己的小“语言抽象”标题。例如,在 GCC 和 MSVC/C++ 上将“inline”定义为“inline”,而在 MSVC/C 上定义为“__inline”。或者 MSVC stdint.h 很容易找到或编写。

我过去曾成功编写过可移植代码 - 我主要在一个平台上使用 GCC 为特定产品工作。我还编写了适用于所有平台的代码,包括 Windows XP 和 Mobile。在构建服务器上运行“测试构建”之前,我从未为这些平台编译过它,而且我很少遇到任何问题。我想我可能编写了错误的代码,触发了一次或两次 64 位兼容性警告。

Windows 程序员反其道而行之,偶尔会出现问题,主要是因为他们的编译器不像我们的那样迂腐,所以我们看到了他们没有看到的警告,而不是 GCC 根本不支持的东西。但是修复警告意味着当代码后来在具有更原始编译器的系统上使用时,它仍然可以工作。

在图书馆层面,这要困难得多。如果你#include 并通过 windows.h 使用 Windows API,那么显然它不会在 linux 上工作,如果你使用 KDE 和 GCC,然后尝试使用 MSVC 编译,情况也是如此。

严格来说,这是一个平台问题,而不是编译器问题,但它相当于同一件事。如果你想编写可移植的代码,你需要一个操作系统抽象 API,比如你的所有目标都支持的 POSIX(或其子集),并且你需要在编写它时考虑“可移植”。采用大量使用特定于 Windows 的 API 的代码,并试图让它在 GCC/linux 上工作,基本上是对 AFIAK 的完全重写。与尝试重新编译相比,使用 WINE 可能会更好。

【讨论】:

【参考方案3】:

您混淆了“编译器”和“操作系统”。 不是 MSVC C 编译器带来的东西:它是 Windows API 的 C 特定体现。您可以从 Visual Studio 中独立获得它。 Windows 上的任何其他 C 编译器都可能提供它。例如,在 Linux 端,您有 等。它们不是 GCC 的重要组成部分,任何其他为 Linux 编译的编译器都会提供它们。

因此,您需要回答两个不同的问题:如何以任何编译器都接受的方式对 C 进行编码?以及如何隐藏我对操作系统的依赖?

【讨论】:

【参考方案4】:

从不同的答案中可以看出,这个主题相当复杂。请记住,这是我最近将一些代码移植到三个平台(msvc 8/Windows、gcc 4.2/Linux、gcc 3.4/嵌入式 ARM9 处理器)时遇到的一些问题。它最初只能在 Visual Studio 2005 下编译。

a) 在 Windows 平台上编写的许多代码都使用 windows.h 中定义的类型。我必须创建一个“windows_types.h”文件,其中包含以下内容:

#ifndef _WIN32
    typedef short              INT16;
    typedef unsigned short     UINT16;
    typedef int                INT32;
    typedef unsigned int       UINT32;
    typedef unsigned char      UCHAR;
    typedef unsigned long long UINT64;
    typedef long long          INT64;
    typedef unsigned char      BYTE;
    typedef unsigned short     WORD;
    typedef unsigned long      DWORD;
    typedef void *             HANDLE;
    typedef long               LONG;
#endif

丑陋,但比修改以前仅针对 Windows 的代码要容易得多。

b) 在模板代码中不需要 typename 关键字来声明类型。 MSVC 在这方面很松懈(尽管我假设某些编译器开关会产生警告)。不得不在很多地方添加它。

c) 简单,但耗时:Windows 不区分大小写,许多#included 文件的大小写不正确会导致在 Linux 下出现问题。

d) 有相当多的代码使用 Windows API 来做很多事情。例如 CRITICAL_SECTIONS 和 INTERLOCKED_INCREMENT。我们尽可能使用 boost 库来解决这些问题,但重新编写代码非常耗时。

e) 很多代码依赖于包含在预编译头文件中的头文件。我们在 gcc3.4 上使用 pch 时遇到了问题,因此我们必须确保所有 .h/cpp 文件正确地包含它们的所有依赖项(因为它们应该首先具有)。

f) VS 2005 有两个讨厌的错误。允许将auto_ptr's can be assigned to anything 和临时变量传递给引用参数。两者都无法在 gcc 下编译(谢天谢地!),但需要返工。

g) 奇怪的是,我们的模板代码试图明确地专门化 class 模板函数。不允许。 gcc 再次拒绝,VS 2005 放手了。一旦理解了问题,就很容易将其返工为常规重载。

h) 在 VS 2005 下,允许使用字符串构造 std::exception。在 gcc 或标准下不允许。重新编写代码以更喜欢使用派生异常类之一。

希望这就是您正在寻找的信息!

【讨论】:

很棒的清单。你提到的每一个我都观察过了。【参考方案5】:

嗯,这是一个相当困难的问题。事实是 MSVC 不支持最新的 C 标准,关于它的 c++ 合规性,我可以告诉你任何事情。但是,MSVC 和 gcc 都可以理解“windows”C,您只是不能指望另一种方式。例如,如果您使用 ANSI C99 功能,那么您可能很难从 gcc“移植”到 MSVC。

但只要你尝试 MSVC-> gcc 的方式,你的机会会更好。您唯一需要注意的是库。 Windows 上的大多数库都应该与 MSVC 一起使用,因此您需要一些额外的工具来使 gcc 也可以访问它们。

LCC 是一个相当老的系统,AFAIKT 不太支持 ANSI C99,它还需要 MSVC 的工具才能正常工作。 LCC“只是”一个编译器。

lcc-win32 是一个 C 开发系统,力求与 ANSI C99 兼容。它与链接器、IDE 等一起提供。

我不知道数字火星的实施状态

还有 Pelles-C,它也是一个成熟的 IDE。

我们在 OpenWatcom 附近闲逛。这曾经是一个相当不错的系统,但我不知道它的一致性如何。

总而言之,您可以希望从 MSVC -> 其他系统中获得更简单的方法,但反过来可能会更糟。

问候 弗里德里希

【讨论】:

【参考方案6】:

vs2008 比 2005 更符合标准。 我遇到了更多的问题,尤其是 gcc 的“功能”,它可以让你在运行时分配一个可变大小的数组“int array[variable]”,这只是纯粹的邪恶。

【讨论】:

gcc 在成为标准之前确实允许它。 IIRC 它还允许在 C++ 代码中使用它【参考方案7】:

使用 Visual C/C++ 2005/2008 编写的程序可能无法使用其他编译器(例如 GNU C/C++)编译,反之亦然。

如果您 (1) 在一个编译器中使用某种可用的扩展而不在另一个编译器中使用某种扩展(例如 C++ 标准,在一些地方但在许多​​编译器中需要 typenametemplate 关键字,则这是正确的——包括 Visual C++ 不强制执行此操作;gcc 过去也不强制执行此操作,但 changed in 3.4) 或 (2) 使用在一个编译器而不是另一个编译器上实现的一些标准兼容行为(现在这个海报男孩是导出模板,但只有一两个编译器支持这一点,Visual C++ 和 gcc 不在该组中)。

例如,当尝试重用代码时,该代码使用 windows.h,为特定编译器编写的另一个编译器,

我从未见过这样做有什么问题。我在 gcc 中看到了使用 Microsoft 的 windows.h 的问题。但是当我在 gcc 中使用 gcc 的 windows.h 和在 Visual C++ 中使用 Microsoft 的 windows.h 时,我可以访问所有记录在案的函数。毕竟这就是“实现的 windows.h”的定义。

需要注意哪些差异?

我看到的主要是人们不知道上面提到的依赖 template/typename 的事情。有趣的是,许多人认为 gcc 不够聪明,无法做到 Visual C++ 所做的事情,而实际上 gcc 首先拥有该功能,然后以符合标准的名义决定将其删除。

在不久的将来,您将在使用 C++0x 功能时遇到问题。但是 gcc 和 Visual C++ 都在该标准中实现了更简单的东西。

【讨论】:

以上是关于Windows 上的 C 编译器之间的实际区别是啥?的主要内容,如果未能解决你的问题,请参考以下文章

gcc 和VC++有啥区别呢,VC++编译时用的编译器 相当于gcc的是啥东西

在块内,__block 变量和静态变量之间的实际区别是啥?

编译器和转译器之间的主要区别是啥?

Apache Tajo 和 Apache hive 之间的实际区别是啥

redux 和状态机(例如 xstate)之间的实际区别是啥?

Windows Azure 和 Windows IIS 之间的确切区别是啥?