sizeof(void*) 最直接可靠地反映编译目标指针大小:4 表示 32 位(ILP32),8 表示 64 位(LP64/ILP64);其值在编译期确定,不可用于运行时判断,预处理需用 LP64 或 _WIN64 等宏。

用 sizeof(void*) 最直接可靠
系统指针大小由编译目标决定,不是运行时动态变化的。所以不需要查操作系统 API 或读取环境变量,sizeof(void*) 在编译期就确定了,且语义最准确——它就是指针类型的字节数。
常见错误是用 sizeof(int) 或 sizeof(long) 判断,但它们在不同平台下不一致:int 通常是 4 字节(即使在 64 位 Windows/Linux),long 在 Windows 上仍是 4 字节(LLP64),Linux/macOS 是 8 字节(LP64),完全不可靠。
-
sizeof(void*) == 4→ 编译目标为 32 位(ILP32) -
sizeof(void*) == 8→ 编译目标为 64 位(LP64 或 ILP64) - 这个值在预处理阶段就能用,比如
#if sizeof(void*) == 8(注意:实际预处理器不支持sizeof,需改用__LP64__等宏,见下一条)
预编译宏判断更适用于条件编译
如果要在头文件里写 #ifdef 分支(比如声明不同大小的句柄类型),不能依赖 sizeof,得用编译器内置宏:
- Clang/GCC/MSVC 都支持
__LP64__(仅 64 位 Unix-like 系统) - 更通用的是
__x86_64__、_M_X64(表示目标架构是 x86-64),但 ARM64 下不适用 - 最稳妥的组合:
#if defined(__LP64__) || defined(_WIN64)—— 覆盖主流 64 位 Windows 和类 Unix 环境 - MSVC 还提供
_M_AMD64和_M_ARM64,GCC/Clang 有__aarch64__
别用 WIN32 或 _WIN32 判断位数——它们在 64 位 Windows 上依然定义,只表示 Windows 平台,不反映指针宽度。
立即学习“C++免费学习笔记(深入)”;
运行时获取毫无意义,也做不到
有人想调用 GetNativeSystemInfo(Windows)或 uname(Linux)来“检测系统位数”,这是误解:一个 32 位程序在 64 位系统上跑,void* 仍是 4 字节;反之,64 位程序无法在纯 32 位系统启动。所谓“系统位数”对进程来说没有独立存在意义,只有“当前进程的指针大小”才是唯一有效的事实。
- 试图用
sizeof在运行时做分支(比如 if (sizeof(void*) == 8))是无效的——该表达式是常量,编译器会直接优化掉另一分支 - 没有标准 C++ 接口能返回“当前 OS 支持的最大地址宽度”,那不属于语言范畴
结构体对齐和指针混用时容易出错
当你把指针存进固定大小字段(比如 uint32_t 或 uintptr_t),位数不匹配会导致截断或填充异常。例如:
uintptr_t p = reinterpret_cast<uintptr_t>(&x); // 在 64 位下 p 可能 > 0xFFFFFFFF,若强制存进 uint32_t 就丢高 32 位
所以跨平台代码中必须:
- 用
uintptr_t/intptr_t存指针整数值,它们保证能容纳指针 - 避免手动拆解指针到
uint32_t[2]等数组——除非你明确在做序列化且控制两端 ABI - 结构体中含指针成员时,注意
offsetof和内存布局在 32/64 位下可能不同(尤其涉及#pragma pack)
真正要警惕的不是“怎么判断”,而是后续所有基于指针大小的假设是否被无意识打破——比如硬编码偏移、误用固定宽度整型、或忽略 size_t 与 int 的差异。


















