How to detect reliably Mac OS X, iOS, Linux, Windows in C preprocessor?

181,808

Solution 1

There are predefined macros that are used by most compilers, you can find the list here. GCC compiler predefined macros can be found here. Here is an example for 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 __linux__
    // linux
#elif __unix__ // all unices not caught above
    // Unix
#elif defined(_POSIX_VERSION)
    // POSIX
#else
#   error "Unknown compiler"
#endif

The defined macros depend on the compiler that you are going to use.

The _WIN64 #ifdef can be nested into the _WIN32 #ifdef because _WIN32 is even defined when targeting the Windows x64 version. This prevents code duplication if some header includes are common to both (also WIN32 without underscore allows IDE to highlight the right partition of code).

Solution 2

As Jake points out, TARGET_IPHONE_SIMULATOR is a subset of TARGET_OS_IPHONE.

Also, TARGET_OS_IPHONE is a subset of TARGET_OS_MAC.

So a better approach might be:

#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

Note that above checks TARGET_OS_SIMULATOR macro because TARGET_IPHONE_SIMULATOR macro got deprecated since iOS 14.

Solution 3

5 Jan 2021: link update thanks to @Sadap's comment.

Kind of a corollary answer: the people on this site have taken the time to make tables of macros defined for every OS/compiler pair.

For example, you can see that _WIN32 is NOT defined on Windows with Cygwin (POSIX), while it IS defined for compilation on Windows, Cygwin (non-POSIX), and MinGW with every available compiler (Clang, GNU, Intel, etc.).

Anyway, I found the tables quite informative and thought I'd share here.

Share:
181,808
eonil
Author by

eonil

Favorite words: "Make it work, make it right, make it fast" — by Kent Beck? "...premature optimization is the root of all evil (or at least most of it) in programming." - from The Art of Computer Programming, by Donald Knuth. "Yes, but your program doesn't work. If mine doesn't have to work, I can make it run instantly and take up no memory." — from Code Complete, by Steve Mcconnell. "Flat is better than nested." — from The Zen of Python, by Tim Peters "Making decisions is slow." — from The Ninja build system manual, author unknown. "A little copying is better than a little dependency." - from Go Proverbs, by Rob Pike Preferred tools: macOS, iOS, Ubuntu. Rust, Swift, VIM, Xcode. SQLite, PostgreSQL, Redis. And a few more trivial stuffs. Feel free to fix my grammar. I always appreciate!

Updated on July 08, 2022

Comments

  • eonil
    eonil almost 2 years

    If there's some cross-platform C/C++ code that should be compiled on Mac OS X, iOS, Linux, Windows, how can I detect them reliably during preprocessor process?

  • Paul R
    Paul R about 13 years
    The OP specifically asked about Mac OS X versus iOS
  • Evgeny Gavrin
    Evgeny Gavrin about 13 years
    @Paul, "code should be compiled on Mac OS X, iOS, Linux, Windows"
  • eonil
    eonil about 13 years
    @Paul, @Evgeny I'm sorry for my mistake. My question includes Windows and Linux.
  • Steven Lu
    Steven Lu almost 12 years
    There is more... it should be #if TARGET_OS_IPHONE rather than #ifdef since TARGET_OS_IPHONE is defined as 0 on a Mac.
  • MFH
    MFH almost 12 years
    According to SourceForge _WIN32 is defined for both 32 und 64bit versions of Windows, so shouldn't _WIN64 be placed before _WIN32?
  • Jake Petroules
    Jake Petroules about 11 years
    #elif TARGET_IPHONE_SIMULATOR will never be hit since it will never be 1 while TARGET_OS_IPHONE is 0
  • AlcubierreDrive
    AlcubierreDrive over 10 years
    Note: People are saying that "__unix" is a catch-all, but it does not appear to be defined for me on Mac OS 10.7.5 with gcc 4.2.1 (gcc provided by Apple with Xcode)
  • Muruganandham K
    Muruganandham K over 10 years
    how to check the IPads?
  • jdknight
    jdknight over 9 years
    Instead of __linux shouldn't __linux__ be used?
  • daniel
    daniel over 8 years
    @jdknight yes __linux__ is the supported macro on all linux distributions, __linux is not supported on all linux distributions, __unix__ should also be used in place of __unix for the same reason, since all platforms that follow the unix guidelines support __unix__, and not __unix, here is a more in depth description nadeausoftware.com/articles/2012/01/…
  • fnc12
    fnc12 over 7 years
    also add __ANDROID__
  • 4LegsDrivenCat
    4LegsDrivenCat over 7 years
    I would also add __ANDROID__ above __linux__ as it has its own specifics compared to Linux.
  • 4LegsDrivenCat
    4LegsDrivenCat over 7 years
    I would also add __ANDROID__ above __linux__ for completeness as it has its own specifics compared to Linux.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    Wouldn't this require that any code specific to Windows, that is the same for both 32- and 64-bit, be duplicated in the _WIN64 and _WIN32 blocks? It's going to skip the _WIN32 one if it detects _WIN64, which may not be desirable. Something like this might work better.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    @MFH Not necessarily. If there's any code shared between 32-bit and 64-bit Windows, putting the _WIN64 block inside the _WIN32 one is optimal, because it prevents duplication of code. He mentioned this in the answer.
  • Lennart Rolland
    Lennart Rolland about 7 years
    I added the win-32 ONLY part which was obviously missing
  • Mecki
    Mecki about 7 years
    My Linux only defines __linux__, __gnu_linux__ and linux, but not __linux
  • parasrish
    parasrish over 6 years
  • jww
    jww over 6 years
    What is #define TARGET_OS_OSX 1? Apple and OS X defines its own macros.
  • Kadam Parikh
    Kadam Parikh about 4 years
    Aren't Linux and Macintosh actually POSIX?
  • Lindydancer
    Lindydancer over 3 years
    The link is dead.
  • bb1950328
    bb1950328 over 3 years