哪个跨平台预处理器定义? (__WIN32__ 或 __WIN32 或 WIN32 )?

Posted

技术标签:

【中文标题】哪个跨平台预处理器定义? (__WIN32__ 或 __WIN32 或 WIN32 )?【英文标题】:Which Cross Platform Preprocessor Defines? (__WIN32__ or __WIN32 or WIN32 )? 【发布时间】:2011-02-28 17:00:39 【问题描述】:

我经常看到__WIN32WIN32__WIN32__。我认为这取决于使用的预处理器(来自 Visual Studio 或 gcc 等)。

我现在必须先检查 os,然后再检查使用的编译器吗?我们在这里使用 G++ 4.4.x、Visual Studio 2008 和 Xcode(我假设又是一个 gcc)和 ATM,我们只使用 __WIN32____APPLE____LINUX__

【问题讨论】:

_WIN32 是系统性的,比其他拼写更冒犯。见sourceforge.net/p/predef/wiki/OperatingSystems。好的做法是测试每种情况(操作系统、架构、编译器......)的相关内容,而不是针对另一种情况进行测试。也不要重新定义你自己的。 【参考方案1】:

不明白为什么必须这样做。您可能必须记住在编译器的命令行上手动指定定义,但仅此而已。作为记录,Visual Studio 的定义是_WIN32(带一个下划线)而不是__WIN32。如果没有定义就没有定义,也没关系。

【讨论】:

所以我只能写一次#ifdef __WIN32__ 而不是#ifdef WIN32 || __WIN32 || __WIN32__ @brubelsabs:是的,但如果您决定使用其他编译器,则必须记住自己在命令行中输入预处理器定义。 AFAIK _WIN32 是为所有(现代)Windows 编译器(当然不包括 WinCE)定义的。无需自己定义... @math:你的#ifdef-表达式是错误的。应该是#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)。参考C Preprocessor directives and boolean operators。 @IInspectable:或者#if WIN32 || _WIN32 || __WIN32__。未定义的名称被视为零。问题是在#define _WIN32 0的情况下应该怎么做。【参考方案2】:

我已经重建了我的答案...该死的,正在疯狂编辑:P:

您不需要使用部分的。对于 MacOSX、Linux 和其他类 Unix 系统,您可能根本不需要使用任何工具。

最受欢迎的是(据 Google 所说)是_WIN32

从不在源代码中“手动”定义它。它以下列方式之一定义: 作为命令行预处理器/编译器标志(如g++ -D _WIN32) 或者它是由编译器本身预定义的(大多数 Windows 编译器都预定义了_WIN32,有时也预定义了WIN32_WIN32_。--那么你根本不需要担心定义它,编译器会完成整个工作。


我的旧答案:

您不必“必须”做任何事情。它只是为了多平台兼容性。通常所有类 Unix(包括 Linux、MacOSX、BSD、Solaris...)和其他 POSIX 平台的代码版本将完全相同,并且必须对 Windows 进行一些更改。所以人们通常为类 Unix 编写他们的代码,并在#ifdef _WIN32#endif 之间放置一些仅限 Windows(例如 DirectX 指令、类 Windows 文件路径...)的部分。

如果您有一些零件,例如。仅 X-Window 系统或仅 MacOS,您可以使用 #ifdef X_WINDOW#ifdef MACOS 之类的东西进行类似操作。然后,您需要在编译时设置适当的预处理器定义(使用 gcc 使用 -D 标志,例如 gcc -D _WIN32)。

如果你不编写任何依赖于平台的代码,那么你就不需要关心这样的#ifdef, #else, #endif 块。大多数 Windows 编译器/预处理器 AFAIK 都预定义了一些符号,如 _WIN32(最流行,据 google 说实话)、WIN32_WIN32_ 等。所以在 Windows 上编译它很可能你不会除了编译之外,还需要做任何其他事情。

【讨论】:

可能我的问题很不清楚:我不想定义 WIN32,而是将它与#ifdef 一起使用。我想知道为什么有这么多变体,是否有一个可以与大多数编译器一起使用。 正如我所说,人们只是使用他们喜欢的东西,没有标准。无论如何,您可以在命令行中(以及 IDE 选项等)编译自己时定义它,因此使用“不支持”的 WIN32__ 而不是“好”的 _WIN32 不是问题。而且,正如我所说,大多数编译器支持 _WIN32,有些支持许多其他编译器(mingw 支持 WIN32 _WIN32 WIN32 __WIN32 MINGW32 WINNT WINNT __WINNT)。看到这个:***.com/questions/142508/…【参考方案3】:

这取决于你想要做什么。如果您的程序想要使用某些特定功能(例如来自 gcc 工具链),您可以检查编译器。如果您想使用某些操作系统特定的功能(无论编译器如何 - 例如 Windows 上的 CreateProcess 和 unix 上的 fork),您可以检查操作系统( _WINDOWS、__unix__ )。

Macros for Visual C

Macros for gcc

您必须检查每个编译器的文档,以便能够在编译时检测到差异。我记得 gnu 工具链(gcc)在 C 库(@​​987654323@)中有一些其他工具链(例如 Visual C)中没有的函数。这样,如果您想在商品之外使用这些功能,那么您必须检测到您正在使用 GCC,因此您必须使用的代码如下:

#ifdef __GNUC__
// do my gcc specific stuff
#else
// ... handle this for other compilers
#endif

【讨论】:

【参考方案4】:

叹气 - 不要依赖编译器 - 在 Makefile 中指定您正在构建的平台。简而言之,以 _ 开头的任何内容都依赖于实现而不是可移植的。

我曾经在一个非常大的项目中尝试过你的方法,在 Sun-C++ 和 GCC 之间来回切换,我们只是决定使用 Makefile 控制,而不是试图推断编译器将要做什么。

【讨论】:

您可以为不同的行为创建包装器并使用这些包装器。这样,您只需在几个源文件中处理平台/编译器差异,(在我看来)这比处理每个平台的 makefile 更好。 你有一个有效的点。但是,我无法想象您支持多个平台并且不使用某种 Makefile(gmake/cmake/qmake)的情况。 link.exe 的 Windows 库定义与 gcc -L -l 不同。编译器优化设置也不是。我宁愿在一个 Makefile(或几个包含)中处理我的平台标志,而不是必须记住在每个头文件/源文件中包含 platform_magic.h。 Boost 会按照你的方式去做——在 boost/system/config.hpp 中,它决定了它在哪个平台上运行。我们只需要同意不同意。 :-D【参考方案5】:

这篇文章回答了你的问题:

C/C++ tip: How to detect the operating system type using compiler predefined macros(加上archive.org link,以防它消失)。

这篇文章很长,并且包含难以复制的表格,但这里是精髓:

您可以通过以下方式检测 Unix 风格的操作系统:

#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
    /* UNIX-style OS. ------------------------------------------- */

#endif

一旦你知道它是 Unix,你就可以找到它是否是 POSIX 和 POSIX 版本:

#include <unistd.h>
#if defined(_POSIX_VERSION)
    /* POSIX compliant */
#endif

您可以通过以下方式检查 BSD 派生系统:

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#if defined(BSD)
    /* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD). ----------- */

#endif
#endif

和 Linux:

#if defined(__linux__)
    /* Linux  */
#endif

和苹果的操作系统

#if defined(__APPLE__) && defined(__MACH__)
    /* Apple OSX and ios (Darwin) */
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
    /* iOS in Xcode simulator */
#elif TARGET_OS_IPHONE == 1
    /* iOS on iPhone, iPad, etc. */    
#elif TARGET_OS_MAC == 1
    /* OS X */
#endif
#endif

带有 Cygwin 的 Windows

#if defined(__CYGWIN__) && !defined(_WIN32)
    /* Cygwin POSIX under Microsoft Windows. */
#endif

非 POSIX Windows 具有:

#if defined(_WIN64)
    /* Microsoft Windows (64-bit) */
#elif defined(_WIN32)
    /* Microsoft Windows (32-bit) */
#endif

全文列出了以下符号,并显示了哪些系统定义了它们以及何时定义它们:_AIX__APPLE____CYGWIN32____CYGWIN____DragonFly____FreeBSD____gnu_linux、@987654339 @,__hpux,linux,__linux,__linux__,__MACH__,__MINGW32__,__MINGW64__,__NetBSD__,__OpenBSD__,_POSIX_IPV6,_POSIX_IPV6,_POSIX_IPV6,@9876 _POSIX_THREADS_POSIX_VERSIONsun__sun__SunOS__sun____SVR4__svr4__TARGET_IPHONE_SIMULATORTARGET_OS_EMBEDDEDTARGET_OS_IPHONETARGET_OS_MACUNIX,unix,__unix,__unix__,WIN32,_WIN32,__WIN32,__WIN32__,WIN64,_WIN64,@987654375,@,@987654375,@,@987654376 __WINNT, __WINNT__.

A related article (archive.org link) 涵盖了检测编译器和编译器版本。它列出了以下符号:__clang____GNUC____GNUG____HP_aCC__HP_cc__IBMCPP____IBMC____ICC__INTEL_COMPILER_MSC_VER3、 __SUNPRO_C__SUNPRO_CC 用于检测编译器,__clang_major____clang_minor____clang_patchlevel____clang_version____GNUC_MINOR____GNUC_PATCHLEVEL____GNUC__,@9876544399@9876544399@9801 @, __IBMCPP__, __IBMC__, __ICC, __INTEL_COMPILER, __INTEL_COMPILER_BUILD_DATE, _MSC_BUILD, _MSC_FULL_VER, _MSC_VER, __PGIC_MINOR__, @987644412@, __PGIC__, __PGIC__, _MSC_FULL_VER __SUNPRO_CC__VERSION____xlC_ver____xlC____xlc__ 用于检测编译器版本。

【讨论】:

链接可能会损坏,我只是在没有任何解释的情况下发布链接,我认为这不是一种好的 QA 风格。即使这只是一个评论。请尝试总结文章。 好电话。我更新了这篇文章以提供更多详细信息,还提供了指向 archive.org 的链接以更好地处理网站消失问题。

以上是关于哪个跨平台预处理器定义? (__WIN32__ 或 __WIN32 或 WIN32 )?的主要内容,如果未能解决你的问题,请参考以下文章

CMake 中的平台检测

[ATL/WTL]_[初级]_[Win32窗口自定义消息处理过程]

为啥在预处理器定义中使用 if 语句?

Windows Mobile 6.5.3 预处理器

WIN32_LEAN_AND_MEAN 含义以及用法

跨平台为宏 __FUNCTION__ 和 __func__ 定义 #define