【问题标题】:Detecting CPU architecture compile-time检测 CPU 架构编译时
【发布时间】:2010-09-14 04:48:09
【问题描述】:

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

是否有一种标准方法来检测我正在构建的架构?如果没有,是否有各种编译器的此类定义的完整列表的来源,例如带有所有样板文件的标头 #ifdefs?

【问题讨论】:

标签: c++ c detection cpu-architecture compile-time


【解决方案1】:

有一个#defines here 的列表。之前有一个高度投票的答案包含此链接,但可能是由于 SO 的“答案必须有代码”规则而被 mod 删除。所以这里是一个随机样本。点击链接查看完整列表。

AMD64

Type Macro Description
Identification __amd64__ __amd64 __x86_64__ __x86_64 Defined by GNU C and Sun Studio
Identification _M_X64 _M_AMD64 Defined by Visual Studio

【讨论】:

  • 32 位的呢?我可以检测适用于 MSVC、GCC 和 Clang 的 32 位和 64 位 x86 的最短方法是什么?
  • 您可以使用该页面上列出的AMD64Intel x86 宏的组合。但你几乎肯定不应该。请改用sizeof()static_assert 等。您还应该了解 x32 ABI。即使在 64 位架构上,指针也可以是 32 位的。
【解决方案2】:

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

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

【讨论】:

  • 您的 ARM 字符串将 ARM CPU 名称(如 ARM7)与 ARM ISA 修订版(如 ARMv7)混在一起。
  • 用正确的 arm7 版本更新了帖子。以及正确的powerpc64检测
  • 我的意思是你应该返回 "ARMv7""ARMv7A" 或其他什么时返回 "ARM7"。 “v”在 ARM 中很重要,它可以区分特定的 ARM 内核模型与 ISA 版本之间的区别。请记住,查看打印此字符串的程序的人只会在他们的机器上看到一个字符串,而不是整个表都清楚地表明它可能是“ARM6T2”(这更清楚地只是 ARMv6T2 的损坏,而不是 CPU型号。)
【解决方案3】:

如果您想转储特定平台上的所有可用功能,您可以像这样运行 GCC:

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

它会转储#define __SSE3__ 1#define __AES__ 1 等宏。

【讨论】:

  • -march=native 对于 GCC 4.9 及更低版本的 ARM 和 MIPS 失败。
【解决方案4】:

如果你想要一个交叉编译器解决方案,那么只需使用 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(单指令多数据)检测。

例如

#if defined(BOOST_ARCH_X86)
    #if BOOST_ARCH_X86_64
        std::cout << "x86_64 " << BOOST_ARCH_X86_64 << " \n";
    #elif BOOST_ARCH_X86_32
        std::cout << "x86 " << BOOST_ARCH_X86_32 << " \n";
    #endif
#elif defined(BOOST_ARCH_ARM)
    #if _M_ARM
        std::cout << "ARM " << _M_ARM << " \n";
    #elif _M_ARM64
        std::cout << "ARM64 " << _M_ARM64 << " \n";
    #endif
#endif

您可以了解更多关于如何使用它here

【讨论】:

    【解决方案5】:

    没有标准。 Brian Hook 在他的“Portable Open Source Harness”中记录了其中的一堆,甚至试图将它们变成连贯且可用的东西(ymmv 关于这一点)。请参阅本网站上的 posh.h 标头:

    请注意,由于前段时间遭到 DOS 攻击,上述链接可能要求您输入一些虚假的用户名/密码。

    【讨论】:

    • 天哪 - 对虚假链接感到抱歉 - 应该是 hookatooka.com/poshlib 提供有关用户 ID/密码的信息。我的浏览器必须在以前访问该页面时“自动登录”。
    • 这也是值得注意的...该网站的作者说明了他们添加密码的原因:“对于给您带来的不便,我深表歉意,但由于我们之前的直接链接遭到了莫名其妙的 DDoS 攻击,我们不得不创建此页面来“缓冲” DDoS...” 我不确定是否为此惩罚 Michael。
    【解决方案6】:

    如果您需要对 CPU 功能进行细粒度检测,最好的方法是同时发布一个 CPUID 程序,该程序将 CPU 支持的一组功能输出到 stdout 或某些“cpu_config.h”文件。然后将该程序与构建过程集成。

    【讨论】:

    • 不适用于交叉编译。除非你知道它需要在哪台机器上运行,否则你如何编译一个 cpuid 程序?
    【解决方案7】:

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

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

    一个完整的列表没有什么意义,因为有成千上万的编译器,但只有 3-4 个被广泛使用(Microsoft C++、GCC、Intel CC,也许是 TenDRA?)。只需决定您的应用程序将支持哪些编译器,列出它们的#defines,并根据需要更新您的标头。

    【讨论】:

    • 这对我在 Visual Studio 2010 上不起作用。_M_X86 肯定没有定义(32 位版本)。正确的是_M_IX86(感谢上面 Serge 的链接)。
    • 这些是否适用于 32 位和 64 位 x86?
    猜你喜欢
    • 2011-02-05
    • 2012-12-19
    • 2018-12-01
    • 2011-01-02
    • 2014-12-08
    • 2014-09-01
    • 2011-03-27
    • 2011-06-05
    相关资源
    最近更新 更多