Есть ли разница между инициализацией переменных и указателей с помощью NULL или 0?

Какой из следующих методов является более правильным способом инициализации переменной?

int x = 0;
int x = NULL;

А указатели? Мне говорили противоречивые вещи о NULL, например: «NULL лучше всего подходит для инициализации указателей» или «Не используйте NULL, но 0 для инициализации переменной» и так далее... Теперь я прочитал в Интернете, что NULL равно до 0, и я проверил это сам. Так в чем смысл? Почему некоторые люди говорят, что использование NULL не является хорошим выбором? Есть что-то, чего мне не хватает?


person Claudio Cortese    schedule 12.01.2016    source источник
comment
NULL не равно 0.   -  person Iharob Al Asimi    schedule 13.01.2016
comment
Этот вопрос связан с этим другим вопросом   -  person Magix    schedule 13.01.2016
comment
stackoverflow .com/questions/8288482/   -  person bruceg    schedule 13.01.2016
comment
@iharob Вы говорите, что if ( 0 == NULL ) неправда?   -  person i486    schedule 13.01.2016
comment
@iharob, это странно, я инициализировал целочисленную переменную значением NULL, и когда я напечатал значение переменной, оно было равно 0.   -  person Claudio Cortese    schedule 13.01.2016
comment
Это не то, что я сказал, это не обязательно 0.   -  person Iharob Al Asimi    schedule 13.01.2016
comment
Макрос NULL всегда будет иметь нулевое значение, хотя это может быть чистое выражение 0, (void *) 0 или какое-либо другое целочисленное выражение, которое оценивается как 0.   -  person John Bode    schedule 13.01.2016
comment
@iharob как это возможно? Извините, если я что-то упустил, я новичок в C и программировании в целом.   -  person Claudio Cortese    schedule 13.01.2016
comment
@JohnBode: Неправда. См. мой ответ ниже.   -  person wallyk    schedule 13.01.2016
comment
@ i486: NULL — это макрос. И для многих реализаций C это #define NULL ((void *)0). 0 — целое число. Таким образом, указатель (void *)0 преобразуется в int перед сравнением. Это уже определено реализацией и приведет к сбою (т. Е. Неопределенное поведение) в типичных 64-битных и других системах, где int имеет меньше битов, чем указатель.   -  person too honest for this site    schedule 13.01.2016
comment
@wallyk: Да, верно — N1570, 6.3.2.3/3 и сноска 66. Нулевой указатель constant (который определен как NULL) всегда имеет нулевое значение. После преобразования соответствующий нулевой указатель value может иметь или не иметь нулевое значение.   -  person John Bode    schedule 13.01.2016
comment
@Olaf Если вы сравните 32-битную 0 и 64-битную 0, я думаю, сравнение будет положительным. Это правда?   -  person i486    schedule 13.01.2016
comment
@i486: (void *)0 Стандарт немного двусмыслен здесь. Он допускает только 0 как константу нулевого указателя (NPC) и указывает, что если константа нулевого указателя преобразуется в тип указателя, результирующий указатель называется нулевым указателем.... Проблема в том, что он также позволяет (void *)0 как NPC, который также является нулевым указателем из-за приведения к указателю (здесь не исключается void *). Я предпочитаю использовать представление null pointer, чтобы эта конструкция уже не была нулевой. Но это может быть спорно.   -  person too honest for this site    schedule 13.01.2016
comment
@ i486: В любом случае, отсутствие специального токена для константы нулевого указателя, такой как Pascal, Modula (NIL), было одним из худших решений в раннем C. C++ наконец-то исправил это с помощью nullptr — очень плохо, что C комитет не был таким смелым.   -  person too honest for this site    schedule 13.01.2016
comment
НЕЛЬЗЯ? Я попытался напечатать значение указателя, инициализированного с помощью NULL, и оно было (ноль)   -  person Claudio Cortese    schedule 13.01.2016
comment
@ClaudioCortese: из стандарта C (C11 n1570): аргумент должен быть указателем на void. Значение указателя преобразуется в последовательность печатных символов способом, определяемым реализацией. (подчеркните мое). К вашему сведению: NIL означает «Нет в списке». Для языков, основанных на списках, таких как LISP (ListProcessing), название сразу становится понятным. Обратите внимание, что библиотеки могут использоваться не только языками C или C++, но также, например. программами на Паскале. Некоторые библиотеки могут просто напечатать значение, например. 0x0, другие, например. (null). AFAIK никто не печатает прописные буквы NULL - вероятно, по уважительным причинам.   -  person too honest for this site    schedule 13.01.2016


Ответы (7)


NULL — константа указателя. Вы используете это для инициализации указателя на значение, которое говорит, что оно ни на что не указывает.

В большинстве реализаций C он определяется как:

#define NULL ((void *)0)

Но гарантии этого нет.

person dbush    schedule 12.01.2016
comment
Может быть, поэтому многие люди говорили мне, что использовать NULL не очень хорошая идея? Это может объяснить тайну для меня. - person Claudio Cortese; 13.01.2016
comment
@КлаудиоКортезе Точно. На практике они обычно одинаковы, но если вы зависите от такого поведения, а затем переместите свой код на платформу, где его нет, у вас возникнут всевозможные проблемы. - person dbush; 13.01.2016
comment
Ммм, хорошо, так что это больше связано с переносимостью кода, чем с чем-то еще, верно? - person Claudio Cortese; 13.01.2016
comment
@КлаудиоКортезе Верно. Всегда делайте свой код переносимым, если у вас нет особых причин этого не делать. - person dbush; 13.01.2016
comment
То же самое относится к указателям, если вы хотите объявить и инициализировать указатель, я бы сделал *pointer = 0, а не *pointer = NULL по причине переносимости, верно? - person Claudio Cortese; 13.01.2016
comment
@ClaudioCortese Нет, вы всегда инициализируете указатель с помощью NULL, то есть int *pointer = NULL. - person dbush; 13.01.2016
comment
ОК Почему? Есть ли причина? Я попытался напечатать адрес указателя, предварительно инициализировав его значением NULL, а затем значением 0, и результаты были такими же. - person Claudio Cortese; 13.01.2016
comment
Как я упоминал ранее, NULL обычно равен 0, но не всегда. Поэтому всегда используйте NULL для указателей. - person dbush; 13.01.2016

Какой из следующих методов является более правильным способом инициализации переменной?

// int x = NULL;  `NULL` implies pointer
int x = 0;        // 0 implies integer value and x is an integer.

А указатели?

void *p = NULL;  // `NULL` implies pointer and p is a pointer.
//void *p = 0;   // 0 implies integer value

что NULL равно 0

Он равен по значению, хотя, возможно, и по битовому шаблону. См. ниже +0.0, -0.0 пример.


Если бы NULL всегда был равен 0, то в C он был бы не нужен.

NULL - это а созвучный нулевой указатель - он часто, но не всегда имеет битовую комбинацию нулей. Указатель со значением NULL всегда будет одинаково сравниваться с 0: то же значение, разные битовые комбинации.

Помните, что == сравнивает значения, а не битовые комбинации.

void *a = NULL;
if (a == NULL) Always_True();
if (a == 0) Always_True();

Пример, который может помочь. +0.0 и -0.0 имеют одинаковое значение, один и тот же тип, но разные битовые комбинации. То же самое может произойти и с указателями.

int main(void) {
  double pz = +0.0;
  double nz = -0.0;
  printf("=:%d  bits:%d\n", pz == nz, memcmp(&pz, &nz, sizeof pz) == 0);  // =:1  bits:0
  return 0;
}
person chux - Reinstate Monica    schedule 12.01.2016

NULL — это константа нулевого указателя. Вы должны использовать это для инициализации типов указателей.

Из C11, глава §7.19, stddef.h

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

и для константы нулевого указателя в C, глава §6.3.2.3

Целочисленное константное выражение со значением 0 или такое выражение, приведенное к типу void *, называется константой нулевого указателя.[...]

Итак, это тип указателя.

Для других переменных, не являющихся указателями, вы должны использовать 0.

person Sourav Ghosh    schedule 12.01.2016
comment
Есть ли реальная причина для этого или это просто личное предпочтение? - person Claudio Cortese; 13.01.2016
comment
@ClaudioCortese Какой из них является личным предпочтением? Тип имеет значение. Возможно, в большинстве случаев реализация эквивалентна, но она просто одинакова. Надеюсь понятно. :) - person Sourav Ghosh; 13.01.2016
comment
Я имею в виду, если NULL == 0, почему нормально инициализировать указатели с помощью NULL и почему нельзя инициализировать переменную с помощью NULL? - person Claudio Cortese; 13.01.2016
comment
@ClaudioCortese, скорее всего, что NULL == 0, но это не гарантируется. Обратите внимание на часть определяемую реализацией в моем ответе. - person Sourav Ghosh; 13.01.2016

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

person John Bode    schedule 12.01.2016

Обязательно используйте NULL при инициализации (или сравнении) указателя; это хороший стиль.

Определенно не используйте NULL при работе с целыми числами; это плохой стиль (и он вполне может не сработать).

Не слушайте никого, кто предлагает не использовать NULL с указателями; они, наверное, путаются.

См. список часто задаваемых вопросов C по адресу http://c-faq.com/null/index.html для получения дополнительной информации.

person Steve Summit    schedule 12.01.2016

Теоретически NULL может быть указателем на адрес, отличный от 0. Но на практике такое определение приведет к сбою большого процента программного обеспечения. И это 0 (или (void *)0) в 99,99% случаев.

person i486    schedule 12.01.2016

Были/были развернуты некоторые архитектуры, для которых NULL не равен нулю: Prime 50, Honeywell-Bull, серия CDC Cyber ​​180 и другие. В этих случаях NULL определенно не взаимозаменяем с нулем.

Подробнее о затронутых машинах см. этот ответ на другой вопрос.

person wallyk    schedule 12.01.2016
comment
Мы говорим о нулевом указателе constant или нулевом указателе value? Что касается C, константа нулевого указателя всегда имеет нулевое значение. - person John Bode; 13.01.2016
comment
@JohnBode: Да, всегда полезно различать NULL (макрос), нулевой указатель и константу нулевого указателя. - person too honest for this site; 13.01.2016
comment
К делу: ответ Уоллика вводит в заблуждение; NULL обычно определяется как некоторая версия 0 даже на тех вычурных старых машинах, где нулевые указатели не равны 0. См. список часто задаваемых вопросов по языку C, вопрос 5.5. - person Steve Summit; 13.01.2016