假设我正在维护一个使用两个参数(两个指针)的库函数。第二个参数仅是为了向后兼容而存在。调用者应始终传递NULL。我想在我的头文件中放入一些内容,如果第二个参数不是编译时常量NULL,则会使编译器发出警告。我以为我可以使用GCC的__builtin_constant_p
和__attribute__((warning))
扩展名来做到这一点:
extern void thefun_called_with_nonnull_arg (void)
__attribute__((__warning__(
"'thefun' called with second argument not NULL")));
extern int real_thefun (void *, void *);
static inline int
thefun (void *a, void *b)
{
if (!__builtin_constant_p(b) || b != 0)
thefun_called_with_nonnull_arg();
return real_thefun(a, b);
}
int warning_expected (void *a, void *b)
{
return thefun(a, b);
}
int warning_not_expected (void *a)
{
return thefun(a, 0);
}
但这不适用于我测试过的任何版本的GCC。我收到对thefun
的两者调用的警告。 (Compiler Explorer demo。)
任何人都可以建议一种替代结构,该结构将对warning_expected
而不是warning_not_expected
产生警告吗?
注意:
b
是int
,则上面的does work。attribute((warning))
,而且我也没有运气找到替代方法。)b
是int
并且thefun
被标记为始终内联,以上功能也无法关闭优化功能。)thefun
定义为宏,而不是将其定义为宏。-Werror
或同等功能处于活动状态,否则它必须是警告,而不是硬错误。 编辑:基于Kamil Cuk's discovery,可以通过将指针强制转换为具有不同大小的整数 来抑制不必要的警告,是对__builtin_constant_p
和filed GCC bug report #91554实施的监督。我仍然对提供使用clang,icc或与GNU libc一起使用的任何其他编译器执行此操作的方式的答案感兴趣。
答案 0 :(得分:4)
我终于设法使其正常工作:
if (!__builtin_constant_p((int)(uintptr_t)b) || b != 0) {
这样您只会收到一个警告。
似乎gcc
无法对指针类型执行__builtin_constant_p
。 __builtin_constant_p(b)
始终返回0,因此warn函数始终处于链接状态。将b
投射到int
很奇怪。尽管它会降低指针值的精度,但我们对此并不在意,因为我们只检查它是否为常数。
答案 1 :(得分:3)
没有GNU扩展,就无法完成您描述的事情。
这种可移植的方法会产生硬错误(因为_Static_assert
需要一个常量表达式):
#define thefun(a, b) \
({ \
_Static_assert(b == 0, \
"'thefun' called with second argument not NULL"); \
real_thefun(a, b); \
})
但是,在GCC和Clang上都有 one 个增强型方法:
extern void thefun_called_with_nonnull_arg (void)
__attribute__((__deprecated__(
"'thefun' called with second argument not NULL")));
extern int real_thefun (void *, void *);
static inline int
thefun (void *a, void *b)
{
if (!__builtin_constant_p((unsigned short)(unsigned long)b) || b != 0)
thefun_called_with_nonnull_arg();
return real_thefun(a, b);
}
int warning_expected (void *a, void *b)
{
return thefun(a, b);
}
int warning_not_expected (void *a)
{
return thefun(a, 0);
}
在GCC 8.3.0和Clang 8.0.0中进行了测试。
有关强制转换的更多信息,请参见GCC bug report #91554。