旧版G++(3.3.5及更早)下常量表达式编译时检查宏的修复
兼容旧版G++(3.3.5及更早)的编译时检查宏修改方案
我是一名C程序员,对C了解有限。我编写了用于编译时检查的Chk和CEx宏,用于在常量表达式中嵌入编译时检查:Chk验证表达式为真(编译时常量),求值为0;CEx确保表达式是编译时常量,求值为表达式本身,不满足则终止编译。这些宏在G 4.1.1上正常工作,但在G++ 3.3.5及更早版本中编译C++代码时会出现解析错误:
$ gcc -x c++ -c x x:22: error: parse error before `)' token x:23: error: parse error before `)' token
原代码如下:
/* in-expression compile-time check evaluating to 0 */ #ifdef __cplusplus template<bool> struct Chk_sa; template<> struct Chk_sa<true>{}; #define Chk(test) (sizeof((Chk_sa<!!(0+(test))>())) * 0) #else #define Chk(test) (sizeof(struct { int (Chk):((0+(test)) ? 1 : -1); }) * 0) #endif /* ensure value x is a constant expression */ #ifdef __cplusplus template<bool,bool> struct CEx_sa; template<> struct CEx_sa<true,false>{}; template<> struct CEx_sa<false,true>{}; #define CEx(x) (sizeof((CEx_sa<!!(0+(x)), !(0+(x))>())) * 0 + (x)) #else #define CEx(x) (sizeof(struct { int (CEx):(((0+(x)) && 1) + 1); }) * 0 + (x)) #endif /* usage like this: */ struct ChkTest { int expr1[Chk(3*3) + 1]; // supposed to be [1] int expr2 : CEx(3*3); // supposed to be : 9 };
问题原因
旧版G++(3.3.x系列)对C++模板语法的解析更为严格,无法正确处理sizeof((Chk_sa<...>()))这种写法——它会把模板实例化后的括号()误解析为语法错误,而不是空结构体的临时对象构造。
修改后的代码
/* in-expression compile-time check evaluating to 0 */ #ifdef __cplusplus template<bool> struct Chk_sa; template<> struct Chk_sa<true>{}; // 移除多余的括号和临时对象构造,直接取类型的sizeof #define Chk(test) (sizeof(Chk_sa<!!(0+(test))>) * 0) #else #define Chk(test) (sizeof(struct { int (Chk):((0+(test)) ? 1 : -1); }) * 0) #endif /* ensure value x is a constant expression */ #ifdef __cplusplus template<bool,bool> struct CEx_sa; template<> struct CEx_sa<true,false>{}; template<> struct CEx_sa<false,true>{}; // 同样移除多余的括号和临时对象构造 #define CEx(x) (sizeof(CEx_sa<!!(0+(x)), !(0+(x))>) * 0 + (x)) #else #define CEx(x) (sizeof(struct { int (CEx):(((0+(x)) && 1) + 1); }) * 0 + (x)) #endif /* usage remains unchanged */ struct ChkTest { int expr1[Chk(3*3) + 1]; // 仍为[1] int expr2 : CEx(3*3); // 仍为:9 };
修改原理
- 空结构体
Chk_sa<true>和CEx_sa的sizeof值为1,乘以0后仍为0,完全保留原Chk宏的求值结果 CEx宏中sizeof(...) *0仍为0,加上x后结果不变,保留原功能- 移除临时对象构造
()后,旧G++能正确解析模板类型的sizeof表达式,避免语法错误
功能验证
修改后的宏在G++ 3.3.5中可以正常编译,同时保留原有的编译时检查功能:
- 若
Chk的参数为假(或非编译时常量),编译器会因找不到Chk_sa<false>的定义而报错 - 若
CEx的参数非编译时常量,编译器无法推导模板参数,会报实例化错误;若参数为常量,仅匹配对应的特化版本,正常通过编译
内容的提问来源于stack exchange,提问作者mirabilos
相关产品推荐
相关产品推荐

