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

C/C++ 結構體初始化器 {0} 的標準語義深度解析

     編輯:關於C語言

現象:無處不在的 {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} 為什麼能正確將所有成員歸零?標準如何規定?

C99 標準條文依據 (ISO/IEC 9899:1999 §6.7.8)

規則 21:初始化器列表項目少於成員數

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、結構體遞歸零初始化)。

規則 20:巢狀聚合體的遞歸初始化

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...

解讀:若成員本身是結構體/聯合,規則遞歸應用。若初始化器以 { 開頭,大括號內內容初始化該子聚合體;否則從列表順序取夠夠數量的初始化器給子聚合體,剩下的給後續成員。

實例推演

例 1:扁平結構體


struct { int a; int b; } s = {0};
// a 獲得顯式初始化器 0
// b 無顯式初始化器 → 規則21 → 靜態零初始化 → 0
// 結果:s.a=0, s.b=0

例 2:巢狀結構體,無內層大括號


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

例 3:巢狀結構體,有內層大括號


Outer o = { {1, 2}, 3 };
// 內層 {1,2} 明確初始化 Inner
// 外層第三個初始化器 3 給 z
// 結果:o.in.x=1, o.in.y=2, o.z=3

例 4:{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} 能「一鍵歸零」任意深度巢狀結構體的標準保證。

C++ 標準的繼承與擴展

  • C++98 直接引用 C 規則 (§8.5.1)。
  • C++11 引入 列表初始化 (Foo f = {}; / Foo f{};) 稱為值初始化,語義更強:
    — 無用戶聲明構造函數的聚合體:{} 等價 {0} 零初始化所有成員。
    — 有默認構造函數的類:{} 調用默認構造函數 (不一定是零初始化)。
  • C++20 = {}; 統一聚合體與類的初始化語義。

對比:{0} vs memset vs {}

最佳實踐建議

  1. C 代碼:統一使用 Type var = {0};。標準保證、零開銷、可讀性強。
  2. C++ 代碼:優先 Type var{}; (值初始化)。聚合體效果同 {0},非聚合體調用默認構造函數,語義更正確。
  3. 避免 memset:除非處理原始字節緩衝區、或與 C 異構接口交互。對含虛函數表、std::string、指針的類極其危險。
  4. 靜態/線程局部變量:無需顯式初始化,語言保證零初始化。static Foo f; 即可。

總結

{0} 不是「技巧」或「習慣用法」,而是 C/C++ 標準明確規定的聚合體初始化語義。理解 §6.7.8 規則 21 (剩餘成員零初始化) 與規則 20 (巢狀遞歸),就能自信地在任何深度巢狀結構體、聯合、數組上使用 {0},獲得標準保證的、類型安全的、零開銷的完全零初始化。這是現代 C/C++ 專業程序員的必備標準知識。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法C 支持C++ 支持類型安全填充字節靜態分析友好
{0}✅ C89+✅ C++98+✅ 編譯器檢查類型✅ 零初始化✅
memset(&s,0,sizeof(s))✅✅ (危險)❌ 無類型檢查,易寫錯大小✅ 零填充❌
Foo f = {}❌ (C23 擬加入)✅ C++11+✅✅✅
Foo f{}❌✅ C++11+✅✅✅