掌握數據類型細節是編寫正確、可移植 C 代碼的基石。本文涵蓋有符號/無符號表示差異、stdint.h 精確寬度類型、邊界值陷阱、自定義類型提升可移植性三大核心主題。
int -32768~32767,unsigned int 0~65535。char 符號性實現定義,跨平台必須顯式聲明 signed char/unsigned char。float/double 始終有符號(IEEE 754 符號位)。#includeint8_t int16_t int32_t int64_t // 有符號精確寬度 uint8_t uint16_t uint32_t uint64_t // 無符號精確寬度 int_least8_t ... // 至少 N 位 int_fast8_t ... // 最快至少 N 位 intptr_t // 能容納指針的有符號整數 uintptr_t // 能容納指針的無符號整數 intmax_t // 最大寬度有符號整數 uintmax_t // 最大寬度無符號整數
優勢:跨平台寬度固定,消除 int 16/32/64 位不確定性。
uint32_t a = 40000, b = 40000, c = 100; uint64_t m = a * b + c; // 錯誤!a*b 先按 32 位計算溢出,再擴展到 64 位 // 正確:強制提升 uint64_t m = (uint64_t)a * b + c; // 或 ((uint64_t)a) * b + c
規則:整數提升 → 常見算術轉換 → 表達式類型確定。無符號參與運算導致整個表達式無符號化,比較時有符號隱式轉無符號極易出錯。
// mytypes.h #ifdef ARCH_64 typedef long int32_t; typedef long long int64_t; #else typedef int int32_t; typedef long long int64_t; #endif // 業務代碼 int32_t user_id; int64_t timestamp;
遷移 64 位平台只需修改 mytypes.h,業務代碼零變動。Linux 內核、嵌入式 SDK 均採用此模式。
struct { char a; int b; }; // sizeof 通常 8(對齊填充 3 字節)
#pragma pack(1) // 或 __attribute__((packed))
struct { char a; int b; }; // sizeof = 5,但訪問可能觸發總線錯誤或性能下降
uintN_t。size_t(無符號,匹配指針寬度)。off_t / int64_t。ptrdiff_t / ssize_t。