Нет предупреждения при возврате NULL с помощью gcc

Используя gcc 5.2.0, я заметил, что этот код не выдает предупреждение:

#include <stddef.h>

int function(void)
{
    return NULL;
}

void procedure(void)
{
    return NULL;
}

Я использовал флаги -Wall -Wextra -std=c99 -pedantic и использую archlinux. Я не уверен, почему этот код отлично работает на gcc, тем более что clang 3.7.0 выдает предупреждение.

Я также пытался использовать более старые версии gcc, такие как 4.9 или 4.7, и обе они генерировали предупреждения.

Предупреждения:

warning: return makes integer from pointer without a cast

и

warning: ‘return’ with a value, in function returning void

Я должен упомянуть, что я пытался скомпилировать gcc 5.2 на Debian, и результат тот же. Так что проблема не в archlinux.

В чем причина? Кажется, я не могу найти ничего, связанного с этим, где-либо еще.

Благодарю вас!


person damwdan    schedule 23.09.2015    source источник
comment
возможный дубликат заголовка stackoverflow.com/questions/1610030/   -  person Potato    schedule 23.09.2015
comment
Лол, ты имеешь в виду обратный дубликат? Этот вопрос спрашивает, почему вы можете вернуть значение в теле функции void. Дубликат спрашивает, почему вы можете написать тело непустой функции без оператора возврата.   -  person BitTickler    schedule 23.09.2015
comment
Было бы полезно, если бы вы опубликовали предупреждающее сообщение.   -  person juanchopanza    schedule 23.09.2015
comment
@juanchopanza вопрос был в том, почему нет ... и его задавали раньше. короткий ответ, предупреждение будет с -Wconversion.   -  person    schedule 23.09.2015
comment
@FelixPalmen, о котором я говорил, особенно потому, что clang 3.7.0 действительно генерирует предупреждение ..   -  person juanchopanza    schedule 23.09.2015
comment
Просто ради интереса... кто-нибудь знает, что с этим сделает компилятор compcert?   -  person BitTickler    schedule 23.09.2015
comment
@juanchopanza Я добавил предупреждения! @FelixPalmen -Wconversion ничего не изменил.   -  person damwdan    schedule 23.09.2015
comment
-Wsystem-headers исправляет это, компилятор использует неправильное место для диагностики (тот, что из определения макроса). Пожалуйста, отправьте отчет об ошибке в bugzilla gcc.   -  person Marc Glisse    schedule 23.09.2015


Ответы (3)


Похоже, это регресс в gcc 5.2.0 — и, насколько я могу судить, странный.

В gcc 4.4.5 и 4.8.4 программа (после добавления необходимого #include <stddef.h>) выдает предупреждения для обоих операторов return NULL; даже без каких-либо дополнительных параметров командной строки.

В gcc 5.2.0 предупреждение не выдается даже с gcc -c -Wall -Wextra -std=c99 -pedantic. Для второго, возвращающего значение из функции void, диагностика обязательна.

Теперь вот странная часть.

$ gcc --version | head -n 1
gcc (GCC) 5.2.0
$ cat c.c
#include <stddef.h>

int function(void) {
#ifdef USE_NULL
   return NULL;
#else
    return ((void*)0);
#endif
}

void procedure(void) {
#ifdef USE_NULL
   return NULL;
#else
    return ((void*)0);
#endif
}
$ gcc -c c.c
c.c: In function ‘function’:
c.c:7:12: warning: return makes integer from pointer without a cast [-Wint-conversion]
     return ((void*)0);
            ^
c.c: In function ‘procedure’:
c.c:15:12: warning: ‘return’ with a value, in function returning void
     return ((void*)0);
            ^
$ gcc -c -DUSE_NULL c.c
$ 

Когда определено USE_NULL, никаких предупреждений не выдается. Компиляция с gcc -E -DUSE_NULL (которая выводит вывод препроцессора на стандартный вывод) подтверждает, что NULL определяется как ((void*)0). Но когда я заменяю NULL на ((void*)0), выдаются предупреждения (как и должно быть).

Я не знаю, что происходит. После раскрытия макроса NULL он должен быть неотличим от ((void*)0), и тем не менее поведение компилятора меняется в зависимости от того, какой макрос используется.

person Keith Thompson    schedule 23.09.2015
comment
Вы, вероятно, имеете в виду 5.2.0. - person Antoine Pietri; 23.09.2015

Действительность первой функции зависит от того, как определяется NULL. С первой функцией проблем нет, если NULL определяется как 0. Но если она определена как (void *) 0 (что обычно имеет место в коде C), первая функция становится недействительной. GCC часто очень снисходительно относится к неявным преобразованиям указателя в целое число.

Вторая функция абсолютно недействительна. В спецификации языка четко указано, что «оператор возврата с выражением не должен появляться в функции, возвращаемый тип которой недействителен». Если он компилируется, это должен быть еще один пример чрезмерной снисходительности GCC.

Вам нужно запустить GCC в режиме -pedantic, если вы хотите, чтобы его диагностический вывод был связан со стандартным языком C. В режиме по умолчанию он не является заслуживающим доверия компилятором C (по крайней мере, с точки зрения его диагностического вывода), и тот факт, что он «не выдает предупреждения», абсолютно ничего не значит.

Тем не менее, в моих экспериментах мне не удалось заставить GCC жаловаться на вторую функцию даже с переключателями -std= и -pedantic. Похоже на ошибку в компиляторе.

person AnT    schedule 23.09.2015
comment
ОП утверждает, что использует -pedantic. - person juanchopanza; 23.09.2015
comment
Я действительно использую -pedantic. - person damwdan; 23.09.2015

Я заполнил отчет об ошибке здесь: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67730

Это было подтверждено и исправлено для 5.3, кажется!

Спасибо за вашу помощь.

person damwdan    schedule 30.09.2015