結構體本質:自定義的聚合類型
struct 將**異構數據**按聲明順序聚合為單一類型。與數組「同構、連續、下標訪問」不同,結構體**異構、按序佈局、成員名訪問**,且**支持賦值/傳值**(逐成員拷貝)。
struct Student {
char name[20];
int age;
float score;
}; // 定義類型 struct Student
struct Student s1 = {"Alice", 20, 92.5f}; // 聚合初始化
struct Student s2 = s1; // 合法:逐成員拷貝
// int a[3] = {1,2,3}; int b[3] = a; // 錯誤:數組不可賦值
內存佈局與對齊:性能與大小的隱形博弈
對齊規則
- 成員對齊:每個成員偏移量必須是其對齊要求的倍數 (通常 = sizeof(類型),受
#pragma pack(n) / __attribute__((aligned(n))) 限制)。
- 結構體整體對齊:= 最大成員對齊要求。結構體大小 = **最小能容納所有成員並滿足整體對齊的倍數** (尾部填充)。
實例分析
struct A { char c; int i; }; // 大小 8: c(1) + pad(3) + i(4)
struct B { int i; char c; }; // 大小 8: i(4) + c(1) + pad(3)
struct C { char c; double d; }; // 大小 16: c(1) + pad(7) + d(8)
struct D { double d; char c; }; // 大小 16: d(8) + c(1) + pad(7)
優化技巧:按類型大小遞減排序成員 (大→小),可最小化填充,縮減內存佔用、提升緩存命中率。
結構體指針與成員訪問
struct Student *ps = &s1;
- 間接訪問運算符
->:ps->age 等價於 (*ps).age。-> 結合優先級高於一元運算符,*ps.age 解析為 *(ps.age) (錯誤),**必須用 -> 或 (*ps).age**。
結構體作為函數參數:三種方式深度對比
1. 傳值 void foo(struct Student s)
- 機制:調用者棧上構造**臨時副本** (逐成員拷貝),函數操作副本,返回時銷毀。
- 開銷:大小與結構體大小成正比。大結構體**棧壓力大、拷貝慢**。
- 適用:小結構體 (
sizeof ≤ 2-3寄存器,如struct Pair {int a,b;}),需語義隔離(不修改原值)。
2. 傳指針 void foo(const struct Student *ps)
- 機制:傳遞地址 (通常1寄存器),函數間接訪問原對象。
- 開銷:極小 (指針大小)。加
const 表達只讀意圖,啟用編譯器優化/檢查。
- 適用:**絕大多數場景**,尤其大結構體、需修改原值、可選參數 (傳NULL)。
3. 傳引用 (C++專有) void foo(const Student& s)
- 機制:編譯器實現為指針,語法如傳值。**無臨時對象、無拷貝、語法自然**。
- 優勢:效率≈指針,語法≈傳值,**避免空指針解引用風險 (引用必須綁定合法對象)**,支持臨時對象綁定
const T& 延長生命周期。
- 適用:C++首選默認方式。需修改用
Student&,只讀用 const Student&。
性能實測對比 (大結構體 1KB)
| 方式 | 汇編指令數 | 棧使用 | 備註 |
| 傳值 | ~200 (memcpy循環) | +1KB | 極慢 |
| 傳指針 | ~5 (mov寄存器) | +8B | 快,需檢查NULL |
| 傳引用 | ~5 | +8B | 最快且最安全 (C++) |
進階模式:返回值優化與移動語義
C: 輸出參數模式
// 1. 調用者分配,傳指針填充 (推薦)
void create_student(struct Student *out, const char *name, int age, float score);
// 2. 返回結構體 (C99+ 支持,依賴 RVO/NRVO 編譯器優化)
struct Student create_student_v2(const char *name, int age, float score) {
return (struct Student){.name="", .age=age, .score=score}; // 指定初始化器
}
C++: 值返回 + 移動語義 (C++11+)
Student create_student(string name, int age, float score) {
return Student{std::move(name), age, score}; // NRVO 或 移動構造 (零拷貝)
}
// 調用: Student s = create_student("Bob", 21, 88.0f); // 高效
特殊成員與佈局控制
- 位域:
struct { unsigned a:3; unsigned b:5; }; 緊湊存儲,**跨平台佈局不可移植**,僅用於硬件寄存器映射/極度受限內存。
- 零長度數組 / 柔性數組成員 (C99):
struct Buffer { size_t len; char data[]; }; 分配 malloc(sizeof(Buffer) + n),實現變長結構體。**C++用 std::vector/std::string 替代。**
- 匿名聯合體/結構體 (C11/C++11):
union { struct {int x,y;}; struct {int w,h;}; }; 同一內存多視圖。
offsetof 宏:offsetof(Student, score) 獲取成員偏移 (編譯期常量),用於序列化/反射/容器實現。
現代C++最佳實踐
- 聚合初始化:
Student s{"Alice", 20, 92.5f}; (C++20 指定初始化器 Student s{.name="Alice", .age=20})。
- 規則之零/五/三:優先用
std::string/std::vector 等RAII類型作成員,**自動獲得正確拷貝/移動/析構**,無需手寫特殊成員函數。
std::byte (C++17) 替代 char/uint8_t 做字節操作,類型安全。
- 反射模擬:Boost.PFR /
magic_get / 自定義宏 實現結構體成員遍歷/序列化/ORM。
總結:選擇決策樹
需要修改原值?
├─ 是 → C: 傳指針 (T*) / C++: 傳引用 (T&)
└─ 否 (只讀)
├─ 小類型 (≤ 16-24 bytes, 簡單POD) → C/C++: 傳值 (T) / C++: const T&
└─ 大類型 / 非POD / 含RAII成員 → C: const T* / C++: const T& (首選)
**核心原則**:語義清晰、零開銷抽象、類型安全。C用 const T* 表達只讀借用,C++用 const T& 享受語法糖與安全保障。大結構體**永不傳值**。
- 上一篇文章: 基於C語言設計流的語音識別芯片優化實踐:從算法到矽片的全鏈路
- 下一篇文章: 基於消息隊列的TCP/IP迭代服務器設計:高併發、低資源、易管理
Copyright ©
程式碼之家 All Rights Reserved