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 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
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
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>
.
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.
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
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