在 C 語言開發中,數據序列化(將內存數據結構轉換為可存儲/傳輸格式)與反序列化是常見需求。雖然 C 標準庫未提供內建序列化機制,但通過自定義協議、fprintf/fscanf、fwrite/fread、或第三方庫,均可實現高效、跨平台的數據持久化與交換。
fprintf/fscanf 序列化最簡單、可移植性最強的方案。定義結構體與對應的格式字符串,利用 fprintf 寫入文本文件,fscanf 讀取還原。
struct student {
int id;
char sex;
int age;
char name[65];
double high;
double weight;
};
#define FMT_STUDENT "%d %c %d %s %lf %lf "
void student_serialize(struct student *stu, FILE *fp) {
fprintf(fp, FMT_STUDENT, stu->id, stu->sex, stu->age, stu->name, stu->high, stu->weight);
}
void student_deserialize(struct student *stu, FILE *fp) {
fscanf(fp, FMT_STUDENT, &stu->id, &stu->sex, &stu->age, stu->name, &stu->high, &stu->weight);
}
優點:跨平台、人類可讀、無對齊/大端序問題。缺點:解析較慢、文件體積大。
fwrite/fread 直接內存映射(失敗案例)嘗試直接將結構體內存寫入文件(fwrite(stu, sizeof(*stu), 1, fp)),但在 Windows 生成的文件在 Linux 上讀取失敗。原因在於:
int、double)在不同架構下可能不同。結論:fwrite/fread 直接寫結構體**不適合跨平台**,僅限同平台同編譯器環境下的高性能場景。
為減少重複勞動,設計宏模板 SERIALIZE_BASE_REGISTER,通過傳入結構體名、格式字符串、打印/掃描參數列表,自動生成序列化/反序列化函數。
#define SERIALIZE_BASE_REGISTER(name, pbc, ptf, scf) \
static int serialize_printfs_##name(void* data, int len) { \
FILE* fp = fopen("serialize_" #name, "wb"); \
struct name* _ = (struct name*)data; \
for (int i = 0; i < len; ++i) { \
fprintf(fp, pbc, ptf); \
++_; \
} \
fclose(fp); \
return 0; \
} \
static int serialize_scanfs_##name(void* data, int len) { \
FILE* fp = fopen("serialize_" #name, "rb"); \
struct name* _ = (struct name*)data; \
int ns = 0, nz = 0; \
const char* s = pbc; \
while (*s) if (*s++ == '%') ++nz; \
while (ns < len && fscanf(fp, pbc, scf) == nz) { \
++ns; ++_; \
} \
fclose(fp); \
return ns; \
}
struct person {
int id; char sex; int age; char name[65]; double high; double weight;
};
SERIALIZE_BASE_REGISTER(person, "%d %c %d %s %lf %lf ",
_->id, _->sex, _->age, _->name, _->high, _->weight,
&_->id, &_->sex, &_->age, _->name, &_->high, &_->weight)
調用 serialize_printfs_person()、serialize_scanfs_person() 即可完成序列化/反序列化。
將 Windows 上生成的文本序列化文件傳輸至 Linux,使用相同頭文件編譯的反序列化程序成功讀取,驗證了文本協議方案的跨平台能力。
| 方案 | 跨平台 | 性能 | 體積 | 適用場景 |
|---|---|---|---|---|
| 文本協議 | ✅ 優 | 中 | 大 | 配置文件、調試、跨語言交互 |
| 二進制內存映射 | ❌ 差 | ✅ 極快 | 小 | 同平台高性能 IPC、緩存 |
| protobuf | ✅ 優 | 快 | 小 | 大型項目、跨語言 RPC |
| JSON | ✅ 優 | 慢 | 大 | Web API、配置、日誌 |
對於中小型 C 項目,文本協議 + 宏模板自動化 是性價比最高的選擇:代碼量少、無依賴、跨平台、易維護。僅在性能極其敏感或需跨語言交互時,考慮引入 protobuf 或 JSON 庫。