警告不是编译时间常数的函数参数

zwo*_*wol 14 c gcc compiler-warnings

假设我正在维护一个接受两个参数(两个指针)的库函数。第二个参数仅是为了向后兼容而存在。调用者应始终传递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);
}
Run Code Online (Sandbox Code Playgroud)

但这不适用于我测试过的任何版本的GCC。两次致电我都会收到警告thefun。(编译器资源管理器演示。)

谁能建议一种替代构造,它会为warning_expected而不是发出警告warning_not_expected

笔记:

  • 奇怪的是,如果是,则上述方法确实有效bint
  • 上面的代码使用了特定于GCC的扩展,但是,欢迎使用可在多种编译器上使用的解决方案。(特别是,clang并没有实现attribute((warning)),我也没有运气找到替代方法。)
  • 关闭优化后仍然可以使用的解决方案比不使用优化的解决方案更好。(即使bintthefun标记为始终在线,以上功能也无法关闭优化功能。)
  • 不涉及定义thefun为宏的解决方案比包含宏的解决方案更为可取。
  • 标头必须包含在C程序和C ++程序中,才能工作。适量的ifdeffage是可以接受的。
  • 除非-Werror有效,否则它必须是警告,而不是硬错误。

编辑:基于卡米尔·库克(Kamil Cuk)的发现,可以通过将指针强制转换为不同大小的整数来抑制不必要的警告,我确定这是对实施中的疏忽,__builtin_constant_p提交了GCC错误报告#91554。我仍然对提供使用clang,icc或与GNU libc一起使用的任何其他编译器执行此操作的方式的答案感兴趣。

Kam*_*Cuk 4

我终于设法让它发挥作用:

if (!__builtin_constant_p((int)(uintptr_t)b) || b != 0) {
Run Code Online (Sandbox Code Playgroud)

这样您只会收到一个警告。

似乎gcc不能__builtin_constant_p在指针类型上执行。总是__builtin_constant_p(b)返回0,所以警告函数总是链接的。铸造bint奇怪的作品。尽管它会丢失指针值的精度,但我们并不关心它,因为我们只检查它是否是常量。