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

These are the predefined macros that C/C++ compilers define to tell you what type of processor the target processor, for which code is being generated, is. There are also predefined macros in C/C++ that tell you the compiler, predefined macros in C/C++ that tell you the target platform and predefined macros in C/C++ that tell you what language features are available.

Non-model-specific macros that describe the processor in terms of its features

Macro Definition Compiler(s)
Macro Definition Compiler(s)
__32BIT__ The target processor is (nominally) 32-bit. IBM VAC++
__64BIT__ The target processor is (nominally) 64-bit.
__FLT_HAS_INFINITY__ Defined to 1 if and only if the float type has a value for representing infinity. GCC
__FLT_HAS_QUIET_NAN__ Defined to 1 if and only if the float type has a non-signalling (quiet) Not A Number value. GCC
__LDBL_HAS_INFINITY__ Defined to 1 if and only if the long double type has a value for representing infinity. GCC
__LDBL_HAS_QUIET_NAN__ Defined to 1 if and only if the long double type has a non-signalling (quiet) Not A Number value. GCC
__ORDER_LITTLE_ENDIAN__ Defined to an unspecified non-zero integer value distinct from the other two order macros. GCC
__ORDER_BIG_ENDIAN__ Defined to an unspecified non-zero integer value distinct from the other two order macros. GCC
__ORDER_PDP_ENDIAN__ Defined to an unspecified non-zero integer value distinct from the other two order macros. GCC
__BYTE_ORDER__ Defined to be equal in value to one of __ORDER_LITTLE_ENDIAN__, __ORDER_BIG_ENDIAN__, or __ORDER_PDP_ENDIAN__; indicating the order of bytes within integer types. GCC
__FLOAT_WORD_ORDER__ Defined to be equal in value to one of __ORDER_LITTLE_ENDIAN__, __ORDER_BIG_ENDIAN__, or __ORDER_PDP_ENDIAN__; indicating the order of bytes within floating point types. GCC

The point of the order macros is that they enable feature tests of the form:

#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)

	// ... little-endian code

#endif

The fact that they are non-zero when defined means that you can employ the zero value case to determine whether the feature test is available in the first place. The C++ language standard mandates that the value of an identifier that isn't a macro, in a controlling expression for conditional compilation, is zero, remember.

Macros that are specific to Intel Architecture processor targets

Macro Definition Compiler(s)
Macro Definition Compiler(s)
__IA64__ Defined to 1 if the processor architecture is IA-64 (a.k.a. Itanium). GCC
__ia64__ Defined to 1 if the processor architecture is IA-64 (a.k.a. Itanium). GCC
_M_IA64 Defined to 1 if the processor architecture is IA-64 (a.k.a. Itanium). MSVC++
_M_X64 Defined if a 64-bit x86 instruction set is the target. MSVC++
__X86_64__ Defined to 1 if a 64-bit x86 instruction set is the target. OpenWatcom
__x86_64__ Defined if a 64-bit x86 instruction set is the target. GCC, Clang, Intel
_M_IX86 Defined if a 16-bit or a 32-bit 8086 or 80x86 processor is the target. The value indicates the processor but not the bitness: 0 for 8086, 100 for 80186, 200 for 80286, 300 for 80386, 400 for 80486, 500 for Pentium, and 600 for Pentium Pro or later. OpenWatcom
Defined if and only if a 32-bit 80x86 processor is the target. The value indicates the processor: 300 for 80386, 400 for 80486, 500 for Pentium, and 600 for Pentium Pro or later. MSVC++, DigitalMars
__X86__ Defined to 1 if a 16-bit or 32-bit x86 instruction set is the target. OpenWatcom
__386__ Defined to 1 if and only if a 32-bit x86 instruction set is the target. OpenWatcom
_M_I386
__I86__ Defined to 1 if and only if a 16-bit x86 instruction set is the target. OpenWatcom
Always defined. The value indicates the processor but not the bitness: 0 for 8086, 1 for 80186, 2 for 80286, 3 for 80386, 4 for 80486, 5 for Pentium, and 6 for Pentium Pro or later. DigitalMars
_M_I86 Defined to 1 if and only if a 16-bit x86 instruction set is the target. OpenWatcom
Always defined. DigitalMars
__i386 Defined if a 32-bit x86 instruction set is the target. Intel
__i386__ Defined if a 32-bit x86 instruction set is the target. GCC, Intel
_M_I8086 Defined if 16-bit 8086 code is the target. DigitalMars
_M_I286 Defined to 1 if and only if an 80286 or later x86 or x86-64 processor is the target. DigitalMars

Intel Architecture conditional compilation

A consistent, robust, and portable way to differentiate amongst the different Intel Architecture targets is tricky.

OpenWatcom provides a simple differentiation. Its compiler for 16-bit targets defines __I86__ and _M_I86, and its compiler for 32-bit targets defines __386__ and _M_I386. Both compilers define __X86__ and _M_IX86, with the latter indicating what instruction set is being used. (Remember that the new instructions specific to the 80486 and Pentium are available in both 16-bit and 32-bit code.) This would be a fairly straightforward scheme:

// This is OpenWatcom's scheme.
#if __X86_64__

	// It's the x86-64/IA32e architecture.

#elif __X86__
	// It's an x86 architecture of some kind:
#  if __386__ || _M_I386

	// Using the compiler for 32-bit targets, wpp386 or wcc386, so must be x86-32.
#    if _M_IX86 >= 600
		// Pentium Pro instructions and instruction scheduling
#    elif _M_IX86 >= 500
		// Pentium instructions and instruction scheduling
#    elif _M_IX86 >= 400
		// 80486 instructions and instruction scheduling
#    elif _M_IX86 >= 300
		// 80386 instructions and instruction scheduling
#    else
		// This is not possible with the 32-bit compiler.
#    endif

#  elif __I86__ || _M_I86

	// Using the compiler for 16-bit targets, wpp or wcc, so must be x86-16.
#    if _M_IX86 >= 600
		// Pentium Pro instructions and instruction scheduling
#    elif _M_IX86 >= 500
		// Pentium instructions and instruction scheduling
#    elif _M_IX86 >= 400
		// 80486 instructions and instruction scheduling
#    elif _M_IX86 >= 300
		// 80386 instructions and instruction scheduling
#    elif _M_IX86 >= 200
		// 80286 instructions and instruction scheduling
#    elif _M_IX86 >= 100
		// 80186 instructions and instruction scheduling
#    else
		// 8086 instructions and instruction scheduling
#    endif

#  endif
#endif

That is, it would be simple, if everyone else followed the same scheme. But they don't. DigitalMars always defines the _M_I86 macro, even for 32-bit targets, and doesn't define __386__ or _M_I386 at all. DigitalMars doesn't support anything other than 16-bit and 32-bit targets:

// This is DigitalMars' scheme.
#if defined(_M_IX86)

	// It must be the x86-32 architecture.
#    if _M_IX86 >= 600
		// Pentium Pro instructions and instruction scheduling
#    elif _M_IX86 >= 500
		// Pentium instructions and instruction scheduling
#    elif _M_IX86 >= 400
		// 80486 instructions and instruction scheduling
#    elif _M_IX86 >= 300
		// 80386 instructions and instruction scheduling
#    else
		// This is not possible with the 32-bit compiler.
#    endif

#else

	// It must be the x86-16 architecture.
#    if _M_I286
		// 80286 instructions and instruction scheduling
#    elif _M_I8086
		// 8086 instructions and instruction scheduling
#    else
		// This is not possible with the 16-bit compiler.
#    endif

#endif

Microsoft's C++ compiler, similarly, doesn't define __I86__, _M_I86, __386__, or _M_I386 at all, and only defines _M_IX86. Since Microsoft's C++ compiler doesn't even allow for the possibility of 16-bit targets, is scheme is somewhat different:

// This is Microsoft's scheme.
#if _M_IA64

	// It's the Itanium/IA64 architecture.

#elif _M_X64 /*Modern macro*/ \
   || _M_AMD64 /*Older macro with a vendor-specific name*/

	// It's the x86-64 architecture.

#elif _M_IX86

	// It's the x86-32 architecture.
#    if _M_IX86 >= 600
		// Pentium Pro instructions and instruction scheduling
#    elif _M_IX86 >= 500
		// Pentium instructions and instruction scheduling
#    elif _M_IX86 >= 400
		// 80486 instructions and instruction scheduling
#    elif _M_IX86 >= 300
		// 80386 instructions and instruction scheduling
#    else
		// This is not possible with the 32-bit compiler.
#    endif

#else

	// … _M_PPC, _M_RX000, and _M_ALPHA indicate non-Intel
	// architectures that are no longer available as targets.

#endif

Worse, GCC, Clang, and Intel's C++ compiler don't define any of these nine macros. Instead, they have an alternative scheme of their own, using a completely disjoint set of macros (note the lowercase spellings instead of uppercase) that are — just to make the incompatibility symmetrical — not defined at all by OpenWatcom, Microsoft's C++ compiler, or DigitalMars:

// This is the scheme for GCC, Clang, and Intel's compiler.
#if defined(__ia64__)

        // ... Itanium/IA64

#if defined(__x86_64__)

	// ... x86-64/IA32e

#elif defined(__i386__)

	// ... x86-32

#endif

Combining these into a single, portable, conditional compilation that works on all of the compilers makes quite a mess:

#if defined(__IA64__) \
 || _M_IA64 /*MSVC++*/ \
 || defined(__ia64__) /*GCC,Clang,Intel*/

        // ... Itanium/Intel Architecture 64

#elif __X86_64__ /*OpenWatcom*/ \
   || _M_X64 /*MSVC++*/ \
   || _M_AMD64 /*MSVC++ compatibility with older compilers*/ \
   || defined(__x86_64__) /*GCC,Clang,Intel*/

	// ... x86-64/IA32e

#elif __386__ || _M_I386 /*OpenWatcom*/ \
   || (defined(__DMC__) && defined(_M_IX86)) /*DigitalMars*/ \
   || (defined(_MSC_VER) && _M_IX86) /*MSVC++*/ \
   || defined(__i386__) /*GCC,Clang,Intel*/

	// ... x86-32
#    if _M_IX86 >= 600
		// Pentium Pro instructions and instruction scheduling
#    elif _M_IX86 >= 500
		// Pentium instructions and instruction scheduling
#    elif _M_IX86 >= 400
		// 80486 instructions and instruction scheduling
#    elif _M_IX86 >= 300
		// 80386 instructions and instruction scheduling
#    else
		// This must be GCC or Clang.
#    endif

#  elif __I86__ || _M_I86 /*OpenWatcom*/ \
   || (defined(__DMC__) && !defined(_M_IX86)) /*DigitalMars*/

	// ... x86-16
#    if _M_IX86 >= 600
		// Pentium Pro instructions and instruction scheduling
#    elif _M_IX86 >= 500
		// Pentium instructions and instruction scheduling
#    elif _M_IX86 >= 400
		// 80486 instructions and instruction scheduling
#    elif _M_IX86 >= 300
		// 80386 instructions and instruction scheduling
#    elif _M_IX86 >= 200 || _M_I286
		// 80286 instructions and instruction scheduling
#    elif _M_IX86 >= 100
		// 80186 instructions and instruction scheduling
#    else
		// 8086 instructions and instruction scheduling
#    endif

#endif

Macros for other than Intel Architecture processor targets

Macro Definition Compiler(s)
Macro Definition Compiler(s)
__ppc__ Defined to 1 if the processor architecture is PowerPC GCC
_M_PPC Defined to 1 if the processor architecture is PowerPC (no longer available as a target in modern revisions of the compiler) MSVC++
_M_RX000 Defined to 1 if the processor architecture is MIPS (no longer available as a target in modern revisions of the compiler) MSVC++
_M_ALPHA Defined to 1 if the processor architecture is Alpha (no longer available as a target in modern revisions of the compiler) MSVC++

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