В чем разница между указателем, указывающим на местоположение 0x0, и указателем, установленным в NULL?

12

Указатель, указывающий на 0x0000, совпадает с указателем, установленным в NULL? Если значение NULL определено на языке Си, то в какое место оно физически переводится? Это так же, как 0x0000. Где я могу найти более подробную информацию об этих понятиях?

Arpith
источник
1
Об этом уже спрашивали в переполнении стека - stackoverflow.com/questions/1296843/… . Я думаю, что это граница для нас, но я готов дать ей преимущество сомнения на данный момент.
ChrisF

Ответы:

12

Дело в том, что большинство ответов здесь не адресованы, по крайней мере, не явно, в том, что нулевой указатель - это значение, которое существует во время выполнения, а константа нулевого указателя - это синтаксическая конструкция, которая существует в исходном коде C.

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

NULLэто макрос, определенный в <stddef.h>некоторых других стандартных заголовках, который расширяется до определенной в реализации постоянной нулевого указателя . Расширение обычно либо: 0либо ((void*)0)(внешние скобки необходимы для соответствия другим языковым правилам).

Таким образом, литерал 0, когда используется в контексте, который требует выражения типа указателя, всегда оценивается как a null pointer, то есть уникальное значение указателя, которое указывает на отсутствие объекта. Это не подразумевает ничего о представлении нулевого указателя . Нулевые указатели очень часто представлены как все биты-ноль, но они могут быть представлены как что-либо. Но даже если указатель нулевой представляется в виде 0xDEADBEEF, 0или (void*)0по - прежнему является постоянным указателем нулевой .

Ответ на вопрос о StackOverflow охватывает это хорошо.

Это подразумевает, среди прочего, что memset()или calloc(), который может установить область памяти равной нулю, все необязательно будет устанавливать любые указатели в этой области на нулевые указатели. Они, вероятно, делают это в большинстве реализаций, но язык не гарантирует этого.

Я не знаю , почему этот вопрос не считается дубликатом этого одного , или , как это актуально здесь.

Кит Томпсон
источник
1
Один из моих доводов в отношении дизайна и развития языка C состоит в том, что цифра ноль продолжает использоваться в качестве недревесного представления нулевого указателя. Еще в самые ранние дни языка (например, до появления таких вещей, как прототипы функций) указатели и целые числа были достаточно взаимозаменяемыми, чтобы использование «0» для нулевого указателя было простым и «просто работало». Однако, когда стало необходимо различать целое число ноль и нулевой указатель, представление «0» должно было быть признано устаревшим в пользу ключевого слова или последовательности операторов.
суперкат
Означает ли это, что указатель NULL может фактически указывать на некоторое местоположение, когда ему присваивается значение NULL, в зависимости от платформы? Константа нулевого указателя может быть синтаксической конструкцией, но что именно происходит при выполнении кода? Предположим, эта синтаксическая конструкция была скомпилирована на платформе GNU / Linux. Каково значение указателя, когда мы присваиваем ему значение NULL? Чем этот адрес отличается от любого другого адреса?
Арфит
1
@Arpith: Присвоение NULLили любая константа нулевого указателя объекту указателя устанавливает значение этого объекта в нулевой указатель . На уровне машины это может указывать на некоторый допустимый кусок памяти. Разыменование нулевого указателя имеет неопределенное поведение; доступ к фрагменту памяти по адресу 0x0000000является допустимым поведением, как и буквально все остальное. Этот адрес отличается от любого другого адреса тем, что (а) сравнение равно NULLи (б) сравнение неравнозначно любому указателю на объект С. Нулевой указатель - это произвольное значение указателя, используемое для указания того, что оно ни на что не указывает.
Кит Томпсон
1
На уровне машины это может указывать на некоторый допустимый кусок памяти, но в большинстве сред C это будет указывать на недопустимую память, так что любая попытка использовать указатель приведет к аппаратной ловушке / ошибке / исключению. Обычно это только на самых простых аппаратных платформах - без поддержки управления памятью - где указатель NULL указывает на допустимое расположение памяти.
Соломон Слоу
7

Каждая платформа может определять NULL по своему усмотрению.

В соответствии со стандартом C, если вы присвоите указателю ноль, он будет преобразован в значение NULL (для этой платформы.) Однако, если вы возьмете указатель NULL и приведете его к типу int, нет никаких гарантий, что вы получите ноль на каждой платформе там. Дело в том, что на большинстве платформ он будет нулевым.

Информацию об этом материале вы можете найти в Спецификации языка Си . Один источник, за достоверность которого я не могу поручиться, это: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf

Майк Накис
источник
2
Если они решат отойти от стандарта, они могут переопределить NULL pointer constant. Насколько я знаю, там нет компиляторов, которые делают это.
Карлсон
Есть ли компилятор, который не реализует NULL как 0? И гарантированно ли значение NULL равно false?
Угорен
Стандарт NULL гарантированно оценивает как ложный. Я не знаю, есть ли какой-либо компилятор (платформа, на самом деле), который не реализует NULL как 0, и я серьезно сомневаюсь в этом, но стандарт не запрещает это, так что кто знает.
Майк Накис
Существует путаница между представлением абстрактной «указатель нулевой константы» (как указано в спецификации) в памяти, которая может быть как платформа мейкера радует и определение NULLмакроса, который должен расширяться 0в C ++ и либо 0или (void *)0в C, потому что это настоящая «константа нулевого указателя».
Ян Худек
Хотя теоретически NULL может быть определен как что-либо, в соответствии со стандартом существует гарантия, что константа int со значением 0, приведенным к указателю, приведет к нулевому указателю (ISO 9899: 1999 6.3.2.3/3). Макрос NULL в stddef.h должен быть нулевым указателем (7.17 / 3), поэтому компилятору было бы очень обременительно не реализовывать NULL как 0 или (void *) 0.
1

Он определен на языке Си, потому что нет ни одного неизменного машинного адреса, которому он соответствует. Если бы это было так, нам бы не понадобилась абстракция! Несмотря на то, что на большинстве платформ NULL может в конечном итоге быть реализован как 0 того или иного типа, просто неправильно полагать, что это универсально, если вы вообще заботитесь о переносимости.

Килиан Фот
источник
Вот какие стандарты для open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Карлсон
0

Согласно разделу « Стандартный документ C » 6.3.2.3:

Целочисленное константное выражение со значением 0 или такое выражение, приведенное к типу void *, называется константой нулевого указателя.55) Если константа нулевого указателя преобразуется в тип указателя, результирующий указатель, называемый нулевым указателем, имеет вид гарантированно сравнивать неравный указатель с любым объектом или функцией.

До сих пор я не видел компилятор, который оторвался от этого.

Карлсон
источник
@ PéterTörök Ты прав, это тиоп. :)
Карлсон
1
Да, но обратите внимание, что он ничего не говорит о указателе, который на самом деле имеет числовое значение 0. Он не может, хотя на большинстве платформ это так.
Ян Худек