C99 引入**複合字面量**與**可變參數宏**,使得「結構體參數函數」可轉為「可變參數函數」調用風格,極大提升調用處可讀性。本文解析酷殼經典案例,展示宏展開原理、GCC/Clang/MSVC 兼容性與工程應用建議。
#include <stdio.h>
#define func(...) myfunc((struct mystru){__VA_ARGS__})
struct mystru {
const char *name;
int number;
};
void myfunc(struct mystru ms) {
printf("%s: %d\n", ms.name ? ms.name : "untitled", ms.number);
}
int main() {
func("three", 3); // 位置參數
func("hello"); // 省略 number → 0
func(.name = "zero"); // 指定初始化器
func(.number = 42, .name = "argc"); // 亂序指定
func(.number = 42); // 僅指定 number
return 0;
}
three: 3 hello: 0 zero: 0 argc: 42 untitled: 42
// 調用 → 展開後
func("three", 3) → myfunc((struct mystru){"three", 3});
func("hello") → myfunc((struct mystru){"hello"});
func(.name = "zero") → myfunc((struct mystru){.name = "zero"});
func(.number=42,.name="a")→ myfunc((struct mystru){.number=42, .name="a"});
func(.number=42) → myfunc((struct mystru){.number=42});
**關鍵點**:
| 編譯器 | 複合字面量 | 指定初始化器 | 可變參數宏 | 備註 |
|---|---|---|---|---|
| GCC ≥ 3.0 | ✅ | ✅ | ✅ | 完美支援 |
| Clang ≥ 3.0 | ✅ | ✅ | ✅ | 完美支援 |
| MSVC ≤ 2017 | ❌ | ❌ | ✅ | 不支援 C99 此特性 |
| MSVC 2019+ | ⚠️ 部分 | ⚠️ 部分 | ✅ | /std:c11 /experimental:c11atomics 可能啟用 |
| ICC | ✅ | ✅ | ✅ | 支援 |
C++20 指定初始化器已標準化,且可直接用結構體聚合初始化:
struct Opt { const char* name; int val; };
void func(Opt o);
func({.name="x", .val=1}); // C++20 合法,無需宏
**結論**:純 C 專案中該技巧極具價值;C++ 新代碼優先用原生聚合初始化。