兼容GNU C与C23的deprecated属性宏改写问题
兼容C23的deprecated属性宏解决方案
问题背景
我在使用下述宏时遇到兼容性问题:
// Assume that __GNUC__ or __clang__ is defined. #if defined(__has_c_attribute) #if __has_c_attribute(deprecated) #define ATTRIBUTE_DEPRECATED(...) [[deprecated(__VA_ARGS__)]] #endif /* deprecated */ #else #define ATTRIBUTE_DEPRECATED(...) __attribute__((deprecated(__VA_ARGS__))) #endif /* __has_c_attribute */
核心矛盾
- GNU C扩展中,
__attribute__((deprecated()))和__attribute__((deprecated))等价,空参数列表被允许 - C23标准属性语法中,
[[deprecated()]]是非法写法,无参数时必须写成[[deprecated]](不能带括号)
现有问题
使用std=c2x编译时,调用ATTRIBUTE_DEPRECATED()会触发报错:
deprecated.c:12:14: error: parentheses must be omitted if attribute argument list is empty
而在未定义__has_c_attribute的环境中,以下两种调用形式均可正常工作:
ATTRIBUTE_DEPRECATED() ATTRIBUTE_DEPRECATED("private")
需求
- 让代码同时兼容C23标准
- 支持无需参数时直接写
ATTRIBUTE_DEPRECATED(不带括号)
解决方案
通过宏重载区分无参数和带参数场景,实现跨标准兼容:
最终兼容宏实现
// Assume that __GNUC__ or __clang__ is defined. #if defined(__has_c_attribute) && __has_c_attribute(deprecated) // 针对C23属性语法,区分有无参数分支 #define ATTRIBUTE_DEPRECATED(...) _ATTRIB_DEPRECATED_CHOOSER(__VA_ARGS__, _WITH_ARG, _NO_ARG)(__VA_ARGS__) #define _ATTRIB_DEPRECATED_CHOOSER(_1, _2, NAME, ...) NAME #define _NO_ARG() [[deprecated]] #define _WITH_ARG(msg) [[deprecated(msg)]] #else // 针对GNU扩展,保留原有逻辑(空参数列表被允许) #define ATTRIBUTE_DEPRECATED(...) __attribute__((deprecated(__VA_ARGS__))) #endif
调用示例
三种调用方式均被支持:
ATTRIBUTE_DEPRECATED int old_func1(void); // 无参数无括号 ATTRIBUTE_DEPRECATED() int old_func2(void); // 无参数带括号 ATTRIBUTE_DEPRECATED("use new_func instead") int old_func3(void); // 带参数
原理说明
- C23分支:
- 借助
__VA_ARGS__和宏选择器_ATTRIB_DEPRECATED_CHOOSER,根据传入参数数量自动匹配对应展开逻辑 - 无参数(包括
ATTRIBUTE_DEPRECATED())时展开为[[deprecated]],带参数时展开为[[deprecated(msg)]]
- 借助
- GNU分支:
- 保留原有写法,因为GNU扩展允许
__attribute__((deprecated()))这种空参数形式
- 保留原有写法,因为GNU扩展允许
- 无括号调用支持:
- 直接写
ATTRIBUTE_DEPRECATED时,__VA_ARGS__为空,宏选择器会匹配到_NO_ARG,最终展开为合法的无参数属性
- 直接写
验证用例
以下代码可同时兼容GNU模式和C23标准编译:
// 上述兼容宏代码放在此处 ATTRIBUTE_DEPRECATED int min(int a, int b) { return a < b ? a : b; } ATTRIBUTE_DEPRECATED() int max(int a, int b) { return a > b ? a : b; } ATTRIBUTE_DEPRECATED("use min/max from stdlib") int old_compare(int a, int b) { return a - b; } int main() { return min(10, 20) + max(5, 15) + old_compare(3, 7); }
内容的提问来源于stack exchange,提问作者Madagascar
相关产品推荐
相关产品推荐

