3

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

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

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

4

7 回答 7

7

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

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

于 2008-11-17T10:25:42.243 回答
5

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

编译器也是如此。

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

编写正确的 C89 有点限制( // 没有注释,声明必须在块中的语句之前,没有 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 可能比尝试重新编译它更好。

于 2008-11-17T16:02:27.523 回答
5

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

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

于 2008-11-17T17:09:10.743 回答
5

正如您从不同的答案中可以看出的那样,这个主题相当复杂。请记住,这是我最近将一些代码移植到三个平台(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 可以分配给任何东西,并且允许将临时变量传递给引用参数。两者都无法在 gcc 下编译(谢天谢地!),但需要返工。

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

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

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

于 2008-11-18T07:16:50.563 回答
4

嗯,这是一个相当困难的问题。事实上,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 等一起提供。

我无法了解 Digital Mars 的实施状态

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

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

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

问候弗里德里希

于 2008-11-17T09:31:19.233 回答
1

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

如果您 (1) 在一个编译器中使用某种可用的扩展而不在另一个编译器中使用某种扩展(例如,C++ 标准在一些地方需要typenameandtemplate关键字,但许多编译器 - 包括 Visual C++ 不强制执行此操作,则这是正确的; gcc 过去也不强制执行此操作,但在 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++ 都在该标准中实现了更简单的东西。

于 2008-11-17T19:16:37.040 回答
1

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

于 2008-12-12T17:45:29.900 回答