应使用预定义宏而非sizeof(void*)判断目标架构,因后者仅反映当前程序指针大小,无法准确标识系统原生能力;常见宏包括_WIN64、__x86_64__、__aarch64__等,需按编译器区分使用。

用预定义宏判断目标架构,不是运行时检测
编译时就能确定的架构信息,必须靠预处理器宏,而不是运行时查系统。因为 sizeof(void*) 返回的是**当前程序的指针大小**,不是宿主系统的——32 位程序在 64 位 Windows(WoW64)下跑,sizeof(void*) 仍是 4。
常见宏组合如下:
-
_WIN64:仅在 MSVC 编译 64 位 Windows 程序时定义;_WIN32在所有 Windows 目标上都定义(含 64 位) -
__x86_64__或__amd64__:GCC/Clang 下 x86-64 目标 -
__aarch64__:ARM64(如 Apple Silicon、ARM Linux) -
__arm__且__ARM_ARCH_7A__或更高:32 位 ARM -
__LP64__:表示long和指针为 64 位,macOS/Linux 常见,但 Windows 不用该宏
别混用:_M_X64 是 MSVC 专用,__x86_64__ 是 GCC/Clang 专用,两者不互通。
为什么不能只靠 sizeof(void*) 判断系统位数
它只能告诉你「这个二进制是几字节指针」,即你编译出的目标平台,而非当前机器是否原生支持 64 位。
立即学习“C++免费学习笔记(深入)”;
典型误判场景:
- 在 64 位 Windows 上用
cl /O2 /MD编译(默认 32 位),sizeof(void*) == 4→ 误以为系统是 32 位 - 交叉编译 ARM64 固件到 Cortex-M3 开发板(实际是 32 位 MCU),
sizeof(void*) == 4,但若你错误假设「等于 4 就是 x86_32」,就完全错乱 - 某些裸机或 RTOS 环境中,ABI 可能自定义指针长度,
sizeof(void*)不再具有跨平台语义
所以,sizeof(void*) == 8 只能安全推出「本程序是 64 位目标」,不能反推「系统是 64 位」。
跨平台检测模板:Windows/macOS/Linux/ARM 一把抓
下面这段代码可直接复制进 .cpp 文件,在主流编译器下无警告工作:
#include <iostream>
void detect_arch() {
#if defined(_WIN64)
std::cout << "Windows x64" << std::endl;
#elif defined(_WIN32)
std::cout << "Windows x86" << std::endl;
#elif defined(__APPLE__) && defined(__LP64__)
std::cout << "macOS x64 or ARM64" << std::endl;
#elif defined(__APPLE__) && !defined(__LP64__)
std::cout << "macOS i386 (legacy)" << std::endl;
#elif defined(__linux__)
#if defined(__x86_64__)
std::cout << "Linux x64" << std::endl;
#elif defined(__aarch64__)
std::cout << "Linux ARM64" << std::endl;
#elif defined(__arm__)
std::cout << "Linux ARM32" << std::endl;
#else
std::cout << "Linux other" << std::endl;
#endif
#else
std::cout << "Unknown platform" << std::endl;
#endif
}
注意:__aarch64__ 和 __arm__ 互斥,不会同时定义;ARM32 下一般还有 __ARM_ARCH_7A__ 等子版本宏,但架构判定到 32/64 级已够用。
交叉编译和嵌入式环境的特殊处理
在 CMake 或裸机开发中,你往往需要在编译前就知道目标架构,而不是等运行时。这时不能依赖任何 C++ 运行逻辑。
推荐做法是让构建系统注入宏:
- CMake 中用
target_compile_definitions(my_target PRIVATE ARCH_IS_ARM64) - 手动编译时加
-DARCH_IS_AARCH64,然后在代码里#if defined(ARCH_IS_AARCH64) - 避免在头文件里写
sizeof(void*)判定并导出为常量——它会被编译器内联成固定值,换平台重编译前不会更新
最易被忽略的一点:ARM64 和 AArch64 是同义词,但 __aarch64__ 是 GCC/Clang 标准宏,_M_ARM64 是 MSVC 专用,二者不可混用;若写跨编译器代码,必须分开 #ifdef 分支。


















