代码之家  ›  专栏  ›  技术社区  ›  Rob Kam Bayard Randel

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

  •  3
  • Rob Kam Bayard Randel  · 技术社区  · 16 年前

    用VisualC/C++2005/2008编写的程序可能无法使用其他编译器(如GNUC/C++)进行编译,反之亦然。例如,当尝试重用使用windows.h的代码时,需要注意的区别是什么?

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

    7 回复  |  直到 16 年前
        1
  •  7
  •   JesperE    16 年前

    当试图将为MSVC编写的代码编译到其他编译器时,首先要做的是在关闭Microsoft扩展的情况下编译它。(我想使用/Za标志)。这将引出GCC和其他编译器会抱怨的许多事情。

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

        2
  •  5
  •   Steve Jessop    16 年前

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

    编译器也是如此。

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

    编写正确的C89有一定的限制性(块中的语句前面不能有//注释、声明、内联关键字、stdint.h,因此也不能有64位类型等等),但一旦习惯了就不太糟糕了。如果您只关心GCC和MSVC,那么您可以打开一些您知道MSVC具有的语言特性。否则,您可以编写自己的“语言抽象”标题。例如,在GCC和MSVC/C++中,将“inline”定义为“inline”,但在MSVC/C或MSVC stdint.h中,将“inline”定义为“inline”是很容易找到或编写的。

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

    在图书馆层面,这要困难得多。如果您通过Windows.h包含并使用Windows API,那么显然它在linux上不起作用,如果您将KDE与GCC一起使用,然后尝试使用MSVC进行编译,也是如此。

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

        3
  •  5
  •   Steve Jessop    16 年前

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

        4
  •  5
  •   Community CDub    8 年前

    从不同的答案中可以看出,这个话题相当复杂。考虑到这一点,我最近将一些代码移植到三个平台(msvc 8/Windows、gcc 4.2/Linux、gcc 3.4/embedded ARM9处理器)时遇到了一些问题。它最初只是在VisualStudio2005下编译的。

    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在这方面是宽松的(尽管我认为某些编译器开关会产生警告)。有很多地方需要补充。

    d) 有相当多的代码在许多方面使用Windows API。一个例子是临界_段和联锁_增量。我们尽可能多地使用boost库来替换这些问题,但是修改代码非常耗时。

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

    auto_ptr's can be assigned to anything

    g) 奇怪的是,我们的模板代码试图明确地专门化 模板函数。不允许。gcc再次拒绝,VS 2005放弃。一旦问题被理解,就可以很容易地重新编写成常规重载。

    h) 在VS2005下,允许使用字符串构造std::exception。根据gcc或本标准不允许。重新编写代码,以便更喜欢使用一个派生的异常类。

        5
  •  4
  •   Friedrich    16 年前

    这是一个相当困难的问题。事实上,MSVC不支持最新版本 C标准,关于C++遵从性我可以告诉你任何事情。然而,MSVC和gcc都能理解服务器“windows”C,你不能指望其他方式。例如,如果您使用ANSI C99功能,那么您可能很难从gcc“移植”到MSVC。

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

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

    lcc-win32是一个致力于符合ANSI C99标准的C开发系统。它与链接器、IDE等一起提供。

    我说不出数字火星的实施情况

    总而言之,您可以从MSVC获得更简单的方法,这是“最好的”>但反过来可能会更糟糕。

    当做 弗里德里希

        6
  •  1
  •   Martin Beckett    16 年前

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

        7
  •  1
  •   Max Lybbert    15 年前

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

    typename template 关键字在一些地方,但许多编译器-包括Visual C++不执行此;gcc过去也没有强制执行这一点,但是 changed in 3.4 或(2)使用在一个编译器上实现的标准兼容行为,而不是另一个编译器(现在,这个海报男孩是导出模板,但是只有一个或两个编译器支持这个,Visual C++和GCC不在该组中)。

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

    我从来没见过这样做有什么问题。我发现在gcc中使用Microsoft的windows.h时出现问题。但是当我使用GCC的Windows .h在GCC和微软的Windows .h中,Visual C++中我可以访问所有的文档功能。这毕竟是“已实现的windows.h”的定义。

    需要注意的区别是什么?

    样板 类别名 上面提到的事情。我觉得很有趣,很多人认为GCC不够聪明,不能做Visual C++所做的事情,而实际上GCC首先拥有这个特性,然后决定以标准遵循的名义将其删除。

    在不久的将来,您将在使用C++0x特性时遇到问题。但是GCC和Visual C++都在这个标准中实现了更简单的事情。