Wann war das NULL-Makro nicht 0?

Lesezeit: 9 Minuten

Benutzeravatar von György Andrasek
György Andrasek

Ich erinnere mich vage, vor ein paar Jahren darüber gelesen zu haben, aber ich kann keine Referenz im Internet finden.

Können Sie mir ein Beispiel geben, bei dem das NULL-Makro nicht auf 0 erweitert wurde?

Bearbeiten Sie zur Verdeutlichung: Heute wird es auf beides erweitert ((void *)0), (0)oder (0L). Es gab jedoch längst vergessene Architekturen, bei denen dies nicht der Fall war, und NULL wurde an eine andere Adresse erweitert. Etwas wie

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

Ich suche ein Beispiel für eine solche Maschine.

Update zur Behebung der Probleme:

Ich meinte diese Frage nicht im Zusammenhang mit aktuellen Standards oder um die Leute mit meiner falschen Terminologie zu verärgern. Meine Annahmen wurden jedoch durch die akzeptierte Antwort bestätigt:

Spätere Modelle verwendet [blah]offensichtlich als Beruhigungsmittel für all den vorhandenen schlecht geschriebenen C-Code, der falsche Annahmen machte.

Eine Diskussion über Nullzeiger im aktuellen Standard finden Sie in dieser Frage.

  • NULL wird nicht zu einer Adresse erweitert. Fragen Sie wirklich, wann die NULL Makro wurde für etwas anderes definiert, oder wollen Sie fragen, wann die zugrunde liegende Darstellung der Nullzeigerkonstante nicht alle Bits Null war?

    – jamesdlin

    8. April 2010 um 2:48 Uhr

  • Zuletzt habe ich gesehen, dass es entweder zu ((void *)(3L – 2L – 1L)), (((((0) * 0x55)))) oder (‘\0’) erweitert werden kann. (Das ist in C. Einige davon wären in C++ nicht erlaubt.)

    – Windows-Programmierer

    8. April 2010 um 6:21 Uhr

  • Die Antwort, die Sie akzeptiert haben, beantwortet Ihre Frage nicht wie gestellt. Korrigieren Sie entweder die Frage (falls Sie diese Frage nicht stellen wollten) oder akzeptieren Sie eine andere Antwort erneut. Die Details stehen in den Kommentaren.

    – AnT steht zu Russland

    8. April 2010 um 14:03 Uhr

Benutzeravatar von janks
Janks

Die C-FAQ enthält einige Beispiele historischer Maschinen mit Nicht-0-NULL-Darstellungen.

Aus Die C-FAQ-Liste, Frage 5.17:

F: Im Ernst, haben irgendwelche Maschinen wirklich Nicht-Null-Null-Zeiger oder unterschiedliche Darstellungen für Zeiger auf verschiedene Typen verwendet?

A: Die Prime 50-Serie verwendete Segment 07777, Offset 0 für den Nullzeiger, zumindest für PL/I. Spätere Modelle verwendeten Segment 0, Offset 0 für Nullzeiger in C, was neue Anweisungen wie TCNP (Test C Null Pointer) erforderte, offensichtlich als Lösung [footnote] all der vorhandene schlecht geschriebene C-Code, der falsche Annahmen machte. Ältere, wortadressierte Prime-Maschinen waren auch dafür berüchtigt, dass sie größere Byte-Zeiger (char *‘s) als Wortzeiger (int *‘s).

Die Eclipse MV-Serie von Data General hat drei architektonisch unterstützte Zeigerformate (Wort-, Byte- und Bit-Zeiger), von denen zwei von C-Compilern verwendet werden: Byte-Zeiger für char * und void *, und Wortzeiger für alles andere. Aus historischen Gründen hatten Wortzeiger und Bytezeiger während der Entwicklung der 32-Bit-MV-Zeile von der 16-Bit-Nova-Zeile die Offset-, Umleitungs- und Ringschutzbits an verschiedenen Stellen im Wort. Das Übergeben eines nicht übereinstimmenden Zeigerformats an eine Funktion führte zu Schutzverletzungen. Schließlich fügte der MV C-Compiler viele Kompatibilitätsoptionen hinzu, um zu versuchen, mit Code umzugehen, der Zeigertyp-Nichtübereinstimmungsfehler aufwies.

Einige Mainframes von Honeywell-Bull verwenden das Bitmuster 06000 für (interne) Nullzeiger.

Die CDC Cyber ​​180-Serie verfügt über 48-Bit-Zeiger, die aus einem Ring, Segment und Offset bestehen. Die meisten Benutzer (in Ring 11) haben Nullzeiger von 0xB00000000000. Bei alten CDC-Einerkomplementmaschinen war es üblich, ein Nur-Eins-Bit-Wort als spezielles Flag für alle Arten von Daten zu verwenden, einschließlich ungültiger Adressen.

Die alte HP 3000-Serie verwendet ein anderes Adressierungsschema für Byteadressen als für Wortadressen; Wie einige der oben genannten Maschinen verwendet es daher unterschiedliche Darstellungen für char * und void *
Zeiger als für andere Zeiger.

Die Symbolics Lisp Machine, eine getaggte Architektur, hat nicht einmal herkömmliche numerische Zeiger; es verwendet das Paar <NIL, 0> (im Grunde eine nicht vorhandene <object, offset> handle) als C-Nullzeiger.

Abhängig vom verwendeten “Speichermodell” können Prozessoren der 8086-Familie (PC-kompatibel) 16-Bit-Datenzeiger und 32-Bit-Funktionszeiger verwenden oder umgekehrt.

Einige 64-Bit-Cray-Maschinen repräsentieren int * in den unteren 48 Bits eines Wortes; char * verwendet zusätzlich einige der oberen 16 Bits, um eine Byteadresse innerhalb eines Wortes anzugeben.

  • Im C-Quellcode wäre das NULL-Makro immer noch entweder ein ganzzahliger konstanter Ausdruck, der zu 0 ausgewertet wird, oder eine (void *) Umwandlung desselben. Der resultierende Zeigerwert kann eine Darstellung haben, die nicht 0 ist, aber das bedeutet nicht, dass der Quellcode davon ausgehen kann, dass er 0xffff oder so etwas sein wird.

    – Windows-Programmierer

    8. April 2010 um 6:23 Uhr

  • @Windows Programmer: wahr jetzt, da der C-Standard vorschreibt, dass NULL eine Nullzeigerkonstante ist (im Gegensatz zu jeder Konstante, die einem Nullzeiger entspricht). Alle diese Maschinen sind jedoch älter als der Standard, daher ist es durchaus möglich, dass einer von ihnen dies getan hat #define NULL ((void*)-1)oder #define NULL __nullpointer, wobei __nullpointer ein eingebauter Compiler oder was auch immer ist. Sie sind die richtigen Orte, um nach so etwas zu suchen.

    – Steve Jessop

    8. April 2010 um 8:11 Uhr


  • Entschuldigung, aber die Antwort ist völlig falsch. Die Beispiele in C FAQ sind Beispiele für Maschinen mit Nicht-Null Nullzeigerwerte. Die Frage war über Nicht-Null NULLalso etwa von Null verschieden Nullzeiger-Konstante. Nullzeigerwert und Nullzeigerkonstante sind zwei völlig verschiedene Dinge. Die Antwort verwechselt eine mit der anderen, was ein ziemlich weit verbreiteter Fehler ist (ein Anfängerfehler, sollte ich hinzufügen).

    – AnT steht zu Russland

    8. April 2010 um 13:53 Uhr


  • Die Frage war, was NULL erweitert sich zu. Diese Antwort hat absolut nichts damit zu tun NULL erweitert sich zu. Der Autor der Frage sagt jedoch: “Genau das, wonach ich gesucht habe” (???). Anscheinend ist der Autor verwirrt (missversteht den Unterschied zwischen NPC und NPV, wie ich oben sagte).

    – AnT steht zu Russland

    8. April 2010 um 13:57 Uhr

  • @Windows-Programmierer: Sind Sie sicher, dass K & R das Konzept des typspezifischen Nullzeigerwerts hatte, anstatt einfach ganzzahlig zu konvertieren? 0 auf Zeiger auf Adresse 0x0?

    – AnT steht zu Russland

    1. Juli 2013 um 4:13 Uhr


Benutzeravatar von paxdiablo
paxdiablo

Es gab eine Zeit vor langer Zeit, als es so getippt wurde ((void*)0) oder auf eine andere maschinenspezifische Weise, bei der diese Maschine das Nur-Null-Bitmuster nicht verwendet hat.

Einige Plattformen (bestimmte CDC- oder Honeywell-Maschinen) hatten ein anderes Bitmuster für NULL (d. h. nicht alle Nullen), obwohl ISO/ANSI dies vor der Ratifizierung von C90 festlegte, indem es dies spezifizierte 0 war der richtige NULL-Zeiger im Quellcode, trotzdem des zugrunde liegenden Bitmusters. Aus C11 6.3.2.3 Pointers /4 (obwohl diese Formulierung, wie erwähnt, bis zu C90 zurückreicht):

Ein ganzzahliger konstanter Ausdruck mit dem Wert 0oder ein solcher Ausdruck, der in einen Typ umgewandelt wird void *wird als Nullzeigerkonstante bezeichnet.

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

In C-Compilern kann es erweitert werden zu ‘((void *)0)“ (muss aber nicht). Dies funktioniert nicht für C++-Compiler.

Siehe auch die C-FAQ, die ein ganzes Kapitel enthält Nullzeiger.

In der GNU-Datei 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

Beachten Sie die bedingte Kompilierung auf __cplusplus. C++ kann ((void*) 0) wegen seiner strengeren Regeln für das Casting von Zeigern nicht verwenden; der Standard erfordert, dass NULL 0 ist. C erlaubt andere Definitionen von NULL.

C-Compiler verwenden normalerweise ((void *)0). Der Grund vergeht NULL zu Funktionen mit variablen Argumenten (oder jetzt seltene, aber immer noch legale Funktionen ohne Prototyp). Wenn Zeiger größer als int sind, 0 wird nur befördert int und wird daher nicht korrekt als Zeiger gelesen.

C++-Compiler können diese Definition nicht verwenden, da C++ keine implizite Umwandlung von zulässt void * (Gießen 0 zu jedem Zeiger ist ein Sonderfall). C++11 hat jedoch ein neues Schlüsselwort eingeführt nullptr das ist eine Nullzeigerkonstante von special nullptr_t Typ implizit in einen beliebigen Zeigertyp konvertierbar, aber nicht Zahl. Dies löst sowohl das variadische Argumentproblem als auch die implizite Umwandlung und zusätzlich schwerwiegendere Probleme mit der Überladungsauswahl (0 aus offensichtlichen Gründen wählt int Überladung über Zeiger eins). Es ist legal, diese für ältere Compiler selbst zu definieren, und einige C++-Compiler haben dies in der Vergangenheit versucht.

Benutzeravatar von John Saunders
John Saunders

Im modernen C, void *pointer = 0; soll “Zeiger” so initialisieren, dass er auf nichts zeigt. Es ist plattformspezifisch, ob dies erreicht wird, indem die Bits von “Zeiger” auf Null gesetzt werden.

In der Vergangenheit war diese formale Bedeutung von “0” in einem Zeigerkontext nicht etabliert. Es war notwendig, den Zeiger auf den tatsächlichen Wert zu setzen, den die Plattform als “zeigt nirgendwohin” behandelt. Beispielsweise könnte eine Plattform eine feste Adresse auswählen, der niemals eine Seite zugeordnet wird. In diesem Fall könnte in einem alten Compiler die Plattform definiert worden sein NULL wie:

#define NULL ((void*)0xFFFFF000)

Natürlich gibt es heute keinen Grund, es nicht so zu definieren ((void*)0).

NULL Makro in C erweitert auf implementierungsdefinierte Nullzeigerkonstante. Es kann alles sein (da es implementierungsdefiniert ist), aber im Zeigerkontext ist der Effekt immer derselbe, als ob er auf eine Konstante erweitert würde 0.

In der Geschichte von Standard-C gab es noch nie eine Zeit, in der NULL erweitert um etwas ausdrücklich nicht 0es sei denn, Sie denken darüber nach (void *) 0 als „nicht 0“. Aber (void *) 0 zum NULL ist bis heute weit verbreitet.

  • Es hat noch nie eine Zeit gegeben ISO C-Geschichte … frühe Compiler hatten unterschiedliche Bitmuster, lange bevor die 0 unabhängig von den zugrunde liegenden Bits als NULL kodiert wurde. Obwohl ich mich angesichts meines fortgeschrittenen Alters nicht erinnern kann, welche es waren 🙂

    – paxdiablo

    8. April 2010 um 2:26 Uhr

  • Kapitel und Vers bitte? Der ISO-C-Standard besagt ausdrücklich, dass NULL auf alles erweitert werden kann, worauf die Implementierung es erweitern möchte. 4.1.5. Common Definitions <stddef.h> [...] The macros are NULL which expands to an implementation-defined null pointer constant; and [...] . Dies sollte nicht mit anderem Text verwechselt werden, der besagt, dass der Ausdruck 0, der in den Zeigertyp konvertiert wird, immer eine gültige Möglichkeit ist, eine Nullzeigerkonstante zu erhalten. Was nichts mit dem zu tun hat, worauf sich NULL ausdehnt.

    – Janks

    8. April 2010 um 2:46 Uhr

  • @janks, ich denke, @paxdiablo sagt das in ISO C, 0 in Zeigerkontexten ist die Nullzeigerkonstante, aber in Pre-ISO (Pre-ANSI) C war dies nicht unbedingt wahr. Vermutlich in diesen Varianten würde man schreiben NULLoder welche magische Zahl auch immer der Nullzeiger war.

    – Alok Singhal

    8. April 2010 um 3:18 Uhr

  • @Alok, ja, genau das sagte sein erster Absatz. Aber dann widersprach er dem, indem er sagte, dass “es in der C-Geschichte noch nie eine Zeit gegeben hat, in der NULL auf etwas speziell nicht 0 erweitert wurde”, was Müll ist. Der Standard verlangt es nicht, und er müsste ausnahmslos jede Implementierung von C verwendet haben, um das Negative zu beweisen. Früher glaubten wir, es gäbe keine schwarzen Schwäne, weil wir nur weiße gesehen hatten.

    – Janks

    8. April 2010 um 3:36 Uhr

  • Was ich sagen wollte ist, dass seit dem Moment NULL erschien als bestimmter Teil der Sprache, 0 war eine gültige Art zu definieren NULL. Dh es gab nie eine Zeit NULL war erforderlich als etwas ungleich Null definiert werden. Es könnte auf etwas Plattformspezifisches (beliebiges) definiert werden, aber 0 musste immer genauso gut funktionieren. (Nochmals: seit dem Moment NULL wurde vorgestellt. CRM C zum Beispiel macht keine Erwähnung NULL.)

    – AnT steht zu Russland

    8. April 2010 um 14:00 Uhr


1396780cookie-checkWann war das NULL-Makro nicht 0?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy