Макрос NULL
требуется для раскрытия до «константы нулевой указатель, определенной реализацией».
A константа нулевой указатель определяется как «целочисленное постоянное выражение со значением 0 или такое выражение, отлитое от типа void *
». В отличие от этого определения не требует, чтобы расширение NULL
являлось выражением типа указателя. Общая реализация является:
#define NULL 0
Нулевой константный указатель, когда он используется в контексте, который требует указатель может быть неявно преобразуется в значение указателя; результатом является нулевая указатель .Он также может быть явно преобразован с использованием литого, например (int*)NULL
.
Но нет требования, чтобы выражение, которое квалифицируется как константа нулевого указателя, может использоваться только в таком контексте. Это означает, что если реализация выбирает определить NULL
, как указано выше, то это:
char c = NULL; // legal but ugly
является законным и инициализирует c
в нуль символов.
Такая инициализация не является портативным (так как NULL
может также расширить до ((void*)0)
и вводит в заблуждение, поэтому его следует избегать, но компилятор может позволить его через без предупреждения; NULL
расширяется до 0
по фазе предварительной обработки компилятор, и более поздние фазы не рассматривают его как char c = 0;
, который является законным и безобидным - хотя лично я предпочел бы char c = '\0';
Я просто попробовал ваш пример на моей 32-битной систему Ubuntu с GCC 4.7 при отсутствии.. опционы, компилятор предупреждал обо всех p[2]=NULL;
и p[1]=(void *)0;
:
c.c:8:9: warning: assignment makes integer from pointer without a cast [enabled by default]
c.c:10:9: warning: assignment makes integer from pointer without a cast [enabled by default]
Второе предупреждение ожидается от любого компилятора C; первый указывает, что NULL
фактически определен как ((void*)0)
(код запуска через gcc -E
подтверждает это).
Компилятор не просто «принял» эти задания; он предупредил вас о них. Стандарт языка C просто требует «диагностики» для любого нарушения языковых правил, даже синтаксической ошибки; эта диагностика может на законных основаниях быть нефатальным предупреждающим сообщением. Вы можете сделать gcc более строго с -std=c89 -pedantic-errors
; замените c89
на c99
или c11
для обеспечения соблюдения правил из более поздних версий стандарта. (EDIT: Я вижу из комментариев, что вы используете веб-интерфейс для компилятора, который скрывает предупреждения, см. Мой комментарий к вашему вопросу об обходном пути. Предупреждения важны.)
Если вы публикуете код на C, который генерирует предупреждения компилятора показать нам предупреждения и обратить на них самое пристальное внимание. Они часто указывают на серьезные проблемы, даже нелегальные, в вашей программе.
Язык-адвокат каламбур: это даже не ясно, что это:
char c = (void*)0;
определяет преобразование из void*
в char
. Мое собственное мнение состоит в том, что, поскольку оно нарушает ограничение, оно не имеет определенной семантики. Большинство компиляторов, которые не отклоняют его, будут относиться к нему так, как если бы это было преобразование void*
-to- char
, и также утверждалось, что это необходимое поведение. Но вы можете избежать таких вопросов, если просто обратите внимание на предупреждения компилятора и/или не пишете такой код в первую очередь.
(правила немного отличаются для C++, но вы спрашиваете о C, так что я не буду вдаваться в это.)
ли компилятор производить какие-либо предупреждения для этой программы? Если да, отредактируйте свой вопрос, чтобы показать их нам. –
@Grijesh Chauhan Спасибо за редактирование – Neeraj
@KeithThompson, Это был онлайн-редактор, который не выдавал никаких предупреждений. – Neeraj