CPP / C++ - Preprocessor and Macros

Table of Contents

1 Preprocessor and macros

1.1 Enable and disable macros during compilation

This section is reminder about how to enable and disable macros during compilation. This technique can be used for both C or C++. Note: defining macros with -DMACRO=VALUE only works for GCC(G++) or Clang. MSVC (Microsft Visual C++ compiler) uses '/' slash for defining macros from command line. I this case the macro can be defined using /DMACRO=VALUE.

File: macro-test.cpp

#include <iostream>

#ifndef CODE_VERSION
  #define CODE_VERSION "0.1" 
#endif 

int main(int argc, char** argv)
{

  if(argc < 2)
  {
      std::fprintf(stderr,  " Product version: %s \n", CODE_VERSION);
      std::fprintf(stderr, " Usage: %s <NUMBER> \n", argv[0]);
      return EXIT_FAILURE;
  }

  int n    = std::stoi(argv[1]);
  int prod = 1;

  for(int i = 1; i <= n; i++){
    prod *= i;

    #if LOGGING 
      std::fprintf(stderr, " => i = %d ; prod = %d \n", i, prod); 
    #endif 
  }

  std::printf(" => product = %d \n", prod); 

  // Same as: return 0;
  return EXIT_SUCCESS;
}

Building manually

Build without setting any preprocessor directive.

$ >> g++ macro-test.cpp -o macro-test.bin -std=c++1z -Wall -Wextra

$ >> ./macro-test.bin 
Product version: 0.1 
Usage: ./macro-test.bin <NUMBER> 

$ >> ./macro-test.bin 10
=> product = 3628800 

Build defining the LOGGING macro.

$ >> ./macro-test.bin
Product version: 0.1 
Usage: ./macro-test.bin <NUMBER> 

$ >> g++ macro-test.cpp -o macro-test.bin -std=c++1z -Wall -Wextra -DLOGGING

$ >> ./macro-test.bin 5
=> i = 1 ; prod = 1 
=> i = 2 ; prod = 2 
=> i = 3 ; prod = 6 
=> i = 4 ; prod = 24 
=> i = 5 ; prod = 120 
=> product = 120 

Build defining a different value for the version macro.

$ >> g++ macro-test.cpp -o macro-test.bin -std=c++1z -Wall -Wextra -DLOGGING -DCODE_VERSION='"1.5"'

$ >> ./macro-test.bin
Product version: 1.5 
Usage: ./macro-test.bin <NUMBER> 


$ >> ./macro-test.bin 6
=> i = 1 ; prod = 1 
=> i = 2 ; prod = 2 
=> i = 3 ; prod = 6 
=> i = 4 ; prod = 24 
=> i = 5 ; prod = 120 
=> i = 6 ; prod = 720 
=> product = 720 

1.2 Temporarily disable a code block

A useful technique for during development of C or C++ applications is to surround a piece of code with macros ( #if 1 … #endif ), for enabling the compilation of this code block, or (#if 0 … #endif), for disabling the compilation of this code block. This technique can be used identifying and isolating a piece of code that causes compile-time error or runtime error.

  • Case 1 - Enable code block => Code block surrounded by #if 1 … #else enabled.

File: macro-if-else.cpp

#include <iostream>

int main(int arc, char** argv)
{
  int n = 10;
  int sum = 0;

  for(int i = 0; i < n; i++){
    sum += i;
    #if 1
      std::printf(" => i = %d ; sum = %d \n", i, sum);
    #endif
  }

  std::printf(" => sum = %d \n", sum);

  return 0;
}

Output:

$ >> g++ macro-if-else.cpp -o macro-if-else.bin -std=c++1z -Wall -Wextra

$ >> ./macro-if-else.bin
=> i = 0 ; sum = 0 
=> i = 1 ; sum = 1 
=> i = 2 ; sum = 3 
=> i = 3 ; sum = 6 
=> i = 4 ; sum = 10 
=> i = 5 ; sum = 15 
=> i = 6 ; sum = 21 
=> i = 7 ; sum = 28 
=> i = 8 ; sum = 36 
=> i = 9 ; sum = 45 
=> sum = 45 
  • Case 2 - Code block Disabled => Coce block surrounded by #if 0 … #else disabled.

File: macro-if-else.cpp

#include <iostream>

int main(int arc, char** argv)
{
  int n = 10;
  int sum = 0;

  for(int i = 0; i < n; i++){
    sum += i;
    #if 0
      std::printf(" => i = %d ; sum = %d \n", i, sum); 
    #endif 
  }

  std::printf(" => sum = %d \n", sum); 

  return 0;
}

Output:

$ >> g++ macro-if-else.cpp -o macro-if-else.bin -std=c++1z -Wall -Wextra

$ >> ./macro-if-else.bin
=> sum = 45 

1.3 Variable argument macros

Variable argument macros are function-like macros that can take one or or an arbirtrary amount of arguments. This sections presents an example about how to use this type of macros __VAR__ARGS__

File: macro-args.cpp

#include <iostream> 
#include <string> 

// Note: this macro does not work without at least a third argument. 
#define LOG(severity, message, ...) \
    std::fprintf(stderr, severity " (file: %s, line: %d) / " message "\n", __FILE__, __LINE__,  __VA_ARGS__  )

// Note: This macro can work without a third argument, but it requires C++11. 
// Note: __VA_OPT__(,) only works on GNU-C compiler or C++ compilers supporting at least C++11. 
#define LOG2(severity, message, ...) \
    std::fprintf(stderr, severity " (file: %s, line: %d) / " message "\n", __FILE__, __LINE__  __VA_OPT__(,) __VA_ARGS__  )

#define LOG_INFO(message, ...) LOG("\t[INFO] ", message, __VA_ARGS__)
#define LOG_WARN(message, ...) LOG("\t[WARN] ", message, __VA_ARGS__)

int main(int argc, char** argv)
{
    LOG2("\t[WARN]", "Program started Ok.");
    int sum = 0;
    LOG_INFO("sum = %d", sum);

    for(int n = 0; n < 10; n++)
    {
        sum = n * n;
        LOG_INFO("Iteration k = %d ; sum = %d", n, sum);
    }

    std::fprintf(stdout, " Result => The sum is equal to = %d \n", sum);

    // Requires C++11.
    LOG2("\t[WARN]", "Iterations stopped Ok.");
    return 0;
}

Building and running:

$ >> g++ macro-args.cpp -o macro-args.bin -std=c++1z -Wall -Wextra -g

$ >> ./macro-args.bin 
       [WARN] (file: macro-args.cpp, line: 18) / Program started Ok.
       [INFO]  (file: macro-args.cpp, line: 20) / sum = 0
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 0 ; sum = 0
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 1 ; sum = 1
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 2 ; sum = 4
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 3 ; sum = 9
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 4 ; sum = 16
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 5 ; sum = 25
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 6 ; sum = 36
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 7 ; sum = 49
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 8 ; sum = 64
       [INFO]  (file: macro-args.cpp, line: 25) / Iteration k = 9 ; sum = 81
Result => The sum is equal to = 81 
       [WARN] (file: macro-args.cpp, line: 31) / Iterations stopped Ok.


$ >> ./macro-args.bin 2> /dev/null 
Result => The sum is equal to = 81 

1.4 Do while 0 macro idiom

The do-while-0 macros defined as in the next code block are widely used in low level code such as Linux kernel, embedded systems, lots of C libraries and many other projects. This idiom is useful for creating multi-line macros that works everywhere, including loops and if-else statements where multi line macros would be interpreted in a way not expected by the user.

#define SOMETHING(X) do { /* <<code here>> */} while(0); 

It is usual to define macros with many statements:

#define SOME_MACRO(x) function1((x)) ; function2((x)) 

However, the macro subsititution fails in an if statement:

if(flag)
   SOME_MACRO(x * x + 10);

The intent is to call function1 and function2 if the condition or flag is true and do anything else if the flag is false. However, the macro expands to:

if(flag) 
  function1(x * x + 10); function2(x * x + 10);

// ------- Same as  ------

if(flag){ function1(x * x + 10); } function2(x * x + 10);

If the flag is false, only the function2 is called as the previous code is the same as the next code block.

if(flag){
  function1(x * x + 10); 
}
// Executed regardless if the flag is false or true.
function2(x * x + 10);

The solution is to wrap the function calls into a do { … … } while(0) macro.

#define MACRO_FIX(x) do { function1((x)); function2((x)) } while(0); 

The macro can also be written in a multiline way:

#define MACRO_FIX(x) do { \
                          function1((x)); \
                          function2((x)) \
                         } while(0); 

Note: GCC compile allows replicating the functionality of the do-whil-0 macro idiom with the following syntax: (WARNING: not portable, GCC only)

#define MACRO_SEQUENTIANL1(x) ({ function1((x)); function2((x)); })

#define MACRO_SEQUENTIANL2(x) ({\
                              function1((x));  \
                              function2((x)); \
                             })

Example: do-while-0 macro swaping integer variables.

#define SWAP_INT(a, b) \
   do {                \
        int tmp = (a); \
        (a)     = (b); \
        (b)     = tmp; \
    } while(0)

Summary:

  • Benefits of this idiom:
    • Allows a macro to be used everywhere, including if-else statements.
    • Allows declaring local variables limited to the do-while scope.

1.5 Custom Assertion Macro

1.5.1 Simple assertion macro

Example:

#include <iostream>
#include <cassert>

#define ASSERTION_ENABLED

// Requires header: <cassert>
#ifdef  ASSERTION_ENABLED
  #define ASSERT(condition, text)    \
              { if (!(condition)) {  \
                               std::cerr << " [ASSERTION] " <<  __FILE__ << ":" << __LINE__ << ": " \
                             << text << "\n" ;  \
                               assert(condition);   }}
#else
  #define ASSERT(condition, text)
#endif

int main(){
        int x = 100;
        ASSERT(x > 200, "Assumption: x > 200");

        return 0;
}

When the assertion fails, it prints the message:

g++ scractch.cpp -o scractch.bin -g -std=c++1z -Wall -Wextra && ./scractch.bin
 [ASSERTION] scractch.cpp:33: Assumption: x > 200
scractch.bin: scractch.cpp:33: int main(): Assertion `x > 200' failed.

1.5.2 Improved assertion macro

This assertion macro provides more context information than assert from <cassert> header. When the predicate of an assertion failure happens, this assertion macro prints the file name, line, function and assertion predicate where the failure happened and then terminates the program calling std::terminate.

#include <iostream>

#define ENABLE_ASSERT

#ifdef ENABLE_ASSERT
#define M_ASSERT(expr) \
      { \
         if(!(expr)){ \
            std::cerr << "ASSERTION FAILURE: \n"; \
            std::cerr << " => Condition: " << #expr << "\n"; \
            std::cerr << " =>  Function: " << __FUNCTION__ << "\n"; \
            std::cerr << __FILE__ << ":" << __LINE__ << ":" << "\n"; \
            std::terminate(); \
         } \
      }
#else
#define M_ASSERT(expr)
#endif

Usage:

XMLElement* node = elem->FirstChildElement("CubeX");
M_ASSERT(node != nullptr);

Program output when assertion fails:

... ... ... ... 
ASSERTION FAILURE: 
 => Condition: node != nullptr
 =>  Function: main
tinyxml2-test.cpp:64:
terminate called without an active exception

1.5.3 Type equality assertion macro

Compile-time static assertions that aborts compilation when types are not equal. It is useful for checking assumptions about types at compile-time.

#define ASSERT_TYPE_EQUAL(type, expr) \
   static_assert(std::is_same<type, expr>::value, "Expected type equality")

Usage example:

using iter = std::vector<int>::iterator;

ASSERT_TYPE_EQUAL(std::random_access_iterator_tag,  iter::iterator_category);

ASSERT_TYPE_EQUAL(int ,      iter::value_type );

1.6 Macros for automating boilerplate code

Macros can be used for automating repetitive and boilerplate code such as declaring default constructors, copy constructor, delete copy constructor, move operators and so on.

Some macros for automating construction declaration:

// Define default constructor 
#define CL_CTOR_DEFAULT( className ) \
    public:                          \
    className() = default;           \
    private:

// Makes a class non copiable. 
// Auomates the boilerplate code for 
// declaring a class as non-copiable 
#define CL_NON_COPIABLE( className )                  \
    public:                                           \
    className( className const&) = delete;            \
    className& operator= (className const&) = delete; \
    private:

// Makes a class movable.
// Automates the boilerplate code for 
// declaring default move constructor and 
// and move operator. 
#define CL_CTOR_MOVE_DEFAULT( className )         \
    public:                                       \
    className (className&&) = default;            \
    className& operator= (className&&) = default; \
    private:                                

// Makes a class only movable, but non-copiable. 
#define CL_MOVABLE_ONLY( className )  \
    CL_NON_COPIABLE( className )    \
    CL_CTOR_DEFAULT( className ) 


// Declare default copy constructor explicitly 
#define CL_CTOR_COPY_DEFAULT(className)                      \
    public:                                                  \
       className ( const className & ) = default;            \
       className& operator= ( const className & ) = default; \
    private: \

Declaring a non-copiable (deleted copy constructor and copy-assignment operators) and movable-only:

class Socket
{   
    int fd = -1;

    CL_CTOR_DEFAULT(Socket)
    CL_CTOR_MOVE_DEFAULT(Socket)
    CL_NON_COPIABLE(Socket)
public:
    // ... ...  ... // 
    int get() const { return fd; } 

    ssize_t send(void* buffer, size_t size);  
    ssize_t send(const char* message);
    // ... Placeholder for remaining methods here ... // 
};

Class declared with default move constructors and move-assignment operators.

class Transformation 
{
    float m_x, m_y, m_z, m_w;

    CL_CTOR_COPY_DEFAULT(Transformation)
    CL_CTOR_MOVE_DEFAULT( Transformation )
public:

    float x() const { return m_x; }
    float y() const { return m_y; }
    float z() const { return m_z; }
    // .... ... ... ... // 
};

1.7 Tips and guidelines for writing macros

1.7.1 DO NOT Use macros for defining constants

Unlike in C, in C++ is preferable to use const keyword approach for defining constants instead of preprocessor define macros.

For instance, use:

// PI Number
const double PI = 3.141592653589793; 
// Euler's number 
const double  E = 2.718281828459045;
// Buffer size in bytes 
const size_t BUFFER_SIZE = 1024; 

Instead of:

#define PI 3.141592653589793
#define E  2.718281828459045
#define BUFFER_SIZE 1024

1.7.2 Use parenthesis within macros around parameter names

Reference: PRE01-C. Use parentheses within macros around parameter names - SEI CERT C Coding Standard - Confluence

Example: The following code fails, if the macro argument is an experession such as 2 + 1.

#define CUBE(x) (x * x * x)

So, the result of the followign invokation will be:

// Expected value 81 / 3^3 = 81/27 = 3
int k = 81 / CUBE(2 + 1); 
// Remember the macro just does text substitution. 
int k = 81 / ( 2 + 1 * 2 + 1 * 2 + 1 );
int k = 81 / ( 2 + 2 + 2 + 1 ) = 81/7 = 11;
// Expected k = 3, but got k = 11 
int k = 11;

The correct way to define this macro is to enclose the references to the macro's arguments in its body.

#define CUBE(x) ((x) * (x) * (x))

Now, it works:

int k = 81 / CUBE(2 + 1); 
int k = 81 / ((2 + 1) * (2 + 1) * (2 + 1));
int k = 81 / 27;
int k = 3;

1.7.3 Dump all GCC's preprocessor defines

Reference:

$ gcc -dM -E - < /dev/null
#define __DBL_MIN_EXP__ (-1021)
#define __FLT32X_MAX_EXP__ 1024
#define __UINT_LEAST16_MAX__ 0xffff
#define __ATOMIC_ACQUIRE 2
#define __FLT128_MAX_10_EXP__ 4932
#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F
#define __GCC_IEC_559_COMPLEX 2
#define __UINT_LEAST8_TYPE__ unsigned char
#define __SIZEOF_FLOAT80__ 16
#define __INTMAX_C(c) c ## L
#define __CHAR_BIT__ 8
#define __UINT8_MAX__ 0xff
... ... ... ..
#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL
#define __GCC_ATOMIC_SHORT_LOCK_FREE 2
#define __INT_LEAST64_WIDTH__ 64
#define __UINT_FAST8_TYPE__ unsigned char
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3

1.7.4 Dump all preprocessor macros from a given header file

Reference: g++ - GCC dump preprocessor defines - Stack Overflow

  • GCC (C-Compiler) Dump
$ echo "#include <sys/socket.h>" | gcc -E -dM - | tail -n 10
#define SOL_LLC 268
#define __DBL_MIN_EXP__ (-1021)
#define AF_LLC PF_LLC
#define __FLT32X_MAX_EXP__ 1024
#define AF_MAX PF_MAX
#define __UINT_LEAST16_MAX__ 0xffff
#define __ATOMIC_ACQUIRE 2
#define CMSG_NXTHDR(mhdr,cmsg) __cmsg_nxthdr (mhdr, cmsg)
#define __FLT128_MAX_10_EXP__ 4932
#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F

   ...  ...  ...  ...  ...  ...  ...  ...  ...  ...  ... 

#define __P(args) args
#define PF_LOCAL 1
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3
#define __fsblkcnt_t_defined 
#define _BITS_UIO_H 1
  • G++ (C++ Compiler) Dump
$ echo "#include <cmath>" | gcc -x c++ -std=c++11 -dD -E - | head -n 10
# 1 "<stdin>"
# 1 "<built-in>"
#define __STDC__ 1
#define __cplusplus 201103L
#define __STDC_UTF_16__ 1
#define __STDC_UTF_32__ 1
#define __STDC_HOSTED__ 1
#define __GNUC__ 7
#define __GNUC_MINOR__ 3
#define __GNUC_PATCHLEVEL__ 1

.. ... ... .. ... ... .. ... ... 

$ echo "#include <cmath>" | gcc -x c++ -std=c++11 -dD -E - | tail -n 40
  constexpr float
  tgamma(float __x)
  { return __builtin_tgammaf(__x); }

  constexpr long double
  tgamma(long double __x)
  { return __builtin_tgammal(__x); }



  template<typename _Tp>
    constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                              double>::__type
    tgamma(_Tp __x)
    { return __builtin_tgamma(__x); }



  constexpr float
  trunc(float __x)
  { return __builtin_truncf(__x); }

  constexpr long double
  trunc(long double __x)
  { return __builtin_truncl(__x); }



  template<typename _Tp>
    constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                              double>::__type
    trunc(_Tp __x)
    { return __builtin_trunc(__x); }



}
# 1917 "/usr/include/c++/7/cmath" 3
}
# 1 "<stdin>" 2

1.8 Useful macros for debugging and tracing

Usage: Put this block at the top of the file to debug or log or in a separate header file and compile with the flag -DDEBUG_MODE, for instance. $ g++ file1.cpp fil2.cpp -DDEBUG_MODE

#if defined(DEBUG_MODE)
  #define disp(expr)  std::cerr << __FILE__ << ":" << __LINE__ << ":" \
      << " ; " <<  #expr << " = " << (expr)  <<  std::endl

  #define dbgloc(msg)  std::cerr << __FILE__ << ":" << __LINE__ << ":" << msg 
  #define dbgline __FILE__ << ":" << __LINE__ << ":" <<
  #define dbgtrace(msg) std::cerr << __FILE__ << ":" << __LINE__ << ": TRACING " << msg << "\n";
#else
  #define disp(expr) 
  #define dbgloc(msg)  
  #define dbgline 
  #define dbgtrace(msg) 
#endif 

Note: the program's stdout output is clickable in Emacs which allows to go quickly to the code location that generated the output. To compile and run a c++ program in Emacs use:

$ M-x compile g++ program1.cpp program2.cpp -o out.bin -DDEBUG_MODE && ./out.bin

Macro dbgtrace

The macro dbgtrace creates the message shown in the following code block displaying the file and the line where the message was generated:

Sample usage:

  • dbtrace("invoking copy constructor")

Output example:

gslLinalg.cpp:46: TRACING invoking copy constructor

Macro disp

The macro disp displays any expression in the way it is written, it is useful to create C++ code demonstration and creating proof-of-concept programs.

Sample usage:

  • disp(x * x + 10);

Output example:

math1.cpp:10: ; x * x + 10 = 19

1.9 General Predefined Macros

C++ Provides some useful predefined macros for debugging, logging, compiler identification and detecting the version of C++ standard the compiler is using.

Macro Description Compiler
__LINE__ Contains current line number of the program. all
__FILE__ Name of current file. all
__DATE__ Date in the format month/day/year all
__TIME__ Contains a string in the format hour:minute:second all
     
__cplusplus Contains C++ standard Version string  
     
__FUNCTION__ Print name of current function or method (member function) all
__PRETTY_FUNCTION__ Print name of current function or method with type signature. GGC/G++, Mingw(GCC for Windows) and Clang
__FUNCSIG__ Print name of current function with type signature. MSVC(aka VC++)
     

The macro: __cplusplus is useful for identifying if the code is being compiled with C or C++ compiler and also get the version C++ standard the code is being compiled.

Value of Macro __cplusplus C++ Version
Not defined. N/A the code is being compiled with a C-compiler.
199711L C++98/C++03
201103L C++11
201402L C++14
201703L C++17
N/A C++20

Example:

cout << " time = " << __TIME__
     << " file = " << __FILE__
     << " line = " << __LINE__
     << "  variable  = " << value
     << endl;

1.10 Macros for detecting platform or operating system

The preprocessor macros can be used for cross platform compilation, creating cross platform libraries and isolating platform-specific code.

Macros for detecting Operating System and Platform

Operating System OS Family Macro Description
       
Windows 32 and 64-bits WinNT _WIN32 Defined when compiling on Windows with Msvc(Visual C++) or Gcc
Windows 64 bits WinNT _WIN64 Windows 64 bits.
Windows CE WinCE _WIN32_WCE Windows CE Kernel for embedded systems.
MSDOS   MSDOS or __MSDOS__  
OS2   OS2 or _OS2 or __OS2__ IBM's old OS2 Operating System.
       
Unix-like Unix __unix__ Check whether OS is unix-like (Linux, BSD-variant), Mac OSX)
Linux Unix __linux__ Defined when compiling on Linux with Gcc or Clang
Android Unix __ANDROID__ Android NDK.
MacOSX and IOS (Darwin Kernel) Unix __apple__, __APPLE__, __MACH__ -
BSD Unix __bsd__ -
Free BDS Unix __FreeBSD__  
Net BSD Unix __NetBSD__  
QNX Unix __QNX__  
VxWorks - __VXWORKS__ or __vxworks  
Minix Unix __minix  
NaCL   __native_client__  
AsmJS   __asmjs__  
       
       

Usage example:

void makeDirectory(std::string path){
    #if defined __linux__ || defined __apple__ || defined __bsd__
      mkdir(path.c_str(), 0777);
    #elif _WIN32
      wchar_t* wtext = winUtils::stringToLPWSTR(path);
    CreateDirectoryW(wtext, NULL);
      delete [] wtext;
    #else
      #error "Unknown platform"
    #endif
}

1.11 Macros for detecting compiler

Compiler detection:

Macro Compiler
Compiler  
__GNUC__ GNU C/C++ Compiler.
__MINGW32__ Mingw or GNU C/C++ Compiler ported for Windows NT.
__MINGW64__ Mingw or GNU C/C++ Compiler ported for Windows NT - 64 bits only.
__GFORTRAN__ Fortran / GNU Fortran Compiler
   
__clang__ Clang / LLVM Compiler
   
_MSC_VER Microsoft Visual Studio Compiler MSVC
_MANAGED or __cplusplus_cli Compilation to C++/CLI .NET (CLR) bytecode
   
__INTEL_COMPILER Intel C/C++ Compiler
__PGI or __PGIC__ Portland Group C/C++ Compiler
   
__BORLANDC__ Borland C++ Compiler [DEPRECATED]
   
__EMSCRIPTEN__ emscripten (asm.js - web assembly)
__asmjs__ asm.js
__wasm__ WebAssembly
__NVCC__ NVCC
   
__CLING__ CERN's ROOT Cling C++ Interactive Shell
   
   
C/C++-library  
__GLIBCXX__ Libstdc++
_LBCPP_VERSION LibC++
_MSC_VER MSVC C++ Library (Runtime)
__GLIBC__ GNU LibC runtime
__BIONIC__ Bionic LibC runtime. (Android's C-library modified from BSD)
   
   

See also:

1.12 Macros for detecting architecture

The following pre-defined macros are useful for checking the architecture which the current application is being compiled. This compile-time checking allows dealing with ISA specific (ISA Instruction-set Architecture) features such as SIMD instructions, inline-assembly and sizes in bytes of fundamental data types.

Architecture Macro
Intel x86  
x86 _M_IX86 ; __INTEL__ ; __i386__
   
Intel or AMD X86-64 (64 bits)  
AMD64 (x86-64) __amd__64__
AMD64 __amd_64
AMD64 __x86_64__
AMD64 __x86_64
Intel Itanium 64 bits __IA64__ , __ia64__
ARM Core  
ARM (general) __arm__ , _ARM, _M_ARM, M_ARMT
ARM thumb extension __thumb__
ARM 2 CPU __ARM_ARCH_2__
ARM 3 CPU __ARM_ARCH_3__
ARM 4T CPU __ARM_ARCH_4T__
ARM 5 CPU __ARM_ARCH_5__
ARM 5T CPU __ARM_ARCH_5T__
ARM 6 CPU __ARM_ARCH_6__
ARM 7 CPU __ARM_ARCH_7__
ARM 7 CPU __ARM_ARCH_7A__
ARM 7 CPU __ARM_ARCH_7R__
ARM 7 CPU __ARM__ARCH_7M__
ARM 7 CPU __ARM_ARCH_7S__
   
ARM64 (ARM 64 bits ) __aarch64__
   
PowerPC  
PowerPC core __powerpc ; __powerpc__ ; __POWERPC__ ; _M_PPC
PowerPC core __powerpc64__
SuperH  
SuperH core __sh__ ; __sh1__ ; __sh2__ ; __sh3__
SuperH core __SH3__ ; __SH4__ ; __SH5__
   

Further reading:

1.13 Macros for checking whether the compiler is 32 (x86) or 64 bits (x86-64)

The following macros, taken from (SO 1505582), are useful for checking whether the compiler is 32 bits (Intel x86 based-processor) or 64 bits (Intel x86-64 based processor).

Macros:

// Check windows
#if _WIN32 || _WIN64
   #if _WIN64
     #define ENV64BIT
  #else
    #define ENV32BIT
  #endif
#endif

// Check GCC
#if __GNUC__
  #if __x86_64__ || __ppc64__
    #define ENV64BIT
  #else
    #define ENV32BIT
  #endif
#endif

Sample usage:

#if defined(ENV64Bits)
    std::cout << " [TRACE] 64 Bits - x86_64 " << std::endl;
#else 
    std::cout << " [TRACE] 32 Bits - x86" << std::endl;
#endif

Created: 2021-08-12 Thu 09:16

Validate