宏定义与判断
主流的 C/C++ 编译器会预定义一些特定的宏,以帮助开发者检查和判断程序的运行环境,包括但不限于 所使用的编译器
、目标操作系统
、硬件架构
,以及 所需的运行库
等。根据编译目标环境的不同, 编译器会自动启用或禁用这些预定义宏,从而令开发者在源代码中使用的 #ifdef
或 #if
等宏判断语句在预处理的过程中进入不同的分支。
C/C++ 源文件中,以宏作为判断条件的宏分支语句主要包括以下形式:
#ifdef __ARCH
#ifndef __ARCH__
#elifdef __ARCH // Since C++ 23
#elifndef __ARCH__ // Since C++ 23
#if defined(__ARCH)
#elif defined(__ARCH__)
#if __ARCH
#elif __ARCH__
其中,若宏分支语句的条件或分支块中出现了以下情形的宏,则可以认为它们属于 架构相关宏:
- 编译器预定义的
硬件架构相关宏
,通常有__架构名
和__架构名__
两种形式 - 在编译器预定义的
硬件架构相关宏
作为条件的宏分支语句下,通过#define
语句自定义的宏
其中,编译器预定义的 硬件架构相关宏
通常可在 附录:主流编译器提供的硬件架构相关预定义宏 所提供的清单中找到。 后者则需检查所有使用编译器预定义的 硬件架构相关宏
作为条件的宏分支语句块, 追踪这些语句块下自定义宏的 定义 过程,以及在源代码上下文中的 使用 过程。
架构相关宏
以下代码片段中,展示的是架构相关宏判定标准。 只要分支外部层级结构中出现了任一 架构相关宏, 则分支内部定义的所有宏都认为是 架构相关宏。
#if defined(__CUSTOM) // 非架构相关宏
#define CUSTOM_MACRO // 非架构相关宏
#ifdef __mips__ // 编译器预定义的架构相关宏
#define CUSTOM_ARCH_MACRO_1 // 自定义的架构相关宏
#endif
#endif
#ifdef __x86_64__ // 编译器预定义的架构相关宏
#define CUSTOM_ARCH_MACRO_1 // 自定义的架构相关宏
#if defined(__xxx_CPU_FEATURE__) // 非架构相关宏
#define CUSTOM_ARCH_MACRO_2 // 自定义的架构相关宏
#endif
#elifdef __arm__ // 编译器预定义的架构相关宏
#ifndef __xxx_LIB // 非架构相关宏
#define NOT_USE_xxx_LIB // 自定义的架构相关宏
#endif
#else
#define UNK_ARCH // 自定义的架构相关宏
#endif
附录:主流编译器提供的硬件架构相关预定义宏
Alpha
宏类型 | 宏名称 | 宏描述 |
---|---|---|
标识符 | __alpha__ | 由 GNU C 定义 |
版本号 | __alpha_ev{V}__ | 由 GNU C 定义,其中 {V} 表示版本号。参见 示例 |
标识符 | __alpha __ALPHA __Alpha_AXP | 由 DEC C 定义 |
标识符 | _M_ALPHA | 由 Visual Studio 定义 |
__alpha_ev{V}__
宏示例
CPU | 宏名称 |
---|---|
Alpha EV4 | __alpha_ev4__ |
Alpha EV5 | __alpha_ev5__ |
Alpha EV6 | __alpha_ev6__ |
AMD64
宏类型 | 宏名称 | 宏描述 |
---|---|---|
标识符 | __amd64__ __amd64 __x86_64__ __x86_64 | 由 GNU C 和 Sun Studio 定义 |
标识符 | _M_X64 _M_AMD64 | 由 Visual Studio 定义 |
提示
若要检查目标平台是否为 32 位,可检查是否使用了 ILP32 数据模型。
ARM
宏类型 | 宏名称 | 宏描述 |
---|---|---|
标识符 | __arm__ | 由 GNU C 和 ARM 定义 |
标识符 | __thumb__ | 由 GNU C 和 ARM (Thumb 模式) 定义 |
版本号 | __ARM_ARCH_{V}__ | 由 GNU C 定义 |
版本号 | __TARGET_ARCH_ARM = V __TARGET_ARCH_THUMB = V | 由 ARM 定义,架构版本与该宏值 V 的对应关系参见 此表 |
版本号 | __TARGET_ARCH_{V}{R} | 由 ARM 定义,其中 具体值与编译参数 |
版本号 | __TARGET_CPU_{MODEL} | 由 ARM 定义,其中 具体值与编译参数
具体示例参见 此表 |
标识符 | _ARM | 由 ImageCraft C 定义 |
标识符 | __arm | 由 Diab 定义 |
标识符 | _M_ARMT | 由 Visual Studio (Thumb 模式) 定义 |
版本号 | _M_ARM = V | 由 Visual Studio 定义,其中 V 为 ARM 架构主版本号 |
__TARGET_ARCH_ARM/THUMB 宏与 ARM 架构版本对应关系
ARM 架构版本 | __TARGET_ARCH_ARM | __TARGET_ARCH_THUMB |
---|---|---|
v4 | 4 | 0 |
v4T | 4 | 1 |
v5T, v5TE, v5TEJ | 5 | 2 |
v6, v6K, v6Z | 6 | 3 |
v6T2 | 6 | 4 |
v6-M, v6S-M | 0 | 3 |
v7-A, v7-R | 7 | 4 |
v7-M, v7E-M | 0 | 4 |
v8-A, v8-R | 8 | 5 |
v8-M, v8E-M | 0 | 5 |
v9-A | 9 | 6 |
__TARGET_ARCH_XX 宏与 --cpu 编译参数对应关系
--cpu 参数对应家族 | 对应 __TARGET_ARCH_XX 宏名称 | 描述 |
---|---|---|
4 | __TARGET_ARCH_4 | ARMv4 without Thumb |
4T | __TARGET_ARCH_4T | ARMv4 with Thumb |
5T | __TARGET_ARCH_5T | ARMv5 with Thumb and interworking |
5TE | __TARGET_ARCH_5TE | ARMv5 with Thumb, interworking, DSP multiply, and double-word instructions |
5TEJ | __TARGET_ARCH_5TEJ | ARMv5 with Thumb, interworking, DSP multiply, double-word instructions, and Jazelle extensions |
6 | __TARGET_ARCH_6 | ARMv6 with Thumb, interworking, DSP multiply, double-word instructions, unaligned and mixed-endian support, Jazelle, and media extensions. |
6-M | __TARGET_ARCH_6_M | ARMv6 microcontroller profile with Thumb only, plus processor state instructions. |
6S-M | __TARGET_ARCH_6S_M | ARMv6 microcontroller profile with Thumb only, plus processor state instructions and OS extensions. |
6K | __TARGET_ARCH_6K | ARMv6 with SMP extensions. |
6T2 | __TARGET_ARCH_6T2 | ARMv6 with Thumb (Thumb-2 technology). |
6Z | __TARGET_ARCH_6Z | ARMv6 with Security Extensions. |
7 | __TARGET_ARCH_7 | ARMv7 with Thumb (Thumb-2 technology) only, and without hardware divide. |
7-A | __TARGET_ARCH_7_A | ARMv7 application profile. |
7-A.security | __TARGET_ARCH_7_A | ARMv7-A architecture profile with the SMC instruction (formerly SMI). |
7-R | __TARGET_ARCH_7_R | ARMv7 real-time profile. |
7-M | __TARGET_ARCH_7_M | ARMv7 microcontroller profile. |
7E-M | __TARGET_ARCH_7E_M | ARMv7-M architecture profile with DSP extension. |
8-A.32 | __TARGET_ARCH_8_A | ARMv8, AArch32 state |
8-A.32.crypto | __TARGET_ARCH_8_A | ARMv8, AArch32 state with cryptographic instructions |
8-A.32.no_neon | __TARGET_ARCH_8_A | ARMv8, AArch32 state without Advanced SIMD instructions |
8-A.64 | __TARGET_ARCH_8_A | ARMv8, AArch64 state |
8-A.64.crypto | __TARGET_ARCH_8_A | ARMv8, AArch64 state with cryptographic instructions |
8-A.64.no_neon | __TARGET_ARCH_8_A | ARMv8, AArch64 state without Advanced SIMD instructions |
9-A | __TARGET_ARCH_9_A | ARMv9 |
__TARGET_CPU_XX 宏示例
ARM CPU 型号 | __TARGET_CPU_XX 宏名称 |
---|---|
ARM7TM | __TARGET_CPU_ARM7TM |
Cortex-R4 | __TARGET_CPU_CORTEX_R4 |
Neoverse-N1 | __TARGET_CPU_NEOVERSE_N1 |
ARM64
宏类型 | 宏名称 | 宏描述 |
---|---|---|
标识符 | __aarch64__ | 由 GNU C 定义 |
Intel x86
宏类型 | 宏名称 | 宏描述 |
---|---|---|
标识符 | i386 __i386__ | 由 GNU C 定义 |
版本号 | __i386__ __i486__ __i586__ __i686__ | 由 GNU C 定义 |
标识符 | __i386 | 由 GNU C、Sun Studio 和 Stratus VOS C 定义 |
标识符 | __IA32__ | 由 Stratus VOS C 定义 |
标识符 | __X86__ | 由 Watcom C/C++ 定义 |
标识符 | _X86_ | 由 MinGW32 定义 |
标识符 | __THW_INTEL__ | 由 XL C/C++ 定义 |
版本号 | __I86__ = V | 由 Digital Mars 定义,其中 V 为表示指令集版本号的整数,范围为 [3, 6] ,具体值参见 示例 |
标识符 | __INTEL__ | 由 CodeWarrior 定义 |
标识符 | __386 | 由 Diab 定义 |
标识符 | _M_I86 | 由 Visual Studio、Digital Mars 及 Watcom C/C++ 定义,仅在 16 位架构中定义 |
标识符 | _M_IX86 = {V}00 | 由 Visual Studio、Intel C/C++、Digital Mars 及 Watcom C/C++ 定义,具体值参见 示例 仅在 32 位架构中定义,其中 {V} 为表示指令集版本号的整数,范围为 [3, 6] |
提示
Watcom C/C++ 在 16 位和 32 位架构下,均定义了宏 _M_IX86
宏。在这种情况下,可通过 __386__
及 _M_I386
宏用于确定是否为 32 位架构。
_M_IX86 及 __I86__ 宏示例
CPU 型号 | _M_IX86 宏名称及具体值 | __I86__ 宏具体值 |
---|---|---|
80386 | _M_I386 = 300 | 3 |
80486 | _M_I486 = 400 | 4 |
Pentium | _M_I586 = 500 | 5 |
Pentium Pro/II | _M_I686 = 600 | 6 |
RISC-V
宏类型 | 宏名称 | 宏描述 |
---|---|---|
标识符 | __riscv | 由 GNU C 定义 |