2014-10-22 6 views
3

Компиляция следующего кода:Как избежать «нулевого аргумента, где ненулевые требуется» предупреждение компилятора

#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) проверка. Есть ли способ избежать этого предупреждения?

Спасибо!

+0

После предварительной обработки это будет читать: 'if ((NULL)) foo = strdup ((NULL));', что, вероятно, является причиной ошибки. 'strdup' хочет' const char * ', который не является' NULL'. – bzeaman

+3

Вызов 'strdup (NULL)' в любом случае бессмыслен, так что не беспокойтесь. Предупреждение верно. –

+0

Что вы делаете, это неопределенное поведение, но '-Wno-nonnull' отключит предупреждение. [Руководство по GCC.] (Https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) –

ответ

3

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

//#define FOO "lorem ipsum" 

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

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

+0

Отлично, спасибо! – profzoom

+0

@Deduplicator Какой компилятор вы используете? Если 'FOO' является строкой, VC++ дает« _invalid integer constant expression_ », GCC -« _token ... недопустим в препроцессорных выражениях ». (Хотя на первый взгляд, согласно стандарту, '# if' требует постоянного выражения, а не константного выражения _integer_.) – AlexD

0

Вы правы, что вы защитили вызов 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(),"")) 

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

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

и для отладки строит, что-то вроде:

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

Теперь вы можете представить что-то, что является технически более неясными, но, видимо, более значимым:

if (FOO) foo = strdup(NON_NULL(FOO)); 

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