首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C 語言結構體寫入文件:增加一個成員莫名其妙就正常了?記憶體對齊陷阱

     編輯:程式設計疑難解答

現象

結構體 st 包含三個 char[],fwrite/fread 讀寫文件。運行時輸出亂碼,**增加一個 int dummy 成員後突然正常**。

根本原因:結構體記憶體佈局與文件二進制兼容

1. 原結構體大小計算

struct st {
    char name[4];  // 偏移 0,大小 4
    char age[3];   // 偏移 4,大小 3
    char tel[9];   // 偏移 7,大小 9
}; // 總大小 = 16?實際因對齊可能為 16 或 20
  • 編譯器可能在 tel 後填充 1~3 字節使結構體大小為 4 的倍數(sizeof(int) 對齊)。
  • 不同編譯器/編譯選項(/Zp、-fpack-struct)導致填充不同,**文件二進制格式不穩定**。

2. 增加 int dummy 後

struct st {
    char name[4];
    char age[3];
    char tel[9];
    int dummy;      // 強制 4 字節對齊,結構體大小固定為 20
};
  • 結構體大小固定為 20 字節(4+3+9+4=20,恰好對齊),**消除了編譯器對齊差異**,讀寫一致。

正確做法:顯式控制佈局

方案一:#pragma pack(1) 取消填充(跨平台需謹慎)

#pragma pack(push, 1)
struct st {
    char name[4];
    char age[3];
    char tel[9];
};
#pragma pack(pop)

方案二:序列化逐字段寫入(推薦,可移植)

void writeStruct(FILE* fp, const struct st* s) {
    fwrite(s->name, 1, sizeof(s->name), fp);
    fwrite(s->age, 1, sizeof(s->age), fp);
    fwrite(s->tel, 1, sizeof(s->tel), fp);
}
void readStruct(FILE* fp, struct st* s) {
    fread(s->name, 1, sizeof(s->name), fp);
    fread(s->age, 1, sizeof(s->age), fp);
    fread(s->tel, 1, sizeof(s->tel), fp);
}

方案三:固定大小 + 版本號頭部

struct FileHeader { uint32_t magic; uint16_t version; uint16_t structSize; };
// 寫入頭部,再寫入結構體,讀取時校驗版本與大小

調試建議

寫入文件前 printf("size=%zu, name=%s, age=%s, tel=%s\n", sizeof(struct st), s[i].name, s[i].age, s[i].tel); 確認內存數據正確,再排查文件讀寫。

總結

結構體直接 fwrite 受**記憶體對齊/填充**影響極大,**增加成員改變對齊只是巧合掩蓋問題**。生產代碼必須採用逐字段序列化或顯式打包,確保二進制格式穩定、跨平台兼容。

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