Kiedy makro NULL nie było 0?

Pamiętam, że czytałem o tym kilka lat temu, ale nie mogę znaleźć żadnego odniesienia w sieci.

Czy możesz podać mi przykład, w którym makro NULL Nie rozszerzyło się do 0?

Edit dla jasności: dziś rozszerza się na albo ((void *)0), (0), lub (0L). Jednak były architektury dawno zapomniane, gdzie nie było to prawdą, a NULL rozszerzył się na inny adres. Coś jak

#ifdef UNIVAC
     #define NULL (0xffff)
#endif
[[4]] Szukam przykładu takiego maszyna.

Aktualizacja w celu rozwiązania problemów:

Nie chodziło mi o to pytanie w kontekście obecnych standardów, ani o denerwowanie ludzi moją nieprawidłową terminologią. Jednak moje założenia zostały potwierdzone zaakceptowaną odpowiedzią:

[[18]}późniejsze modele używały [bla], widocznie jako sop do wszystkich zachowanych źle napisanych kodów C, które zawierały błędne założenia.

Aby zapoznać się z dyskusją na temat wskaźników null w obecnym standardzie, zobacz to pytanie.

Author: Community, 2010-04-08

7 answers

C FAQ zawiera kilka przykładów historycznych maszyn z reprezentacjami non-0 NULL.

Z listy C FAQ, pytanie 5.17:

P: poważnie, czy jakieś rzeczywiste maszyny naprawdę używały nonzero null wskaźniki, czyli różne reprezentacje wskaźników do różnych typy?

A: Seria Prime 50 używała segmentu 07777, offset 0 dla null wskaźnik, przynajmniej dla PL / I. późniejsze modele stosowały segment 0, offset 0 dla wskaźniki null w C, np. tcnp (Test C wskaźnik Null), widocznie jako sop do [przypis] wszystkich istniejących źle napisany kod C, który zawierał błędne założenia. Starsze, word-addressed Prime machines notorycznie wymagały również większych wskaźnik bajtowy (char *'S) niż wskaźnik Worda (int *' s).

Seria Eclipse MV Z Data General ma trzy architektury obsługiwane formaty wskaźników (word, byte i BIT), z których dwa są używane przez C Kompilatory: wskaźniki bajtowe dla char * i {[3] } oraz word wskazówki na wszystko inne. Ze względów historycznych podczas ewolucja 32-bitowej linii MV z 16-bitowej linii Nova, word wskaźniki i wskaźniki bajtów miały offset, indirection i ring bity ochronne w różnych miejscach w słowie. Mijając niedopasowany format wskaźnika do funkcji powodował błędy ochrony. Ostatecznie kompilator MV C dodał wiele opcji kompatybilności, aby spróbować aby poradzić sobie z kodem, który miał wskaźnik wpisz błędy niedopasowania.

Niektóre ramki mainframe Honeywell-Bull używają wzorca bitowego 06000 dla (wewnętrzne) wskaźniki null.

Seria CDC Cyber 180 ma 48-bitowe wskaźniki składające się z pierścienia, segment i przesunięcie. Większość użytkowników (w ringu 11) ma wskaźniki null 0xB00000000000. Było powszechne na starych maszynach CDC - dopełniających do używaj słowa jednego bita jako specjalnej flagi dla wszystkich rodzajów danych, łącznie z nieprawidłowymi adresami.

[[10]}stara Seria HP 3000 wykorzystuje inny schemat adresowania bajtów adresów niż w przypadku adresów słownych; podobnie jak kilka maszyn powyżej dlatego używa różnych reprezentacji dla char * i void * wskaźniki niż dla innych wskaźników.

Maszyna Symbolics Lisp, oznaczona architekturą, nie ma nawet konwencjonalnych wskaźników numerycznych; używa pary <NIL, 0> (zasadniczo nie istnieje <object, offset> handle) jako wskaźnik C null.

W zależności od używanego "modelu pamięci", procesory z rodziny 8086 (PC compatibles) mogą korzystać z 16-bitowych wskaźników danych i 32-bitowej funkcji pointers, lub vice versa.

Niektóre 64-bitowe maszyny Cray reprezentują int * w niższych 48 bitach word; char * DODATKOWO używa niektórych z górnych 16 bitów, aby wskazać adres bajtowy w słowie.

 35
Author: janks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-18 05:16:35

Był czas dawno temu, kiedy został wpisany jako ((void*)0) lub inny sposób specyficzny dla maszyny, gdzie ta maszyna nie używała wzorca bitowego.

Niektóre platformy (niektóre maszyny CDC lub Honeywell) miały inny wzorzec bitowy Dla NULL (tj. Nie wszystkie zera), chociaż ISO / ANSI poprawiło to przed ratyfikacją C90, określając, że 0 jest prawidłowym wskaźnikiem NULL w kodzie źródłowym, niezależnie od podstawowego wzorca bitowego. Z C11 6.3.2.3 Pointers /4 (choć, jak wspomniano, to sformułowanie sięga aż do C90):

Wyrażenie stałej całkowitej o wartości 0, lub takie wyrażenie oddane do typu void *, nazywa się stałą wskaźnika null.

 4
Author: paxdiablo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-18 07:41:30

W kompilatorach C może rozwinąć się do ' ((void *)0)' (ale nie musi tego robić). Nie działa to w przypadku kompilatorów C++.

Zobacz także C FAQ, który zawiera cały rozdział o wskaźnikach null .

 3
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-08 02:23:03

W GNU libio.plik 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

Zwróć uwagę na kompilację warunkową _ _ cplusplus. C++ nie może używać ((void*) 0) ze względu na bardziej rygorystyczne zasady dotyczące rzucania wskaźników; standard wymaga, aby NULL było 0. C pozwala na inne definicje NULL.

 3
Author: dan04,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-08 02:27:50

Kompilatory C zwykle używają ((void *)0). Powodem jest przekazanie NULL do funkcji ze zmiennymi argumentami (lub obecnie rzadko spotykanych, ale wciąż legalnych funkcji bez prototypu). Gdy wskaźniki są większe niż int, 0 będzie tylko promowany do int i dlatego nie będzie poprawnie odczytywany jako wskaźnik.

Kompilatory C++ nie mogą używać tej definicji, ponieważ C++ nie zezwala na niejawne rzucanie z void * (rzucanie 0 do dowolnego wskaźnika jest w specjalnej obudowie). Jednak C++11 wprowadził nowe słowo kluczowe nullptr, które jest null stała wskaźnika typu specjalnego nullptr_t jest domyślnie zamieniana na dowolny typ wskaźnika, ale nie na liczbę. Rozwiązuje to zarówno problem zmiennego argumentu, jak i ukrytego cast i dodatkowo poważniejsze problemy z wyborem przeciążenia (0 z oczywistych powodów wybiera int przeciążenie nad wskaźnikiem pierwszym). Jest to legalne, aby zdefiniować je samodzielnie dla starszych kompilatorów i niektóre kompilatory C++ próbował to w przeszłości.

 2
Author: Jan Hudec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 10:36:43

W nowoczesnym C, void *pointer = 0; oznacza inicjalizację "wskaźnika", aby nie wskazywać niczego. Jest to specyficzne dla platformy, czy jest to osiągane przez ustawienie bitów "wskaźnika" na wszystkie-zero.

W przeszłości to formalne znaczenie " 0 " w kontekście wskaźnika nie zostało ustalone. Konieczne było ustawienie wskaźnika na rzeczywistą wartość, którą Platforma potraktowała jako "nie wskazuje nigdzie". Jako przykład platforma może wybrać jakiś stały adres, który nigdy nie zostanie zmapowany do strony. W tym w przypadku, w starym kompilatorze Platforma mogła zdefiniować NULL jako:

#define NULL ((void*)0xFFFFF000)

Oczywiście dzisiaj nie ma powodu, by nie definiować tego jako ((void*)0).

 0
Author: John Saunders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-08 02:32:53

NULL makro w C rozszerza się do zdefiniowanej w implementacji stałej wskaźnika null. Może to być cokolwiek (ponieważ jest zdefiniowane w implementacji), ale w kontekście wskaźnika efekt jest zawsze taki sam, jak gdyby rozszerzył się do stałej 0.

Nigdy nie było czasu w historii standardowego C, kiedy NULL rozszerzyło się do czegoś konkretnie nie 0, chyba że uznasz (void *) 0 ZA "Nie 0". Ale (void *) 0 dla {[0] } jest szeroko stosowany do dnia dzisiejszego.

 0
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-01 16:30:54