如何避免"null参数需要非null null"编译器警告

pro*_*oom 5 c strdup gcc-warning

编译以下代码:

#include <string.h>
#define FOO (NULL)

int main(int argc, char *argv[])
{
    char *foo;

    if (FOO)
        foo = strdup(FOO);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

导致以下编译器警告:

foo.c: In function ‘main’:
foo.c:9:3: warning: null argument where non-null required (argument 1) [-Wnonnull]
   foo = strdup(FOO);
   ^
Run Code Online (Sandbox Code Playgroud)

但是,strdup如果FOONULL因为if (FOO)检查将不会被调用.有没有办法避免这种警告?

谢谢!

Sam*_*ott 6

您是正确的,您已经保护了strdupwith 子句的调用,以确保strdup永远不会用NULL参数调用。

但是为函数调用发出警告的编译器部分与知道调用永远不会发生的部分不同。

您可以NULL使用一个表达式来掩盖 ,以确保生成的参数表达式永远不会是NULL

例如

if (FOO) foo = strdup(FOO?FOO:"");
Run Code Online (Sandbox Code Playgroud)

或者

if (FOO) foo = strdup(FOO + !FOO);
Run Code Online (Sandbox Code Playgroud)

这是strdup不能用NULL值调用的“明确”(至少对编译器而言),并且您的if子句确保永远不会用不再是NULL值的内容调用它。

这时候我们挥挥手说编译器会把它全部优化掉,为了帮助我们直观地优化它,我们有:

#define NON_NULL(x) ((x)?(x):"")
Run Code Online (Sandbox Code Playgroud)

对于调试版本,例如:

#define NON_NULL(x) ((x)?(x):(abort(),""))
Run Code Online (Sandbox Code Playgroud)

我们可能会使用 GNU 扩展?:(可选的缺失中间子句默认为第一个子句)来避免(x)多次评估。

#define NON_NULL(x) ((x)?:"")
Run Code Online (Sandbox Code Playgroud)

对于调试版本,例如:

#define NON_NULL(x) ((x)?:(abort(),"")
Run Code Online (Sandbox Code Playgroud)

现在你可以展示一些技术上更晦涩但显然更有意义的东西:

if (FOO) foo = strdup(NON_NULL(FOO));
Run Code Online (Sandbox Code Playgroud)

并假装这NON_NULL是一些正式的符号和确认。


Ale*_*exD 4

foo如果想法是为if已定义赋值FOO,您可以尝试:

//#define FOO "lorem ipsum"

int main()
{
    char *foo;
    #ifdef FOO
        foo = strdup(FOO);
    #endif
}
Run Code Online (Sandbox Code Playgroud)

它还具有一个优点,if即不需要时不包含整个代码。