用Visual C / C ++ 2005/2008编写的程序可能无法使用其他编译器(如GNU C / C ++)编译,反之亦然。例如,当尝试重用使用windows.h的代码时,为另一个特定的编译器编写代码,需要注意哪些差异?
是否有任何关于如何生成与一个编译器或另一个编译器兼容的代码的信息,例如:使用GC / C ++还是MSVC / C ++?试图这样做的原因是什么?
其他编译器如LCC和Digital Mars呢?
答案 0 :(得分:7)
尝试将为MSVC编写的代码编译到其他编译器时要做的第一件事是在关闭Microsoft扩展的情况下编译它。 (我认为使用/ Za标志)。这会吸引很多GCC和其他编译器会抱怨的事情。
下一步是确保特定于Windows的API(MFC,Win32等)在Windows特定文件中被隔离,从而有效地将您的代码分成“通用”和“特定于Windows”的模块。
答案 1 :(得分:5)
请记住,如果您希望您的网页在不同的浏览器上运行,那么您应该编写符合标准的HTML吗?
编译器也一样。
在语言层面,如果您的代码在GCC上没有警告而使用-std = c89(或-std = c ++ 98 for C ++)编译,-pedantic -Wall,加上-Wextra如果你感觉很勇敢,只要你没有使用-pedantic允许的任何更明显的GNU扩展(这很难意外),那么它很有可能在大多数C89编译器上工作。 C ++不太确定,因为您可能依赖于目标编译器对标准的支持程度。
编写正确的C89有点限制(没有//注释,声明必须在块中的语句之前,没有内联关键字,没有stdint.h,因此没有64位类型等),但是一旦你习惯了它就不会太糟糕了它。如果你关心的只是GCC和MSVC,你可以打开一些你知道MSVC的语言功能。否则,您可以编写自己的“语言抽象”标题。例如,在GCC和MSVC / C ++上将“内联”定义为“内联”,但在MSVC / C中定义为“__inline”。或者MSVC stdint.h很容易找到或写入。
我过去曾成功编写过可移植代码 - 我主要使用GCC在一个特定产品的平台上工作。我还编写了可在所有平台上使用的代码,包括Windows XP和Mobile。在构建服务器上运行“测试构建”之前,我从未为这些平台编译过它,而且我很少遇到任何问题。我想我可能编写了错误的代码,触发了一次或两次64位兼容性警告。
Windows程序员走向另一个方向导致了偶尔的问题,主要是因为他们的编译器不像我们那样迂腐,所以我们看到他们没有警告,而不是GCC根本不支持的事情。但修复警告意味着当代码稍后在具有更原始编译器的系统上使用时,它仍然有效。
在图书馆一级,这要困难得多。如果#include并通过windows.h使用Windows API,那么显然它不适用于linux,如果你使用KDE和GCC然后尝试使用MSVC进行编译也是如此。
严格来说,这是一个平台问题,而不是编译器问题,但它相同。如果你想编写可移植代码,你需要一个OS抽象API,比如所有目标支持的POSIX(或其子集),并且当你首先编写它时,你需要考虑“可移植”。使用大量使用特定于Windows的API的代码,并尝试使其在GCC / linux上运行,基本上是一个完整的重写AFIAK。使用WINE可能比尝试重新编译它更好。
答案 2 :(得分:5)
你正在混淆“编译器”和“操作系统”。 < WINDOWS.H>不是MSVC C编译器带来的东西:它是Windows API的C特定实现。您可以从Visual Studio中独立获取它。 Windows上的任何其他C编译器都可能提供它。例如,在Linux方面,你有< unistd.h>,< pthereads.h>和别的。它们不是GCC的重要组成部分,任何其他编译Linux的编译器都会提供它们。
所以你需要回答两个不同的问题:如何以任何编译器接受它的方式编写C语言?如何隐藏我对OS的依赖?
答案 3 :(得分: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's can be assigned to anything和临时变量传递给引用参数。两者都无法编译(谢天谢地!)在gcc下,但需要返工。
g)奇怪的是,我们有模板代码试图明确地专门化类模板函数。不允许。再次gcc拒绝,VS 2005让它走了。一旦理解了问题,就足够容易重新定期进行超载。
h)在VS 2005下,std :: exception允许用字符串构造。不允许使用gcc或标准。重新编写代码,以便使用其中一个派生的异常类。
希望这是您正在寻找的那种信息!
答案 4 :(得分:4)
这是一个非常困难的问题。事实是,MSVC不支持最新版本 C标准,关于它的c ++兼容性我可以告诉你任何东西。强大的“windows”C是MSVC和gcc所理解的,你不能指望其他方式。例如,如果您使用ANSI C99功能,那么您可能很难从gcc“移植”到MSVC。
但只要你尝试MSVC->的方式; gcc你的机会会更好。您必须注意的唯一一点是库。 Windows上的大多数库都应该与MSVC一起使用,因此您需要一些额外的工具来使它们也可以被gcc访问。
LCC是一个相当老的系统,AFAIKT不支持ANSI C99,它还需要MSVC的工具才能正常工作。 LCC“只是”一个编译器。
lcc-win32是一个致力于符合ANSI C99标准的C开发系统。它伴随着链接器,IDE等。
我无法分辨数字火星实施的状态
然后还有Pelles-C,它也是一个完全成熟的IDE。
我们在OpenWatcom上闲逛。曾经是一个相当不错的系统,但我不知道它是多么符合。
总而言之,您可以从MSVC更简单的方式获得“最佳” - >其他系统,但反过来可能会更糟。
此致 弗里德里希
答案 5 :(得分:1)
用Visual C / C ++ 2005/2008编写的程序可能无法使用其他编译器(如GNU C / C ++)编译,反之亦然。
如果你(1)在一个编译器中使用某种扩展而不是另一个编译器(C ++标准,例如在一些地方需要typename
和template
关键字,那么这是真的。许多编译器 - 包括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 ++都在这个标准中实现了更简单的东西。
答案 6 :(得分:1)
vs2008比2005更符合标准。
我遇到了更多问题,尤其是gcc的'feature',它允许你在运行时分配一个可变大小的数组“int array [variable]”,这只是纯粹的邪恶。