GNU属性nonnull与自定义断言my_assert的冲突问题及解决方案咨询
GNU属性nonnull与自定义断言my_assert的冲突问题及解决方案咨询
我现在遇到了一个GNU C属性和自定义断言宏的冲突问题,想请教下大家该怎么处理才好。先给大家看下我的代码背景:
首先是我自己实现的断言宏和处理函数:
[[gnu::noreturn]] [[gnu::visibility("internal")]] void my_assert_handler(const char* condStr, const char* file, int line); #define my_assert(cond) \ do { \ if (!(cond)) { \ my_assert_handler(#cond, __FILE__, __LINE__); \ __builtin_unreachable(); \ } \ } while (0)
然后我有个接收指针参数的函数foo,一开始是这么写的,用gcc -Wall -Wextra编译完全没问题:
void foo(const char* msg) { my_assert(msg != NULL); printf("%s\n", msg); }
后来我觉得给foo加上nonnull属性很合适,毕竟这个函数不应该接收空指针,于是我修改了函数定义:
[[gnu::nonnull(1)]] void foo(const char* msg) { my_assert(msg != NULL); printf("%s\n", msg); }
结果现在GCC直接给我报了个警告:
local_test.c: In function ‘foo’: local_test.c:11:20: warning: ‘nonnull’ argument ‘msg’ compared to NULL [-Wnonnull-compare] 11 | if (!(cond)) { \ | ^ local_test.c:24:9: note: in expansion of macro ‘my_assert’ 24 | my_assert(msg != NULL); | ^~~~~~~~~
我还发现两个有意思的现象:
- 用Clang编译的话,完全不会出现这个警告;
- 如果把自定义的
my_assert换成<assert.h>里的标准assert宏,GCC也不会报这个警告。
我大概能理解警告出现的原因:GCC看到我给参数加了nonnull属性,就认为这个参数绝对不可能是空指针,那代码里又去判断它是否为NULL,就觉得多此一举,所以抛出了警告。
但问题是,我不想随便舍弃其中任何一个:
- 去掉
[[gnu::nonnull(1)]]的话,我就失去了编译期的空指针检查提醒; - 去掉
my_assert的话,又没了运行时的断言保障,万一真的有边界情况触发空指针(比如编译器优化没覆盖到的场景),我连问题在哪都不知道。
我也不想用#pragma去禁用这个警告,总觉得这是治标不治本的办法;换Clang编译虽然能解决,但我这边主要还是用GCC环境;而且标准的assert宏我也不能用,有项目上的限制。
想请教下大家,有没有什么两全其美的办法,既能保留nonnull的编译期检查,又能保留自定义断言的运行时保障,还不会让GCC报这个警告?
内容来源于stack exchange
相关产品推荐
相关产品推荐

