C 語言基本整數類型(int、long 等)長度隨實現定義,導致跨平台移植時數據截斷、格式化字符串不匹配等隱患。C99 引入 <stdint.h> 定義固定寬度類型,配合 <inttypes.h> 宏實現可移植格式化輸出。本文系統講解類型分類、跨平台打印方案、實戰案例(Muduo 庫)。
| 類別 | 類型示例 | 說明 |
|---|---|---|
| 精確寬度 | int8_t, uint8_t | 恰好 8 位,無填充位,補碼表示(必須存在) |
| int16_t, uint16_t | 恰好 16 位 | |
| int32_t, uint32_t, int64_t, uint64_t | 恰好 32/64 位 | |
| 最小寬度 | int_least8_t, uint_least8_t... | 至少 N 位,通常映射到精確寬度類型 |
| int_least32_t... | 至少 32 位 | |
| 最快寬度 | int_fast8_t, uint_fast8_t... | 至少 N 位且運行最快(通常映射到機器字長) |
| int_fast32_t... | 至少 32 位最快 | |
| 指針寬度 | intptr_t, uintptr_t | 能容納指針的有符號/無符號整數 |
| 最大寬度 | intmax_t, uintmax_t | 實現支持的最大寬度 |
建議:優先使用 int32_t/int64_t 等精確寬度類型作為接口、協議、存儲定義;內部計算可用 int_fast32_t 提速。
問題:int64_t 在 32 位系統是 long long(%lld),64 位系統是 long(%ld)。直接寫死格式化字符串會導致編譯警告或運行時錯誤。
解決方案:使用 <inttypes.h> 提供的宏,預處理器自動展開為正確格式。
#include <inttypes.h>
#include <stdint.h>
int64_t val = 123456789012345LL;
printf("Value: %" PRId64 "\n", val); // 自動展開為 %ld 或 %lld
// C++ 需顯式定義宏開關(C99 標準要求)
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
| 類型 | printf 宏 | scanf 宏 |
|---|---|---|
| int8_t / uint8_t | PRId8 / PRIu8 | SCNd8 / SCNu8 |
| int16_t / uint16_t | PRId16 / PRIu16 | SCNd16 / SCNu16 |
| int32_t / uint32_t | PRId32 / PRIu32 | SCNd32 / SCNu32 |
| int64_t / uint64_t | PRId64 / PRIu64 | SCNd64 / SCNu64 |
| intptr_t / uintptr_t | PRIdPTR / PRIuPTR | SCNdPTR / SCNuPTR |
| intmax_t / uintmax_t | PRIdMAX / PRIuMAX | SCNdMAX / SCNuMAX |
十六進制:PRIx32、PRIx64(小寫)、PRIX32(大寫)。
// muduo/base/Timestamp.cc
#include <muduo/base/Timestamp.h>
#include <sys/time.h>
#include <stdio.h>
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#include <boost/static_assert.hpp>
using namespace muduo;
BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t));
Timestamp::Timestamp(int64_t microseconds)
: microSecondsSinceEpoch_(microseconds) {}
string Timestamp::toString() const {
char buf[32] = {0};
int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
return buf;
}
Timestamp Timestamp::now() {
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t seconds = tv.tv_sec;
return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}
關鍵點:static_assert 保證類型大小;PRId64 確保跨平台打印正確;snprintf 防止緩衝區溢出。
支持 C++11 的編譯器(GCC 4.7+、Clang 3.1+、MSVC 2013+)無需定義 __STDC_FORMAT_MACROS,直接包含 <cinttypes> 即可使用宏。
#include <cinttypes> // C++ 風格頭文件
#include <cstdint>
int64_t val = 42;
printf("%" PRId64 "\n", val); // 直接可用
long 是 64 位:Windows 64 位下 long 仍為 32 位(LLP64),Linux 64 位為 64 位(LP64)。int32_t/int64_t + PRId32/PRId64。SCNd64 等宏,避免 %lld 在 32 位系統讀取 int64_t 錯誤。#pragma pack 或手動序列化)。拥抱 <stdint.h> + <inttypes.h>,是編寫可移植、可維護、專業級 C/C++ 代碼的標誌性習慣。