Когда ПУСТОЙ УКАЗАТЕЛЬ был макросом не 0?

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

Можно ли дать мне пример, где ПУСТОЙ макрос не расширился до 0?

Редактирование для ясности: Сегодня это расширяется до также ((void *)0), (0), или (0L). Однако была архитектура, давно забытая, где это не было верно, и ПУСТОЙ УКАЗАТЕЛЬ, расширенный до другого адреса. Что-то как

#ifdef UNIVAC
     #define NULL (0xffff)
#endif

Я ищу пример такой машины.

Обновление для решения проблем:

Я не имел в виду этот вопрос в контексте текущих стандартов, или расстраивать людей с моей неправильной терминологией. Однако мои предположения были подтверждены принятым ответом:

Более поздние модели используются [вздор], очевидно как кусок ко всему существующему плохо записанному коду C который сделанные неправильными предположениями.

Для дискуссии о нулевых указателях в текущем стандарте посмотрите этот вопрос.

33
задан Community 23 May 2017 в 12:13
поделиться

6 ответов

В FAQ по C есть несколько примеров исторических машин с представлениями, отличными от 0 NULL.

Из Списка часто задаваемых вопросов по C , вопрос 5.17 :

В: Серьезно, действительно ли какие-либо машины действительно использовали ненулевые нулевые указатели или другие представления для указатели на разные типы ?

A: Серия Prime 50 использовала сегмент 07777, смещение 0 для нулевого указателя , по крайней мере, для PL / I. В более поздних моделях для нулевых указателей в C использовался сегмент 0, смещение 0, что требовало новых инструкций, таких как TCNP (Test C Null Pointer), очевидно, в качестве подачки [сноски] ко всем существующим {{ 1}} плохо написанный код C, делающий неверные предположения. Старые машины Prime с адресом слов также были известны тем, что требовали больших байтовых указателей ( char * ), чем указатели слов ( int * ' с).

Серия Eclipse MV от Data General имеет три архитектурно поддерживаемых формата указателя (словесные, байтовые и битовые указатели), два из которых используются компиляторами C: байтовые указатели для char * и void * , а также указатели word для всего остального. По историческим причинам во время эволюции 32-битной строки MV из 16-битной строки Nova указатели слов и байтовые указатели имели защиту смещения, косвенности и кольца биты в разных местах в слове. Передача несоответствующего формата указателя в функцию приводила к ошибкам защиты. В конце концов, компилятор MV C добавил много параметров совместимости, чтобы попытаться справиться с кодом, в котором были ошибки несоответствия типа указателя .

Некоторые мэйнфреймы Honeywell-Bull используют битовый шаблон 06000 для (внутренних) нулевых указателей.

CDC Cyber ​​180 Series имеет 48-битные указатели, состоящие из кольца, сегмента и смещения. Большинство пользователей (в кольце 11) имеют нулевые указатели 0xB00000000000. На старых машинах CDC с дополнением до единицы было обычным делом использовать слово, состоящее из одного бита, в качестве специального флага для всех видов данных, включая недопустимые адреса.

Старая серия HP 3000 использует другую схему адресации для байтовых адресов, чем для словарных адресов; как и некоторые из машин выше , поэтому он использует разные представления для указателей char * и void * , чем для других указателей.

Symbolics Lisp Machine, архитектура с тегами, даже не имеет обычных числовых указателей; он использует пару (в основном, дескриптор несуществующий <объект, смещение> ) в качестве нулевого указателя C.

В зависимости от используемой «модели памяти» процессоры семейства 8086 (совместимые с ПК ) могут использовать 16-разрядные указатели данных и 32-разрядные указатели функций или наоборот.

Некоторые 64-битные машины Cray представляют int * в младших 48 битах слова ; char * дополнительно использует некоторые из старших 16 битов для указания байтового адреса в слове.

32
ответ дан 27 November 2019 в 18:35
поделиться

Давным-давно это было напечатано как ((void *) 0) или какой-либо другой машинно-зависимый способ, где эта машина не использовала битовый шаблон «все нули».

Некоторые платформы (некоторые машины CDC или Honeywell) имели другой битовый шаблон для NULL (т. Е. , а не все нули), хотя ISO / ANSI исправил это до ратификации C90, указав, что 0 был правильным указателем NULL в исходном коде, независимо от базовой битовой комбинации. Из C11 6.3.2.3 Pointers / 4 (хотя, как уже упоминалось, эта формулировка восходит к C90):

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

3
ответ дан 27 November 2019 в 18:35
поделиться

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

В стандартной истории C никогда не было случая, когда NULL расширялся до чего-то конкретно не 0 , если только вы не рассматриваете (void *) 0 как " не 0 ". Но (void *) 0 для NULL широко используется и по сей день.

0
ответ дан 27 November 2019 в 18:35
поделиться

В файле GNU libio.h:

#ifndef NULL
# if defined __GNUG__ && \
(__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
#  define NULL (__null)
# else
#  if !defined(__cplusplus)
#   define NULL ((void*)0)
#  else
#   define NULL (0)
#  endif
# endif
#endif

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

2
ответ дан 27 November 2019 в 18:35
поделиться

В компиляторах C он может расширяться до ' ((void *) 0) ' (но не обязательно) . Это не работает для компиляторов C ++.

См. Также C FAQ, в котором есть целая глава о нулевых указателях .

3
ответ дан 27 November 2019 в 18:35
поделиться

В современном C void * pointer = 0; предназначен для инициализации «указателя», чтобы он ни на что не указывал. Это зависит от платформы относительно того, достигается ли это установкой битов «указателя» на все нули.

В прошлом это формальное значение «0» в контексте указателя не было установлено. Необходимо было установить указатель на фактическое значение, которое платформа трактовала как «никуда не указывает». Например, платформа может выбрать какой-то фиксированный адрес, которому никогда не сопоставляется страница. В этом случае в старом компиляторе платформа могла бы определить NULL как:

#define NULL ((void*)0xFFFFF000)

Конечно, сегодня нет причин не определять его как ((void *) 0) .

0
ответ дан 27 November 2019 в 18:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: