匿名结构体引发Invalid initializer error的原因及GCC修复方案
基于GCC扩展解决匿名结构体类型不匹配问题
问题描述
我正在开发一款可生成C代码的自制编译器,当前遇到如下GCC编译错误:
tests/simple.c:34:36: error: invalid initializer
34 | std_Dynamic_Array(Int64()) k = v(&da);
| ^
经gcc -E预处理后的代码显示,函数v的返回类型与变量k的类型均展开为struct{int count; int capacity; long long* memory; },但GCC将二者视为不同类型。要求避免使用typedef,仅借助GCC专属扩展特性解决,无需考虑其他编译器兼容性。
原始代码
Void() aba () { } #define std_Dynamic_Array(T) struct{Int32() count; Int32() capacity; T* memory; } Void() no_body_func (Int32() b); Int32() test_func (Int32()*** a) { } Int32() test_func2 (Int32() x) { } Int32() b = 33; #define v_macro(T) struct{Int32() count; Int32() capacity; T* memory; } v (std_Dynamic_Array(T)* m) \ { \ Int32() l = 44; \ } Void() _main () { Int64() a = 5; b = 22; Int32() c = test_func2(6); Int32() inner_func (Int32()* a) { Int32() g = 3; } Int32()* x = &b; inner_func(x); Int32() j = *x; Float32() f = 33.000000; std_Dynamic_Array(Int64()) da = {.count = 4}; v_macro(Int64()); std_Dynamic_Array(Int64()) k = v(&da); } int main(int argc, char ** argv) { return 0; }
预处理后代码
void aba () { } void no_body_func (int b); int test_func (int*** a) { } int test_func2 (int x) { } int b = 33; void _main () { long long a = 5; b = 22; int c = test_func2(6); int inner_func (int* a) { int g = 3; } int* x = &b; inner_func(x); int j = *x; float f = 33.000000; struct{int count; int capacity; long long* memory; } da = {.count = 4}; struct{int count; int capacity; long long* memory; } v (struct{int count; int capacity; long long* memory; }* m) { int l = 44; }; struct{int count; int capacity; long long* memory; } k = v(&da); } int main(int argc, char ** argv) { return 0; }
解决方案
核心问题是C标准中每次定义匿名结构体都会生成全新的类型,哪怕成员完全一致。借助GCC的__typeof__扩展可以让类型统一,无需typedef:
方法1:修改v_macro的返回类型
将v_macro的返回类型改为__typeof__(*m),让函数v的返回类型与传入参数指向的结构体类型完全一致,而非重新定义匿名结构体:
#define v_macro(T) __typeof__(*m) v (std_Dynamic_Array(T)* m) \ { \ Int32() l = 44; \ return *m; /* 必须添加返回语句,否则会触发未定义行为 */ \ }
预处理后,函数v的返回类型会直接复用da的结构体类型,此时std_Dynamic_Array(Int64()) k = v(&da);即可正常编译。
方法2:用__typeof__推导变量k的类型
保持v_macro不变,修改变量k的定义,让其类型直接推导自函数v的返回值:
__typeof__(v(&da)) k = v(&da);
这种方式无需修改宏定义,直接利用GCC的类型推导特性让k的类型与v的返回类型完全匹配。
内容的提问来源于stack exchange,提问作者kamkow1
相关产品推荐
相关产品推荐

