{0}C/C++ 代碼中頻繁出現:
struct Foo { int a; double b; char c[32]; } foo = {0};
memset(&foo, 0, sizeof(foo)); // 舊式寫法
Foo foo = {}; // C++11 聚合初始化
Foo foo{}; // C++11 值初始化
{0} 為什麼能正確將所有成員歸零?標準如何規定?
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
解讀:初始化列表項目少於聚合體成員時,剩餘成員按靜態存儲期對象規則隱式初始化 —— 即零初始化 (整數 0、浮點 0.0、指針 NULL、結構體遞歸零初始化)。
If the aggregate contains elements or members that are aggregates or unions... these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace initialize the subaggregate... Otherwise, only enough initializers from the list are taken to account for the elements or members of the subaggregate...
解讀:若成員本身是結構體/聯合,規則遞歸應用。若初始化器以 { 開頭,大括號內內容初始化該子聚合體;否則從列表順序取夠夠數量的初始化器給子聚合體,剩下的給後續成員。
struct { int a; int b; } s = {0};
// a 獲得顯式初始化器 0
// b 無顯式初始化器 → 規則21 → 靜態零初始化 → 0
// 結果:s.a=0, s.b=0
struct Inner { int x; int y; };
struct Outer { Inner in; int z; };
Outer o = { 1, 2 }; // 初始化器列表:1, 2
// Outer 第一個成員是 Inner (聚合體)
// 初始化器無內層 { } → 規則20「否則」分支
// 從列表取「足夠」數量給 Inner:Inner 有 2 個成員 → 取 1, 2 給 in.x, in.y
// 剩餘初始化器:無 → z 觸發規則21 → 零初始化
// 結果:o.in.x=1, o.in.y=2, o.z=0
Outer o = { {1, 2}, 3 };
// 內層 {1,2} 明確初始化 Inner
// 外層第三個初始化器 3 給 z
// 結果:o.in.x=1, o.in.y=2, o.z=3
{0} 作用於巢狀結構體
Outer o = {0}; // 初始化器列表只有一個 0
// Outer 第一個成員 Inner 是聚合體
// 初始化器無內層 { } → 規則20「否則」
// 從列表取足夠數量給 Inner:需要 2 個,但列表只有 1 個 (0)
// → 取 0 給 in.x,in.y 無顯式初始化器 → 規則21 零初始化 → 0
// Outer 其餘成員 z 也無顯式初始化器 → 規則21 零初始化 → 0
// 結果:o.in.x=0, o.in.y=0, o.z=0
這就是 {0} 能「一鍵歸零」任意深度巢狀結構體的標準保證。
Foo f = {}; / Foo f{};) 稱為值初始化,語義更強:{} 等價 {0} 零初始化所有成員。{} 調用默認構造函數 (不一定是零初始化)。= {}; 統一聚合體與類的初始化語義。{0} vs memset vs {}| 方法 | C 支持 | C++ 支持 | 類型安全 | 填充字節 | 靜態分析友好 |
|---|---|---|---|---|---|
{0} | ✅ C89+ | ✅ C++98+ | ✅ 編譯器檢查類型 | ✅ 零初始化 | ✅ |
memset(&s,0,sizeof(s)) | ✅ | ✅ (危險) | ❌ 無類型檢查,易寫錯大小 | ✅ 零填充 | ❌ |
Foo f = {} | ❌ (C23 擬加入) | ✅ C++11+ | ✅ | ✅ | ✅ |
Foo f{} | ❌ | ✅ C++11+ | ✅ | ✅ | ✅ |