閱讀 Linux 內核源碼時,在 init_pid_ns 結構體初始化中看到:
struct pid_namespace init_pid_ns = {
.kref = { .refcount = ATOMIC_INIT(2) },
.pidmap = { [0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } },
.last_pid = 0,
.level = 0,
.child_reaper = &init_task,
};
關鍵點:[0 ... PIDMAP_ENTRIES-1] —— **範圍指定初始化器**,將陣列連續區間一次性賦值。
允許在初始化列表中使用 .field = value(結構體)或 [index] = value(陣列),順序任意、可跳過、可重複(後蓋前)。
| 形式 | 適用對象 | 說明 |
|---|---|---|
.member = val | 結構體/聯合 | 指定成員名,不依賴宣告順序 |
[index] = val | 陣列 | 指定單一索引 |
[first ... last] = val | 陣列 | **GNU 擴展**(非標準 C),指定連續範圍 |
struct Point { int x, y; };
struct Point p = { .y = 10, .x = 5 }; // 亂序初始化
int arr[10] = { [5] = 99, [2] = 77 }; // 稀疏初始化,其餘為 0
int zeros[100] = { 0 }; // 全零(舊寫法同樣有效)
僅 GCC/Clang 支援,MSVC 不支援。Linux 內核專用 GCC,故大量使用。
struct Item { int val; void *ptr; };
struct Item items[10] = {
.val = 1, // 結構體指定初始化
.id = { [0 ... 9] = { 2, NULL } } // 陣列範圍初始化(GNU)
};
等效於:
struct Item items[10];
for (int i=0; i<10; i++) { items[i].val = 2; items[i].ptr = NULL; }
items[0].val = 1; // 後蓋前
#include <stdio.h>
struct Pid { int val; void *fn; };
struct Str { int val; struct Pid id[10]; };
struct Str init_str = {
.val = 1,
.id = { [0 ... 9] = { 2, NULL } } // 需 GCC/Clang 編譯
};
int main() {
for (int i=0; i<10; i++)
printf("init_str.id[%d].val = %d\n", i, init_str.id[i].val);
return 0;
}
// 輸出:全部為 2
[a ... b]:屬 GNU 擴展,**避免在需跨編譯器專案使用**;可用巨集或靜態循環生成代碼替代。const 陣列 + memcpy,或 C++11 std::array + 列表初始化。指定初始化器是 C99 引入的「殺手級特性」,讓結構體/陣列初始化從「位置依賴」進化為「名稱/索引依賴」,大幅降低維護風險。Linux 內核展示了其極致用法(含 GNU 範圍擴展),理解後可在自有代碼中靈活採用標準子集,享受清晰、安全的初始化體驗。