检测CPU架构编译时

Ale*_*x B 76 c c++ cpu-architecture detection compile-time

在编译C或C++代码时,找出CPU架构最可靠的方法是什么?据我所知,不同的编译器有自己的一套非标准预处理器定义(_M_X86在MSVS中__i386__,__arm__在GCC 中等).

有没有一种标准的方法来检测我正在构建的架构?如果没有,是否有各种编译器的这种定义的综合列表的来源,例如包含所有样板#ifdef的标题?

Ser*_*rge 73

以下是有关预定义体系结构宏和其他类型的预定义宏的一些信息.

这个问题询问它们在GCC源代码中的定义.


小智 39

享受吧,我是这个的原作者。

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我的意思是,当您应该返回“ARMv7”或“ARMv7A”或其他内容时,您会返回“ARM7”。在 ARM 中,“v”对于区分特定 ARM 内核模型与 ISA 版本之间的差异非常重要。请记住,查看打印此字符串的程序的人只会在他们的计算机上看到一个字符串,而不是整个表格,清楚地表明它可能是“ARM6T2”(更明显的是,这只是 ARMv6T2 的损坏,而不是 CPU型号。) (6认同)
  • 您的 ARM 字符串将 ARM CPU 名称(如 [ARM7](https://en.wikipedia.org/wiki/ARM7))与 ARM ISA 修订版(如 [ARMv7](https://en.wikipedia.org/wiki/Comparison_of_ARMv7) 混合在一起) -A_核心)。 (3认同)

Joh*_*kin 15

没有编译器间标准,但每个编译器都趋于相当一致.您可以为自己构建一个标题,如下所示:

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

#if GCC
#ifdef __i386__
#define ARCH_X86
#endif
#endif
Run Code Online (Sandbox Code Playgroud)

没有太多指向全面的列表,因为有数千个编译器,但只有3-4个被广泛使用(Microsoft C++,GCC,Intel CC,可能是TenDRA?).只需确定您的应用程序将支持哪些编译器,列出其#defines,并根据需要更新标头.

  • 这在Visual Studio 2010上对我不起作用."_M_X86"肯定没有定义(32位构建).正确的是`_M_IX86`(归功于Serge上面的链接). (2认同)

phu*_*clv 13

如果您想要一个交叉编译器解决方案,那么只需使用Boost.Predef包含

  • BOOST_ARCH_对于正在编译的系统/CPU 架构。
  • BOOST_COMP_对于正在使用的编译器。
  • BOOST_LANG_对于编译所依据的语言标准。
  • BOOST_LIB_C_以及BOOST_LIB_STD_正在使用的 C 和 C++ 标准库。
  • BOOST_OS_对于我们正在编译的操作系统。
  • BOOST_PLAT_适用于操作系统或编译器之上的平台。
  • BOOST_ENDIAN_用于操作系统和体系结构组合的字节顺序。
  • BOOST_HW_对于硬件特定功能。
  • BOOST_HW_SIMD用于SIMD(单指令多数据)检测。

请注意,虽然 Boost 通常被认为是一个 C++ 库,但Boost.Predef它是纯头文件并且适用于 C

例如

#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
Run Code Online (Sandbox Code Playgroud)

您可以在此处了解有关如何使用它的更多信息

Godbolt 上的演示


Wei*_*hen 5

如果要在特定平台上转储所有可用功能,则可以运行GCC,如下所示:

gcc -march=native -dM -E - </dev/null
Run Code Online (Sandbox Code Playgroud)

这将转储像宏#define __SSE3__ 1#define __AES__ 1等等。


Mic*_*urr 4

没有什么标准。Brian Hook 在他的“Portable Open Source Harness”中记录了其中的一些内容,甚至尝试将它们变成连贯且可用的东西(ymmv 对此)。请参阅他的存储库中的 posh.h 标头:

  • Jeez - 对于虚假链接感到抱歉 - 它应该是 http://hookatooka.com/poshlib/ ,它提供了有关用户 ID/密码的信息。我的浏览器必须在之前访问该页面时“自动登录”。 (2认同)
  • 还值得注意的是......该网站的作者说明了他们添加密码的原因:*“对于给您带来的不便,我深表歉意,但由于我们之前的直接链接遭受了莫名其妙的 DDoS 攻击,我们不得不创建此页面来针对 DDoS 的“缓冲”...”* 我不确定因此惩罚 Michael 是否公平。 (2认同)