2013-04-20 2 views
5

Этот вопрос беспокоил меня некоторое время. Я никогда не видел другое определение NULL, это всегдаПочему NULL не предопределен компилятором

#define NULL ((void *) 0) 

есть любая архитектура, где NULL определяется diferently, и если да, то почему компилятор не объявить это для нас?

+0

Вы можете использовать '0' вместо' NULL'. – pmg

+0

NULL определяется в 'stddef.h', вам не нужно определять его самостоятельно. – Mat

+0

@pmg 0 не переносится, если ответ на мой первый вопрос верен – stdcall

ответ

3

C 2011 Стандартный, online draft

6.3.2.3 Указатели
...
3 Константа выражение целое число со значением 0, или такое выражение приводится к типу void *, называется null указатель постоянный. 66) Если константа нулевого указателя преобразуется в тип указателя , результирующий указатель, называемый нулевым указателем , гарантированно сравнится неравномерно с указателем на любой объект или функцию.
66) Макрос NULL определен как <stddef.h> (и другие заголовки) в качестве константы нулевого указателя; см. 7.19.

макроNULL является всегда определяется как нулевой величиной постоянной выражения; это может быть голым 0 или 0 приведение к void *, или какой-либо другой интегральное выражение, которое вычисляется в 0. Насколько исходный код обеспокоен, NULL всегда оценит 0.

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

0

Я не знаю ответа на этот вопрос, но я думаю. В C вы обычно делаете много mallocs и, следовательно, много тестов для возвращаемых указателей. Так как malloc возвращает void *, и особенно (void *) 0 после сбоя, NULL - это натурная вещь для определения, чтобы проверить успех malloc. Поскольку это так важно, другие библиотечные функции также используют NULL (или (void *) 0), например fopen. На самом деле все, что возвращает указатель.

Следовательно, здесь нет причин определять это на уровне языка - это просто специальное значение указателя, которое может быть возвращено таким количеством функций.

1

В темноте до ANSI-C старый K & R C имел множество различных реализаций на оборудовании, которое сегодня будет считаться причудливым. Это было до дней ВМ, когда машины были очень «реальными». Адреса нулей были не только прекрасны на этих машинах, но и нулевой адрес мог быть популярен ... Я думаю, что CDC иногда хранил постоянную системы нуля в нуле (и случались странные вещи, если это было задано отличным от нуля).

 if (NULL != ptr)  /* like this */ 
if (ptr)    /* never like this */

Трюк был найти адрес, который вы могли бы безопасно использовать для указания «ничего», как хранить вещи в конце памяти был также популярен, что исключало 0xFFFF на некоторых архитектурах. И эти архитектуры обычно используют адреса слов, а не байтовые адреса.

4

WhozCraig написал эти комментарии к теперь удаленному answer, но его можно было бы довести до полного ответа (и вот что я здесь сделал). Он отмечает:

Интересное примечание: AS/400 является уникальной площадкой, где любой не- действительный указатель считается эквивалентным NULL. Механики, которые они используют для этого, просто потрясающие. «Действительным» в этом смысле является любой 128-битный указатель (платформа использует 128-битное линейное адресное пространство для всего), содержащее «значение», полученное известным доверенным набором команд. Жестко, как верить, int *p = (int *)1; if (p) { printf("foo"); } будет не печать "foo" на этой платформе. Значение, присвоенное p, не является доверенным источником и, следовательно, считается «недействительным» и, таким образом, эквивалентно NULL.

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


Это отмечено сообщество-вики (это не мой ответ - я не должен получить кредит), но он может быть удален, если WhozCraig пишет свой ответ.

Это показывает, что существуют реальные платформы с интересными свойствами указателя.

Были платформы, где #define NULL ((void *)0) не является обычным определением; на некоторых платформах это может быть только 0, на других, 0L или 0ULL или другие соответствующие значения, если компилятор это понимает. C++ не нравится ((void *)0) как определение; системы, в которых заголовки, взаимодействующие с C++, могут не использовать версию указателя void.

Я узнал С на машине, где представление для адреса char * для данного места памяти отличалось от адреса int * для того же места в памяти. Это было в дни до void *, но это означало, что вы должны были правильно объявить malloc() (char *malloc(); - никаких прототипов), и вам нужно было явно указать возвращаемое значение на правильный тип или получить дампы ядра. Будьте благодарны за стандарт C (хотя рассматриваемая машина, ICL Perq - фирменное оборудование из Three Rivers - была в значительной степени заменена к тому времени, когда был определен стандарт).

+2

У меня нет проблем с этим пребыванием. Это было девять лет с тех пор, как я написал код для OS/400, и для всех, кого я знаю, с тех пор он изменился с тех пор, но это была такая невероятно уникальная перспектива в отношении того, как они достигли этого. Я надеюсь, что он достаточно уверен в этом, чтобы все еще быть точным достаточно для прайм-тайма. Только вызов функции «DLL» был близок к интересному, поскольку он буквально запланирован как системное задание. Эта платформа просто * удивительна *. – WhozCraig

Смежные вопросы