【问题标题】:How to detect reliably Mac OS X, iOS, Linux, Windows in C preprocessor? [duplicate]如何在 C 预处理器中可靠地检测 Mac OS X、iOS、Linux、Windows? [复制]
【发布时间】:2011-08-20 16:06:27
【问题描述】:

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

【问题讨论】:

    标签: c++ c cross-platform c-preprocessor os-detection


    【解决方案1】:

    大多数编译器都使用预定义的宏,您可以找到列表here。 GCC 编译器预定义的宏可以在here 找到。 这是 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
        #if 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 __linux__
        // linux
    #elif __unix__ // all unices not caught above
        // Unix
    #elif defined(_POSIX_VERSION)
        // POSIX
    #else
    #   error "Unknown compiler"
    #endif
    

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

    _WIN64 #ifdef 可以嵌套到 _WIN32 #ifdef 中,因为在面向 Windows x64 版本时甚至定义了 _WIN32。如果某些标头包含对两者都是通用的,这可以防止代码重复 (同样 WIN32 不带下划线允许 IDE 突出显示正确的代码分区)。

    【讨论】:

    • @Paul, "代码应该在 Mac OS X、iOS、Linux、Windows 上编译"
    • 还有更多...应该是#if TARGET_OS_IPHONE 而不是#ifdef,因为TARGET_OS_IPHONE 在Mac 上被定义为0
    • 根据 SourceForge 的说法,_WIN32 是为 32 位和 64 位版本的 Windows 定义的,所以不应该将 _WIN64 放在 _WIN32 之前吗?
    • @jdknight yes __linux__ 是所有 linux 发行版都支持的宏,__linux 并非所有 linux 发行版都支持,__unix__ 也应该用来代替 __unix原因,因为所有遵循 unix 指南的平台都支持__unix__,而不是__unix,这里有更深入的描述nadeausoftware.com/articles/2012/01/…
    • 另加__ANDROID__
    【解决方案2】:

    正如 Jake 指出的那样,TARGET_IPHONE_SIMULATORTARGET_OS_IPHONE 的子集。

    另外,TARGET_OS_IPHONETARGET_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以来已被弃用。

    【讨论】:

    • 我还要在__linux__ 上方添加__ANDROID__,因为它与Linux 相比有自己的特点。
    • 这是否需要在 _WIN64_WIN32 块中复制任何特定于 Windows 的代码(对于 32 位和 64 位都相同)?如果检测到_WIN64,它将跳过_WIN32,这可能是不可取的。像this 这样的东西可能会更好。
    • 我的Linux只定义了__linux____gnu_linux__linux,但没有定义__linux
    • 什么是#define TARGET_OS_OSX 1? Apple 和 OS X 定义了自己的宏。
    【解决方案3】:

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

    一种必然的回答:this site 上的人们已经花时间制作了为每个操作系统/编译器对定义的宏表

    例如,您可以看到 _WIN32 未在 Windows 上使用 Cygwin (POSIX) 定义,而它被定义为在 Windows、Cygwin(非 POSIX)和 MinGW 上使用所有可用编译器(Clang、GNU 、英特尔等)。

    无论如何,我发现这些表格信息量很大,并想在这里分享。

    【讨论】:

    猜你喜欢
    • 2019-01-19
    • 2017-07-30
    • 2013-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2023-04-05
    • 2013-09-07
    相关资源
    最近更新 更多