首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言數據序列化實戰:從文本協議到跨平台二進制方案

     編輯:關於C語言

C 語言數據序列化實戰:從文本協議到跨平台二進制方案

前言

在 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() 即可完成序列化/反序列化。

方案四:第三方庫

  • Protocol Buffers (protobuf-c):高效、跨語言、需定義 .proto 文件並生成代碼,較重。
  • JSON (cJSON 等):通用性強、人類可讀、解析較慢、體積較大。

跨平台驗證

將 Windows 上生成的文本序列化文件傳輸至 Linux,使用相同頭文件編譯的反序列化程序成功讀取,驗證了文本協議方案的跨平台能力。

總結與建議

方案跨平台性能體積適用場景
文本協議✅ 優中大配置文件、調試、跨語言交互
二進制內存映射❌ 差✅ 極快小同平台高性能 IPC、緩存
protobuf✅ 優快小大型項目、跨語言 RPC
JSON✅ 優慢大Web API、配置、日誌

對於中小型 C 項目,文本協議 + 宏模板自動化 是性價比最高的選擇:代碼量少、無依賴、跨平台、易維護。僅在性能極其敏感或需跨語言交互時,考慮引入 protobuf 或 JSON 庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved