C语言数据类型跨平台差异总表
一、主要数据模型总览
| 数据模型 |
int |
long |
long long |
指针 |
典型平台 |
| IP16 |
2 |
4 |
- |
2 |
16位DOS、嵌入式8位系统 |
| LP32 |
2 |
4 |
- |
4 |
早期Unix(V7)、部分嵌入式 |
| ILP32 |
4 |
4 |
8 |
4 |
现代32位系统、Windows 64位(long=4) |
| LP64 |
4 |
8 |
8 |
8 |
Linux/macOS/Unix 64位 |
| LLP64 |
4 |
4 |
8 |
8 |
Windows 64位 |
| ILP64 |
8 |
8 |
8 |
8 |
Cray超级计算机 |
| SILP64 |
8 |
8 |
8 |
8 |
实验性系统 |
二、现代操作系统具体类型大小对比(字节)
| 数据类型 |
32位Linux |
64位Linux |
32位Windows |
64位Windows |
macOS ARM64 |
嵌入式8/16位 |
| char |
1 |
1 |
1 |
1 |
1 |
1 |
| short |
2 |
2 |
2 |
2 |
2 |
2 |
| int |
4 |
4 |
4 |
4 |
4 |
2 |
| long |
4 |
8 |
4 |
4 |
8 |
4 |
| long long |
8 |
8 |
8 |
8 |
8 |
8 |
| float |
4 |
4 |
4 |
4 |
4 |
4 |
| double |
8 |
8 |
8 |
8 |
8 |
8 |
| void* |
4 |
8 |
4 |
8 |
8 |
2-3 |
| size_t |
4 |
8 |
4 |
8 |
8 |
2 |
| time_t |
4 |
8 |
4 |
8 |
8 |
4 |
三、主要差异点汇总
| 差异点 |
Linux/macOS 64位 |
Windows 64位 |
嵌入式系统 |
影响 |
| long大小 |
8字节 |
4字节 |
通常4字节 |
跨平台数据交换 |
| wchar_t大小 |
4字节 |
2字节 |
2字节 |
Unicode处理 |
| time_t大小 |
8字节 |
8字节 |
4字节 |
2038年问题 |
| 指针大小 |
8字节 |
8字节 |
2-4字节 |
内存寻址 |
| 结构体对齐 |
依赖ABI |
MSVC规则 |
编译器指定 |
数据布局 |
四、C标准最小要求
| 类型 |
最小大小 |
最小值头文件 |
标准保证范围 |
| char |
8位 |
<limits.h> |
CHAR_BIT ≥ 8 |
| short |
16位 |
SHRT_MIN/MAX |
-32767~32767 |
| int |
16位 |
INT_MIN/MAX |
-32767~32767 |
| long |
32位 |
LONG_MIN/MAX |
-2147483647~2147483647 |
| long long |
64位 |
LLONG_MIN/MAX |
-9.22×10¹⁸~9.22×10¹⁸ |
| pointer |
无要求 |
- |
足够存储地址 |
五、可移植类型对照表
| 原生类型(危险) |
可移植类型(推荐) |
头文件 |
格式说明符 |
| int |
int32_t / uint32_t |
<stdint.h> |
PRId32 / PRIu32 |
| long |
int64_t / uint64_t |
<stdint.h> |
PRId64 / PRIu64 |
| unsigned long |
uintptr_t |
<stdint.h> |
PRIuPTR |
| size_t |
size_t (已可移植) |
<stddef.h> |
zu |
| void* |
uintptr_t (转换用) |
<stdint.h> |
PRIuPTR |
| 任意整数 |
int_fastN_t |
<stdint.h> |
对应PRIdN |
六、跨平台编程建议方案
| 场景 |
推荐方案 |
注意事项 |
| 数据存储/交换 |
固定宽度类型(int32_t等) |
避免long,注意字节序 |
| 循环计数 |
size_t |
适合数组索引 |
| 位操作 |
uintN_t (N=8,16,32,64) |
明确位数 |
| 性能优化 |
int_fastN_t / uint_fastN_t |
平台最优大小 |
| 内存敏感 |
int_leastN_t / uint_leastN_t |
最小尺寸保证 |
| 文件偏移 |
off_t (POSIX) / int64_t |
大文件支持 |
| 时间处理 |
time_t + 检测2038问题 |
必要时用int64_t |
七、检测与兼容性代码模板
// 1. 系统检测
#if defined(_WIN64) || defined(__LP64__) || defined(_LP64)
#define IS_64BIT 1
#else
#define IS_64BIT 0
#endif
// 2. long大小检测
#if LONG_MAX == 2147483647L
#define LONG_IS_32BIT 1
#elif LONG_MAX == 9223372036854775807L
#define LONG_IS_64BIT 1
#endif
// 3. 字节序检测
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define IS_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define IS_BIG_ENDIAN 1
#endif
八、关键问题快速参考
| 问题 |
原因 |
解决方案 |
| 2038年问题 |
time_t为32位 |
使用64位time_t或int64_t |
| long差异 |
LP64 vs LLP64 |
避免long跨平台传输 |
| 结构体填充 |
对齐规则不同 |
使用#pragma pack或手动打包 |
| 指针截断 |
指针→int转换 |
使用uintptr_t |
| 格式字符串崩溃 |
%ld不匹配 |
使用inttypes.h宏 |
| 内存布局变化 |
字节序不同 |
定义网络字节序转换函数 |
总结要点
- 最大陷阱:
long 在64位Linux/macOS(8字节) vs Windows(4字节)
- 嵌入式特殊:
int 可能为2字节,指针可能非标准大小
- 唯一安全路径:使用
<stdint.h> 固定宽度类型
- 必须检查:字节序、对齐、系统字长
- 永远不要假设任何原生类型的大小,总是用
sizeof() 验证
一句话建议
新项目:全部使用 <stdint.h> 明确类型;旧项目:逐步替换并添加静态断言检查。