Warum ist NULL/0 ein illegaler Speicherort für ein Objekt?

Lesezeit: 8 Minuten

Ich verstehe den Zweck der NULL konstant in C/C++, und ich verstehe, dass es dargestellt werden muss etwas Weise intern.

Meine Frage ist: Gibt es einen grundlegenden Grund, warum die 0-Adresse ein ungültiger Speicherort für ein Objekt in C/C++ wäre? Oder sind wir in der Theorie “Verschwendung” eines Bytes Speicher aufgrund dieser Reservierung?

  • Mögliches Duplikat stackoverflow.com/questions/2759845/…

    – srikanta

    2. Juni 2010 um 18:45 Uhr

  • 0 ist nicht unbedingt ein ungültiger Speicherplatz. Verwandte Frage: stackoverflow.com/questions/2511921/…

    – Kirill W. Ljadwinski

    2. Juni 2010 um 18:57 Uhr


  • @aioobe: Wenn Sie den Zweck von verstehen NULL und dieser Nullzeiger muss dargestellt werden irgendwie intern, dann müssen Sie verstehen, dass es absolut nichts mit 0-Adresse zu tun hat. Nullzeiger kann numerisch angebunden werden irgendein Adresse, nicht unbedingt auf 0-Adresse.

    – AnT steht zu Russland

    2. Juni 2010 um 19:05 Uhr

  • In allen mir bekannten Hardware-Architekturen wird der “Beginn” des Speichers (Adresse 0 und darüber hinaus) verwendet, um Dinge wie Interrupt-Vektoren und mehr Dinge zu speichern. Daher ist es eine vernünftige Wahl, 0 als ungültige Adresse für Benutzeranwendungen zu verwenden, selbst wenn diese Adresse tatsächlich aufgrund von MMU etwas anderes sein könnte als die 0-Adresse vor der Verwendung von MMU. wichtig ist, dass NULL eine ungültige Adresse sein muss, dh eine Adresse, die dem Programm nicht “zugeordnet” werden kann; wahrscheinlich ist es numerisch immer 0, aber es ist keine Notwendigkeit

    – Shin Takezou

    2. Juni 2010 um 20:17 Uhr

  • Ich habe mit mehreren Mikroprozessoren gearbeitet, die keine solchen Beschränkungen für die Adresse 0 hatten. Der Nullzeiger kann eine vollkommen gültige Adresse sein und ist es manchmal auch. Wichtig ist, dass der Compiler dort keine Objekte erzeugt. Technisch gesehen ist es eine Compiler-Einschränkung, nicht eine architektonische.

    – Dennis Zickefoose

    2. Juni 2010 um 21:22 Uhr

Benutzer-Avatar
bobTeufel

Der Null-Zeiger muss nicht wirklich 0 sein. In der C-Spezifikation ist garantiert, dass wenn ein konstanter 0-Wert im Kontext eines Zeigers angegeben wird, dieser vom Compiler als null behandelt wird, wenn Sie dies jedoch tun

char *foo = (void *)1;
--foo;
// do something with foo

Sie greifen auf die 0-Adresse zu, nicht unbedingt auf den Nullzeiger. In den meisten Fällen ist dies tatsächlich der Fall, aber es ist nicht notwendig, sodass wir dieses Byte nicht wirklich verschwenden müssen. Obwohl es im größeren Bild, wenn es nicht 0 ist, etwas sein muss, wird also ein Byte verschwendet irgendwo

Bearbeiten: Die Verwendung von NULL wurde aufgrund der Verwirrung in den Kommentaren entfernt. Außerdem lautet die Hauptnachricht hier “Nullzeiger != 0, und hier ist etwas C/Pseudo-Code, der den Punkt zeigt, den ich versuche zu machen.” Bitte versuchen Sie nicht wirklich, dies zu kompilieren oder sich Gedanken darüber zu machen, ob die Typen korrekt sind; die Bedeutung ist klar.

  • Theoretisch gibt es das nicht haben ein Nullzeiger sein, der irgendwo beiseite gelegt wird. Aber dann müssten Programmierer haben isValid Flags, die stattdessen allen ihren Zeigern zugeordnet sind. Die Optionen sind also, irgendwo ein Byte oder überall viele Bytes zu verschwenden.

    – Dennis Zickefoose

    2. Juni 2010 um 19:19 Uhr

  • Ihr Code-Snippet ruft undefiniertes Verhalten auf, aber ich werde nicht ablehnen, da die Bedeutung klar ist.

    – jalf

    2. Juni 2010 um 19:21 Uhr

  • Abwechselnd, int z = 0; void *foo = (void *)z; erzeugt nicht unbedingt einen Nullzeiger (zumindest in C++; ich kenne mich mit den C-Standards nicht so gut aus).

    – David Thornley

    2. Juni 2010 um 19:32 Uhr

  • @Dennis Zickefoose: Anscheinend gibt es einige Architekturen, die ein hohes Bit im Zeiger als Flag verwenden, das ihn als null oder ungültig markiert. Es gibt viele Möglichkeiten, wie ISAs an die Sache herangehen.

    – Grauschimmer

    2. Juni 2010 um 19:52 Uhr

  • Nitpick: NULL (in Großbuchstaben) bedeutet das Präprozessor-Makro (das per Definition 0 (oder möglicherweise (void*) 0 für einige C-Implementierungen). Was meinen Sie der Nullzeiger. c-faq.com/null/varieties.html

    – jamesdlin

    2. Juni 2010 um 20:21 Uhr

Benutzer-Avatar
Uri

Das hat nichts mit Speicherverschwendung zu tun, sondern mit Speicherorganisation.

Wenn Sie mit dem Speicherplatz arbeiten, müssen Sie davon ausgehen, dass alles, was nicht direkt “Ihnen gehört”, vom gesamten System geteilt wird oder für Sie illegal ist. Eine Adresse “gehört Ihnen”, wenn Sie die Adresse von etwas auf dem Stapel genommen haben, das sich noch auf dem Stapel befindet, oder wenn Sie sie von einem dynamischen Speicherzuordner erhalten und noch nicht recycelt haben. Einige OS-Aufrufe liefern Ihnen auch Rechtsgebiete.

In den guten alten Zeiten des Real-Modus (z. B. DOS) war der gesamte Anfang des Adressraums der Maschine überhaupt nicht dazu gedacht, von Benutzerprogrammen geschrieben zu werden. Einige davon wurden sogar Dingen wie I/O zugeordnet. Wenn Sie beispielsweise in den Adressraum bei 0xB800 (ziemlich niedrig) schreiben, können Sie tatsächlich den Bildschirm erfassen! Nichts wurde jemals an Adresse 0 platziert, und viele Speichercontroller ließen Sie nicht darauf zugreifen, daher war es eine gute Wahl für NULL. Tatsächlich wäre der Speichercontroller auf einigen PCs verrückt geworden, wenn Sie versucht hätten, dort zu schreiben.

Heute schützt Sie das Betriebssystem mit einem virtuellen Adressraum. Trotzdem darf kein Prozess auf Adressen zugreifen, die ihm nicht zugeordnet sind. Die meisten Adressen sind nicht einmal einer tatsächlichen Speicherseite zugeordnet, sodass der Zugriff auf sie eine allgemeine Schutzverletzung oder ein Äquivalent in Ihrem Betriebssystem auslöst. Aus diesem Grund wird 0 nicht verschwendet – obwohl alle Prozesse auf Ihrem Computer “eine Adresse 0 haben”, wenn sie versuchen, darauf zuzugreifen, wird sie nirgendwo abgebildet.

  • Dies hängt nur am Rande mit dem Problem zusammen, aber war nicht die Seite 0 für die Interrupt-Tabelle reserviert? Wenn ja, dann wäre 0 eine gültige Adresse.

    – Steven Sudit

    2. Juni 2010 um 19:01 Uhr


  • @ user168715: Was einer von vielen guten Gründen ist, warum Windows 9x/Me-Kernel nicht als vernünftig bezeichnet werden können …

    – lockerer

    2. Juni 2010 um 20:46 Uhr

  • @slacker: Zu ihrer Verteidigung hat MS nicht versucht, vernünftig zu sein. Vielmehr wollte es Abwärtskompatibilität um jeden Preis, sogar Vernunft, sicherstellen.

    – Steven Sudit

    2. Juni 2010 um 21:10 Uhr

  • @slacker: Auch hier stimme ich voll und ganz zu, dass es unvernünftig ist. Aber es erfüllte ihr Ziel, nämlich weiterhin diese verrückten DOS-Spiele ausführen zu können. Gut, dass moderne CPUs virtualisierungsfähig sind.

    – Steven Sudit

    2. Juni 2010 um 23:09 Uhr

  • Der Farbtextmodus-Videospeicher wird tatsächlich auf den Realmodus abgebildet Segment 0xB800was eigentlich eine ziemliche ist hoch Adresse im Real-Modus (sie liegt über der berühmten “640k-Grenze”).

    – Café

    2. Juni 2010 um 23:55 Uhr

Benutzer-Avatar
Markus Byers

Es ist nicht erforderlich, dass ein Nullzeiger gleich der 0-Adresse ist, es ist nur so, dass die meisten Compiler es so implementieren. Es ist durchaus möglich, einen Nullzeiger zu implementieren, indem ein anderer Wert gespeichert wird, und zwar einige Systeme tun dies. Das C99-Spezifikation §6.3.2.3 (Zeiger) spezifiziert nur, dass ein ganzzahliger konstanter Ausdruck mit dem Wert 0 eine Nullzeigerkonstante ist, aber es sagt nicht, dass ein Nullzeiger, wenn er in eine ganze Zahl umgewandelt wird, den Wert 0 hat.

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

Jeder Zeigertyp kann in einen Integer-Typ konvertiert werden. Außer wie zuvor angegeben, ist das Ergebnis implementierungsdefiniert. Wenn das Ergebnis nicht im Integer-Typ dargestellt werden kann, ist das Verhalten undefiniert. Das Ergebnis muss nicht im Wertebereich eines ganzzahligen Typs liegen.

Auf einigen eingebetteten Systemen wird die Speicheradresse Null für etwas Adressierbares verwendet.

  • Gibt es Mittel, mit denen ein eingebettetes System, bei dem die Maschinendarstellung der Nullzeigerkonstante etwas anderes als 0 war, Code erlauben könnte, “reibungslos” einen Zeiger auf die physikalische Adresse Null zu erstellen? Der einzige Ansatz, der mir einfällt, wäre, Zeigeradressen als so etwas wie die echte Adresse und die Nullzeigerkonstante zu speichern, aber das scheint wirklich eklig zu sein.

    – Superkatze

    6. März 2012 um 0:57 Uhr

Die Nulladresse und der NULL-Zeiger sind nicht (notwendigerweise) dasselbe. Nur ein wörtlich Null ist ein Nullzeiger. Mit anderen Worten:

char* p = 0; // p is a null pointer

char* q = 1;
q--; // q is NOT necessarily a null pointer

Systeme können den Nullzeiger intern auf beliebige Weise darstellen, und diese Darstellung kann ein Byte Speicher “verschwenden” oder nicht, indem sie die tatsächliche 0-Adresse illegal macht. Allerdings wird ein Compiler benötigt, um a zu konvertieren wörtlich Nullzeiger in was auch immer die systeminterne Darstellung von NULL ist. Ein Zeiger, der auf andere Weise als durch die Zuweisung einer wörtlichen Null auf die Nulladresse zeigt, ist nicht notwendigerweise null.

Nun verwenden die meisten Systeme 0 für NULL, müssen es aber nicht.

Es ist nicht unbedingt ein illegaler Speicherort. Ich habe Daten gespeichert, indem ich einen Zeiger auf Null dereferenziert habe … es passiert, dass das Datum ein Interrupt-Vektor war, der an dem Vektor gespeichert wurde, der sich an der Adresse Null befindet.

Konventionell wird es normalerweise nicht vom Anwendungscode verwendet, da viele Systeme in der Vergangenheit wichtige Systeminformationen hatten, die bei Null begannen. Es könnte das Boot-ROM oder eine Vektortabelle oder sogar ein ungenutzter Adressraum sein.

Benutzer-Avatar
Clifford

Bei vielen Prozessoren ist die Adresse Null der Rücksetzvektor, in dem sich das Bootrom (BIOS auf einem PC) befindet, sodass Sie wahrscheinlich nichts an dieser physischen Adresse speichern werden. Auf einem Prozessor mit einer MMU und einem unterstützenden OS müssen die physikalischen und logischen Adressadressen nicht gleich sein, und die Adresse Null ist möglicherweise keine gültige logische Adresse im Kontext des ausführenden Prozesses.

Benutzer-Avatar
Donnie

NULL ist normalerweise die Nulladresse, aber in Ihren Anwendungen ist es die Nulladresse virtuellen Adressraum. Die virtuellen Adressen, die Sie in den meisten modernen Betriebssystemen verwenden, haben nichts mit tatsächlichen physischen Adressen zu tun, das Betriebssystem bildet den virtuellen Adressraum für Sie auf die physischen Adressen ab. Also, nein, mit der virtuellen Adresse 0 darstellen NULL verschwendet keinen Speicher.

Lesen Sie weiter virtueller Speicher für eine ausführlichere Diskussion, wenn Sie neugierig sind.

  • Dies funktioniert nur auf Betriebssystemen, die einen virtuellen Adressbereich unterstützen. Auf eingebetteten Systemen ist die Adresse 0 gültig (insbesondere wenn sich dort etwas befindet, wie RAM oder ein UART).

    – Thomas Matthäus

    2. Juni 2010 um 19:32 Uhr

1312060cookie-checkWarum ist NULL/0 ein illegaler Speicherort für ein Objekt?

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

Privacy policy