Как избежать "null аргумент, где требуется ненулевой" предупреждение компилятора


Компиляция следующего кода:

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

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

    if (FOO)
        foo = strdup(FOO);

    return 0;
}

Приводит к следующему предупреждению компилятора:

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

Однако strdup не будет вызываться, если FOO является NULL из-за проверки if (FOO). Есть ли способ избежать этого предупреждения?

Спасибо!

2 4

2 ответа:

Если идея состоит в том, чтобы присвоить значение foo, если FOO определено, вы можете попробовать:

//#define FOO "lorem ipsum"

int main()
{
    char *foo;
    #ifdef FOO
        foo = strdup(FOO);
    #endif
}

У него также есть преимущество, что весь код if не включается, когда он не нужен.

Вы правы, что вы защитили вызов strdup с предложением, чтобы гарантировать, что strdup никогда не вызывается с аргументом NULL.

Но та часть компилятора, которая выдает предупреждение для вызова функции, не является той же самой частью, которая знает, что вызов никогда не может произойти.

Вместо этого вы можете скрыть NULL выражением, которое гарантирует, что сгенерированное выражение аргумента никогда не может быть NULL.

Например

if (FOO) foo = strdup(FOO?FOO:"");

Или

if (FOO) foo = strdup(FOO + !FOO);

Здесь "ясно" (по крайней мере компилятору), что strdup не может быть вызвано со значением NULL, и Ваше предложение if гарантирует, что оно никогда не вызывается с тем, что было, больше не является значением NULL.

В этот момент мы машем руками и говорим, что компилятор оптимизирует все это, и чтобы помочь нам визуально оптимизировать все это, у нас есть:

#define NON_NULL(x) ((x)?(x):"")

И для отладочных сборок, что-то вроде:

#define NON_NULL(x) ((x)?(x):(abort(),""))

Мы might использует расширение GNU ?: (с необязательным пропуском среднего предложения по умолчанию к первому предложению), чтобы избежать оценки (x) более одного раза.

#define NON_NULL(x) ((x)?:"")

И для отладочных сборок, что-то вроде:

#define NON_NULL(x) ((x)?:(abort(),"")
Теперь вы можете представить нечто технически более неясное, но, по-видимому, более значимое:
if (FOO) foo = strdup(NON_NULL(FOO));

И притворимся, что NON_NULL - Это какая-то формальная нотация и подтверждение.