stdint 与 inttypes
C99 引入 <stdint.h> 和 <inttypes.h>,提供固定宽度的整数类型和可移植的格式化宏。这些头文件解决了 int、long 等平台相关类型的大小不确定问题,是编写可移植代码的重要工具。
stdint.h
#include <stdint.h>
/* 精确宽度类型 */
int8_t i8; /* 8 位 */
int16_t i16; /* 16 位 */
int32_t i32; /* 32 位 */
int64_t i64; /* 64 位 */
uint8_t u8; /* 无符号 8 位 */
uint16_t u16;
uint32_t u32;
uint64_t u64;
/* 最小宽度类型 */
int_least8_t; /* 至少 8 位 */
int_least16_t; /* 至少 16 位 */
/* 最快宽度类型 */
int_fast8_t; /* 至少 8 位,最快 */
int_fast16_t;
/* 指针大小整数 */
intptr_t; /* 可以保存指针的整数 */
uintptr_t;
/* 最大宽度 */
intmax_t; /* 最大整数 */
uintmax_t;
inttypes.h
#include <inttypes.h>
#include <stdio.h>
int32_t x = 42;
uint64_t y = 10000000000ULL;
/* 格式化宏 */
printf("x = %" PRId32 "\n", x); /* x = 42 */
printf("y = %" PRIu64 "\n", y); /* y = 10000000000 */
printf("hex = %" PRIx32 "\n", x); /* hex = 2a */
/* scanf */
scanf("%" SCNd32, &x);
类型限制
#include <stdint.h>
INT8_MIN; /* -128 */
INT8_MAX; /* 127 */
UINT8_MAX; /* 255 */
INT32_MIN; /* -2147483648 */
INT32_MAX; /* 2147483647 */
UINT32_MAX; /* 4294967295 */
INT64_MIN;
INT64_MAX;
UINT64_MAX;
使用场景
网络协议:
struct PacketHeader {
uint16_t magic; /* 2 字节 */
uint32_t length; /* 4 字节 */
uint16_t checksum; /* 2 字节 */
};
/* 大小和布局在所有平台一致 */
文件格式:
/* 保证 32 位偏移 */
uint32_t offset;
fread(&offset, sizeof(uint32_t), 1, fp);
常见错误
直接格式化:
uint64_t x = 100;
printf("%lu\n", x); /* 错误:32 位平台 lu 是 32 位 */
/* 正确 */
printf("%" PRIu64 "\n", x);
假设 int 是 32 位:
/* 错误 */
int32_t x = INT_MAX; /* 如果 int 是 16 位,截断 */
/* 正确 */
int32_t x = INT32_MAX;
最佳实践
- 需要精确大小时用
intN_t/uintN_t - 格式化用
PRI*/SCN*宏 - 网络、文件格式用固定宽度类型
- 通用算法用
int_fastN_t - 指针运算用
intptr_t/uintptr_t