Detecting CPU architecture compile-time

There's no inter-compiler standard, but each compiler tends to be quite consistent. You can build a header for yourself that's something like this:

#if MSVC
#ifdef _M_X86
#define ARCH_X86
#endif
#endif

#if GCC
#ifdef __i386__
#define ARCH_X86
#endif
#endif

There's not much point to a comprehensive list, because there are thousands of compilers but only 3-4 in widespread use (Microsoft C++, GCC, Intel CC, maybe TenDRA?). Just decide which compilers your application will support, list their #defines, and update your header as needed.


Enjoy, I was the original author of this.

extern "C" {
    const char *getBuild() { //Get current architecture, detectx nearly every architecture. Coded by Freak
        #if defined(__x86_64__) || defined(_M_X64)
        return "x86_64";
        #elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
        return "x86_32";
        #elif defined(__ARM_ARCH_2__)
        return "ARM2";
        #elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
        return "ARM3";
        #elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARM_4T)
        return "ARM4T";
        #elif defined(__ARM_ARCH_5_) || defined(__ARM_ARCH_5E_)
        return "ARM5"
        #elif defined(__ARM_ARCH_6T2_) || defined(__ARM_ARCH_6T2_)
        return "ARM6T2";
        #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
        return "ARM6";
        #elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7";
        #elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7A";
        #elif defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7R";
        #elif defined(__ARM_ARCH_7M__)
        return "ARM7M";
        #elif defined(__ARM_ARCH_7S__)
        return "ARM7S";
        #elif defined(__aarch64__) || defined(_M_ARM64)
        return "ARM64";
        #elif defined(mips) || defined(__mips__) || defined(__mips)
        return "MIPS";
        #elif defined(__sh__)
        return "SUPERH";
        #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
        return "POWERPC";
        #elif defined(__PPC64__) || defined(__ppc64__) || defined(_ARCH_PPC64)
        return "POWERPC64";
        #elif defined(__sparc__) || defined(__sparc)
        return "SPARC";
        #elif defined(__m68k__)
        return "M68K";
        #else
        return "UNKNOWN";
        #endif
    }
}

If you want a cross-compiler solution then just use Boost.Predef which contains

  • BOOST_ARCH_ for system/CPU architecture one is compiling for.
  • BOOST_COMP_ for the compiler one is using.
  • BOOST_LANG_ for language standards one is compiling against.
  • BOOST_LIB_C_ and BOOST_LIB_STD_ for the C and C++ standard library in use.
  • BOOST_OS_ for the operating system we are compiling to.
  • BOOST_PLAT_ for platforms on top of operating system or compilers.
  • BOOST_ENDIAN_ for endianness of the os and architecture combination.
  • BOOST_HW_ for hardware specific features.
  • BOOST_HW_SIMD for SIMD (Single Instruction Multiple Data) detection.

Note that although Boost is usually thought of as a C++ library, Boost.Predef is pure header-only and works for C

For example

#include <boost/predef.h>
// or just include the necessary headers
// #include <boost/predef/architecture.h>
// #include <boost/predef/other.h>

#if BOOST_ARCH_X86
    #if BOOST_ARCH_X86_64
            std::cout << "x86-64\n";
    #elif BOOST_ARCH_X86_32
            std::cout << "x86-32\n";
    #else
            std::cout << "x86-" << BOOST_ARCH_WORD_BITS << '\n'; // Probably x86-16
    #endif
#elif BOOST_ARCH_ARM
    #if BOOST_ARCH_ARM >= BOOST_VERSION_NUMBER(8, 0, 0)
        #if BOOST_ARCH_WORD_BITS == 64
            std::cout << "ARMv8+ Aarch64\n";
        #elif BOOST_ARCH_WORD_BITS == 32
            std::cout << "ARMv8+ Aarch32\n";
        #else
            std::cout << "Unexpected ARMv8+ " << BOOST_ARCH_WORD_BITS << "bit\n";
        #endif
    #elif BOOST_ARCH_ARM >= BOOST_VERSION_NUMBER(7, 0, 0)
            std::cout << "ARMv7 (ARM32)\n";
    #elif BOOST_ARCH_ARM >= BOOST_VERSION_NUMBER(6, 0, 0)
            std::cout << "ARMv6 (ARM32)\n";
    #else
            std::cout << "ARMv5 or older\n";
    #endif
#elif BOOST_ARCH_MIPS
    #if BOOST_ARCH_WORD_BITS == 64
            std::cout << "MIPS64\n";
    #else
            std::cout << "MIPS32\n";
    #endif
#elif BOOST_ARCH_PPC_64
            std::cout << "PPC64\n";
#elif BOOST_ARCH_PPC
            std::cout << "PPC32\n";
#else
            std::cout << "Unknown " << BOOST_ARCH_WORD_BITS << "-bit arch\n";
#endif

You can find out more on how to use it here

Demo on Godbolt


If you would like to dump all available features on a particular platform, you could run GCC like:

gcc -march=native -dM -E - </dev/null

It would dump macros like #define __SSE3__ 1, #define __AES__ 1, etc.