Predefined macros in C/C++ that tell you what the target platform is.

These are the predefined macros that C/C++ compilers define to tell you what operating system API is being targetted. There are also predefined macros in C/C++ that tell you the compiler, predefined macros in C/C++ that tell you the target processor and predefined macros in C/C++ that tell you what language features are available.

Note that in some compilers the macros are not hardwired, and platform names are under the user's control. With OpenWatcom C/C++, for example, an arbitrary "build target" name can be specified with the -bt option to the compiler, and a platform macro named after the build target name will be predefined. For such compilers, the following are conventional names. They're also the names used by default, when the target platform is the same as the host platform (that the compiler is itself running on) and no explicit build target is specified.

Macro Meaning Compiler(s)
Macro Meaning Compiler(s)
__OS2__ The target platform API is OS/2. OpenWatcom,IBM VAC++,DigitalMars
__DOS__ The target platform API is MS/PC/DR-DOS. OpenWatcom
MSDOS The target platform API is MS/PC/DR-DOS. (This is specially defined when the build target is dos.) OpenWatcom
The target platform API is MS/PC/DR-DOS. DigitalMars
__NT__ The target platform API is Win32. OpenWatcom
__QNX__ The target platform API is QNX (specifically). OpenWatcom
__LINUX__ The target platform API is Linux (specifically). OpenWatcom
__linux__ The target platform API is Linux. GCC
__UNIX__ The target platform API is Unix-alike (i.e. QNX or Linux). (This is specially defined when the build target is qnx or linux.) OpenWatcom
__unix__ The target platform API is Unix-alike (i.e. Cygwin or Linux). GCC, Clang
_WIN32 The target platform API is Win32. DigitalMars, GCC, Clang, MSVC++
__WINDOWS__ The target platform API is either Win16 or OpenWatcom's 32-bit extended version of Win16. OpenWatcom
_WINDOWS The target platform API is Win16. (This is specially defined, but only by the 16-bit compiler, when the build target is windows.) OpenWatcom
__WINDOWS_386__ The target platform API is OpenWatcom's 32-bit extended version of Win16. (This is specially defined, but only by the 32-bit compiler, when the build target is windows.) OpenWatcom
__CYGWIN__ The target platform API is Cygwin. GCC, Clang
__CYGWIN32__
__DragonFly__ The target platform API is DragonFly BSD. GCC, Clang
__FreeBSD__ The target platform API is FreeBSD. GCC, Clang
__NetBSD__ The target platform API is NetBSD. GCC, Clang
__OpenBSD__ The target platform API is OpenBSD. GCC, Clang
__MACH__ The target platform API is Mach-based (including NextSTEP and MacOS 10). GCC, Clang
__APPLE__ The target platform API is "Apple-ish". llvm-gcc, Clang

The POSIX API

The POSIX API isn't really a target platform. This is because it is available, to varying degrees, on many quite different target platforms. There are: a native POSIX subsystem on Windows NT; a POSIX API supplied by Cygwin; and a POSIX API supplied by the BSDs, Solaris, AIX, HP/UX, and Linux as their native system APIs. The compilers with their historical origins in MS/PC/DR-DOS, such as OpenWatcom and Microsoft's compiler, even provide C language bindings to the DOS API that resemble the POSIX API C language bindings on a dark night if one squints heavily and that some programmers have mistaken for the POSIX API.

The POSIX API is an extremely broach church, and there are a shedload of of feature-test macros that are defined by the <unistd.h> header, which is the main C language binding header for the POSIX API (c.f. <windows.h> for Win16 and Win32, <os2.h> for 16-bit and 32-bit OS/2, and <dos.h> for MS/PC/DR-DOS). These include the _POSIX_VERSION macro, as well as quite a lot of others including for examples _POSIX2_C_VERSION, _POSIX_CHOWN_RESTRICTED, _POSIX_SAVED_IDS, _POSIX_JOB_CONTROL, _POSIX_FSYNC, and _POSIX_MAPPED_FILES.

Unfortunately, there's no predefined macro that tells one that the <unistd.h> header is available for inclusion in the first place. A common misconception is to think that the __unix__ or __UNIX__ macros do this. They do not. There are compilers with a <unistd.h> header that predefine neither of those macros, and there are compilers where the POSIX API is a shim layer over the underlying platform API, and the __unix__ or __UNIX__ macros are predefined as a source portability measure, and don't provide the information that there is in fact a more specific, "true", platform API available.

POSIX-Think expects programmers to work the other way around. Instead of the compiler predefining a platform macro and the program source using conditional compilation to select which platform API to target, the POSIX way of working has the program source (or the build system via compiler options) predefining a platform macro which tells the compiler's library which platform API to make available. The upshot of this is that the macro for detecting whether to use the POSIX API is user-defined, not compiler-defined. One checks for it as follows:

#if defined(_POSIX_C_SOURCE) \
 || defined(_POSIX1_SOURCE) \
 || defined(_POSIX_SOURCE)

        // ... code targetting the POSIX API

#end

Cygwin

The __unix__ and __CYGWIN__ macros are complex. Compilers targetting Cygwin intentionally define __unix__ in order that code that is targetted to a Unix-alike API is selected. It is a source code portability measure. However, Cygwin compilers can also target the Win32 API. Cygwin programs, POSIX or otherwise, are Win32 programs, after all. (On Windows NT, Cygwin programs execute under the aegis of the Win32 subsystem, not under the aegis of the POSIX subsystem.) Yet those compilers still define the __CYGWIN__ and __unix__ macros, because they always define them.

To account for this, one relies upon the _WIN32 macro instead and uses code such as:

#if defined(__CYGWIN__) 
#  if defined(_WIN32)

        // ... code compiled with Cygwin GCC or Clang, targetting Win32 API

#  else

        // ... code compiled with Cygwin GCC or Clang, targetting POSIX API

#  end
#end

The __unix__ macro is otherwise, outwith Cygwin and checking for the BSDs, pretty much useless, as it doesn't really indicate a specific API. Instead, to determine exactly what flavour of the POSIX API one has, one should use the fine-grained feature-test macros that are defined in <unistd.h>. Indeed, unless one is targetting some non-standard Cygwinism, one is better off not checking for __CYGWIN__ at all and rather targetting the POSIX or Win32 APIs directly:

#if defined(_POSIX_C_SOURCE) \
 || defined(_POSIX1_SOURCE) \
 || defined(_POSIX_SOURCE)

        // ... code targetting POSIX API

#elif defined(_WIN32)

        // ... code targetting Win32 API

#end

The BSDs

The FreeBSD Porter's Handbook gives a recommendation that actually applies to all of the BSDs. Don't use the various __FreeBSD__ macros at all unless there is absolutely no other way to check for the relevant information. Rather, check for a "Unix-alike" that will have the <sys/param> header, and then read the BSD macro from that header:

#if defined(__unix__) || defined(__UNIX__) || (defined(__APPLE__) && defined(__MACH__))
#  include <sys/param.h>
#  if defined(BSD)

        // ... code targetting the BSD API

#  end
#end

GCC and Clang targetting Apple's Darwin is one of the few cases where a "Unix-alike" target platform doesn't have the __unix__ or __UNIX__ macros defined, hence the check for __APPLE__ and __MACH__. Strictly speaking, those two macros don't, either apart or in combination, mean "Unix-alike". It just so happens that no Mach-based "Apple-ish" platform API will fail to have a <sys/param.h> header.

As with Cygwin, however, the far better approach is to ignore the BSD macro entirely in favour of the fine-grained feature-test macros that are defined in <unistd.h>.

Apple-ish platforms

The __APPLE__ macro has exactly one valid use: recognizing Darwin when checking for the BSDs. It's only defined by Apple-supplied and Apple-forked compilers, such as lvm-gcc, Apple's old fork of GCC 4, and Clang, and by compilers that seek to be compatible with those, such as IBM's XLC++. And even then it's only defined by those compilers when Darwin is the target platform.

If you find yourself using this macro in any other circumstance, you are probably doing something terribly wrongheaded.

OS/2 API

The __OS2__ macro denotes both the 16-bit OS/2 API and the 32-bit OS/2 API. To differentiate between them, which is fortunately rarely needed in practice, one has to resort to checking the bitness of the target instruction set:

#if defined(__OS2__) 
#  if __32BIT__ || __386__ || _M_I386 || defined(__i386__) \
   || (defined(__DMC__) && _M_IX86)

        // ... code targetting the 32-bit OS/2 API

#  else

        // ... code targetting the 16-bit OS/2 API

#  end
#end

MS/PC/DR-DOS API

The MSDOS macro denotes both the 16-bit DOS API and the 32-bit extended DOS API provided by a "DOS Extender". To differentiate between them one has to resort to checking the bitness of the target instruction set:

#if defined(MSDOS) 
#  if __32BIT__ || __386__ || _M_I386 || defined(__i386__) \
   || ((defined(__DMC__) || defined(_MSC_VER)) && _M_IX86)

        // ... code targetting the 32-bit extended DOS API

#  else

        // ... code targetting the 16-bit DOS API

#  end
#end

© Copyright 2012 Jonathan de Boyne Pollard. "Moral" rights asserted.
Permission is hereby granted to copy and to distribute this web page in its original, unmodified form as long as its last modification datestamp information is preserved.