如果有一些跨平台的C/ c++代码应该在Mac OS X, iOS, Linux, Windows上编译,我如何在预处理器过程中可靠地检测它们?


当前回答

大多数编译器都使用预定义的宏,你可以在这里找到列表。GCC编译器预定义宏可以在这里找到。 下面是gcc的一个例子:

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
   //define something for Windows (32-bit and 64-bit, this part is common)
   #ifdef _WIN64
      //define something for Windows (64-bit only)
   #else
      //define something for Windows (32-bit only)
   #endif
#elif __APPLE__
    #include <TargetConditionals.h>
    #if TARGET_IPHONE_SIMULATOR
         // iOS, tvOS, or watchOS Simulator
    #elif TARGET_OS_MACCATALYST
         // Mac's Catalyst (ports iOS API into Mac, like UIKit).
    #elif TARGET_OS_IPHONE
        // iOS, tvOS, or watchOS device
    #elif TARGET_OS_MAC
        // Other kinds of Apple platforms
    #else
    #   error "Unknown Apple platform"
    #endif
#elif __ANDROID__
    // Below __linux__ check should be enough to handle Android,
    // but something may be unique to Android.
#elif __linux__
    // linux
#elif __unix__ // all unices not caught above
    // Unix
#elif defined(_POSIX_VERSION)
    // POSIX
#else
#   error "Unknown compiler"
#endif

所定义的宏取决于将要使用的编译器。

_WIN64 #ifdef可以嵌套到_WIN32 #ifdef中,因为_WIN32甚至是在针对Windows x64版本时定义的。如果某些头包含对两者都是公共的,则可以防止代码重复 (没有下划线的WIN32允许IDE突出显示正确的代码分区)。

其他回答

2021年1月5日:由于@Sadap的评论,链接更新。

这是一个必然的答案:这个网站上的人已经花时间为每个OS/编译器对定义了宏表。

例如,你可以看到_WIN32在Windows Cygwin (POSIX)上没有定义,而在Windows Cygwin(非POSIX)上定义了编译,在MinGW上定义了所有可用的编译器(Clang, GNU, Intel等)。

不管怎样,我发现这些表格非常有用,我想在这里分享。

正如Jake指出的,TARGET_IPHONE_SIMULATOR是TARGET_OS_IPHONE的子集。

另外,TARGET_OS_IPHONE是TARGET_OS_MAC的子集。

所以一个更好的方法可能是:

#ifdef _WIN64
   //define something for Windows (64-bit)
#elif _WIN32
   //define something for Windows (32-bit)
#elif __APPLE__
    #include "TargetConditionals.h"
    #if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR
        // define something for simulator
        // (although, checking for TARGET_OS_IPHONE should not be required).
    #elif TARGET_OS_IPHONE && TARGET_OS_MACCATALYST
        // define something for Mac's Catalyst
    #elif TARGET_OS_IPHONE
        // define something for iphone  
    #else
        #define TARGET_OS_OSX 1
        // define something for OSX
    #endif
#elif __linux
    // linux
#elif __unix // all unices not caught above
    // Unix
#elif __posix
    // POSIX
#endif

注意上面检查了TARGET_OS_SIMULATOR宏,因为TARGET_IPHONE_SIMULATOR宏从iOS 14开始就被弃用了。

大多数编译器都使用预定义的宏,你可以在这里找到列表。GCC编译器预定义宏可以在这里找到。 下面是gcc的一个例子:

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
   //define something for Windows (32-bit and 64-bit, this part is common)
   #ifdef _WIN64
      //define something for Windows (64-bit only)
   #else
      //define something for Windows (32-bit only)
   #endif
#elif __APPLE__
    #include <TargetConditionals.h>
    #if TARGET_IPHONE_SIMULATOR
         // iOS, tvOS, or watchOS Simulator
    #elif TARGET_OS_MACCATALYST
         // Mac's Catalyst (ports iOS API into Mac, like UIKit).
    #elif TARGET_OS_IPHONE
        // iOS, tvOS, or watchOS device
    #elif TARGET_OS_MAC
        // Other kinds of Apple platforms
    #else
    #   error "Unknown Apple platform"
    #endif
#elif __ANDROID__
    // Below __linux__ check should be enough to handle Android,
    // but something may be unique to Android.
#elif __linux__
    // linux
#elif __unix__ // all unices not caught above
    // Unix
#elif defined(_POSIX_VERSION)
    // POSIX
#else
#   error "Unknown compiler"
#endif

所定义的宏取决于将要使用的编译器。

_WIN64 #ifdef可以嵌套到_WIN32 #ifdef中,因为_WIN32甚至是在针对Windows x64版本时定义的。如果某些头包含对两者都是公共的,则可以防止代码重复 (没有下划线的WIN32允许IDE突出显示正确的代码分区)。