NULL против нуля в C - PullRequest
       41

NULL против нуля в C

0 голосов
/ 03 апреля 2020

Я недавно прочитал Могу ли я использовать NULL в качестве замены для значения 0?

Короче говоря, в ответах было упомянуто, что использование NULL в качестве замены для значения 0 не предлагается и будет приводить к UB.

Но в Безопасно ли предполагать, что константа NULL равна нулю? , короче говоря, было сказано, что допущение if(!ptr)//ptr is a pointer не совсем неправильно.

Я знаю, что содержание вопроса отличается, но как это можно объяснить тем, что использование NULL в качестве замены для 0 неверно, тогда как if(!ptr) верно? Поскольку if(!ptr) эквивалентно if(ptr==0) (я предполагаю, что это правильно, не уверен).

Кроме того, я использовал if(ptr==0), и он никогда не работал неправильно для меня (чтобы проверить, является ли ptr NULL), и я назначил 0 указателю ptr, и когда я отлаживал, мой код ptr был равен NULL . Эти два опыта безопасны?

Ответы [ 3 ]

2 голосов
/ 03 апреля 2020

С это NULL ссылка на указатель :

Чтобы инициализировать указатель с нулевым значением или присвоить нулевое значение существующему указателю, постоянная нулевого указателя (NULL или любая другая целочисленная константа со значением ноль ).

[Выделение мое]

Таким образом, целочисленная константа 0 является действительной константой нулевого указателя.

Но обратите внимание, что она не Это не означает, что фактическое нулевое значение на используемой аппаратной платформе равно 0, это означает лишь то, что компилятор принимает 0 в качестве псевдонима для системной константы нулевого указателя.

Также, нулевой указатель всегда «ложь», а ненулевой указатель всегда «истина», поэтому условие типа if (ptr) или if (!ptr) работает хорошо.

1 голос
/ 03 апреля 2020

NULL - это макрос. Это «определяемая реализацией константа нулевого указателя;» C17dr § 7.19 3.

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

Так что NULL может иметь тип void *, int, long, unsigned, long long, et c.

0 - это int константа.

Когда все в порядке.

Назначение : оба значения ниже назначают p,q к некоторому нулевой указатель .

void *p = 0;
void *q = NULL; 

Сравнение кодов : p==q верно, поскольку все нулевые указатели равны. Все нулевые указатели не равны адресу какого-либо объекта. !p и !q оба равны 1.

Когда все не в порядке.

Аргумент функции

Тип и его размер NULL определяется реализацией.

printf("%d\n", 0);            // OK - %d expects an int
printf("%d\n", NULL);         // Not OK, NULL could be long, void *, etc.
printf("%p\n", NULL);         // Not OK, NULL could be int, long, long long
printf("%p\n", (void*) NULL); // OK - %p expects a void*

_Generic()

Результат ниже определяется реализацией.

_Generic((NULL), \
  void *: "void *", \
  int: "int", \
  long: "long", \
  default: "TBD")

Сравнение макросов

Приведенное ниже сообщение "error: operator '*' не имеет правого операнда" для меня. #if !0 было хорошо.

#if !NULL
#error foo
#endif
1 голос
/ 03 апреля 2020

Я знаю, что содержание вопроса отличается, но как это объяснить, что использование NULL в качестве замены для 0 неверно, а if(!ptr) - правда? Поскольку if(!ptr) эквивалентно if(ptr==0) (я предполагаю, что это правильно, не уверен).

if(!ptr) эквивалентно if (!ptr != 0) семантикой операторов if, что эквивалентно if (ptr == 0) семантикой операторов !, != и == с операндами-указателями. Это хорошо согласуется, но это не следует из того, что вы знаете об операциях с целыми числами. Операции над указателями имеют свои собственные правила.

И это именно то, что нужно. Поскольку целочисленная константа со значением ноль - которая является конструктом исходного кода - является, среди прочего, константой нулевого указателя, она по определению сравнивается равной всем значениям нулевого указателя , Это вообще ничего не говорит о представлении значений нулевого указателя любого типа, о типе выражения, в которое расширяется макрос NULL, или о значении, полученном путем преобразования в целое число любого конкретного значения нулевого указателя, которое не представлено в исходный код в виде целочисленной константы со значением ноль.

...