Frage

ich würde gerne wissen Architekturen, die gegen die Annahmen verstoßen Ich habe unten aufgeführt. Außerdem möchte ich wissen, ob eine der Annahmen für alle Architekturen falsch ist (dh, wenn einer von ihnen einfach völlig falsch ist).

  1. sizeof (int *) == sizeof (char *) == sizeof (void *) == sizeof (func_ptr *)

  2. Die In-Memory-Darstellung aller Zeiger für eine bestimmte Architektur ist unabhängig vom Datentyp, auf das gezeigt wird.

  3. Die In-Memory-Darstellung eines Zeigers ist dieselbe wie eine Ganzzahl der gleichen Bitlänge wie die Architektur.

  4. Die Multiplikation und Aufteilung der Zeigerdatentypen werden vom Compiler nur verboten. Hinweis: Ja, ich weiß, dass dies unsinnig ist. Was ich meine ist - gibt es Hardware -Unterstützung, um diese falsche Verwendung zu verbieten?

  5. Alle Zeigerwerte können an eine einzelne Ganzzahl gegossen werden. Mit anderen Worten, welche Architekturen verwenden immer noch Segmente und Offsets?

  6. Das Inkrementieren eines Zeigers entspricht dem Zugabe sizeof(the pointed data type) an die vom Zeiger gespeicherte Speicheradresse. Wenn p ist ein int32* dann p+1 ist gleich der Speicheradresse 4 Bytes danach p.

Ich bin am meisten daran gewöhnt, Zeiger in einem zusammenhängenden, virtuellen Speicherraum zu verwenden. Für diese Verwendung kann ich im Allgemeinen durch denkt, dass sie sie als Adressen in einer Zahlenlinie betrachten. Siehe Stapelüberlauffrage Zeigervergleich.

War es hilfreich?

Lösung

Ich kann Ihnen keine konkreten Beispiele für all diese geben, aber ich werde mein Bestes geben.

sizeof(int *) == sizeof(char *) == sizeof(void *) == sizeof(func_ptr *)

Ich kenne keine Systeme, in denen ich kennt Dies ist falsch zu sein, aber überlegen Sie:

Mobile Geräte haben häufig einen gewissen schreibgeschützten Speicher, in dem Programmcode und dergleichen gespeichert werden. Lesewerte (CONT-Variablen) können möglicherweise im schreibgeschützten Speicher gespeichert werden. Und da der ROM -Adressraum möglicherweise kleiner als der normale RAM -Adressraum ist, kann auch die Zeigergröße unterschiedlich sein. Ebenso können Zeiger auf Funktionen eine andere Größe haben, da sie möglicherweise auf diesen schreibgeschützten Speicher hinweisen, in den das Programm geladen wird und ansonsten nicht geändert werden kann (sodass Ihre Daten nicht darin gespeichert werden können).

Ich kenne also keine Plattformen, auf denen ich beobachtet habe, dass die oben genannte nicht gilt, aber ich kann mir Systeme vorstellen, in denen es möglicherweise der Fall ist.

Die In-Memory-Darstellung aller Zeiger für eine bestimmte Architektur ist unabhängig vom Datentyp, auf das gezeigt wird.

Denken Sie an Mitgliederzeiger gegen reguläre Zeiger. Sie haben nicht die gleiche Darstellung (oder Größe). Ein Mitgliedszeiger besteht aus a this Zeiger und ein Offset.

Und wie oben ist es denkbar, dass einige CPUs konstante Daten in einen separaten Speicherbereich laden würden, der ein separates Zeigerformat verwendete.

Die In-Memory-Darstellung eines Zeigers ist dieselbe wie eine Ganzzahl der gleichen Bitlänge wie die Architektur.

Hängt davon ab, wie diese Bitlänge definiert wird. :) Ein int Auf vielen 64-Bit-Plattformen sind noch 32 Bit. Aber ein Zeiger ist 64 Bit. Wie bereits gesagt, wird CPUs mit einem segmentierten Speichermodell Zeiger haben, die aus einem Zahlenpaar bestehen. Ebenso bestehen Mitgliedszeiger aus einem Zahlenpaar.

Die Multiplikation und Aufteilung der Zeigerdatentypen werden vom Compiler nur verboten.

Letztendlich nur Zeiger -Datentypen existieren im Compiler. Was die CPU arbeitet, sind keine Zeiger, sondern Ganzzahlen und Speicheradressen. Es gibt also nirgendwo sonst, wo diese Operationen auf Zeigertypen könnte Verboten sein. Sie können auch die CPU bitten, die Verkettung von C ++ - String -Objekten zu verbieten. Dies kann dies nicht tun, da der C ++ - String -Typ nur in der C ++ - Sprache vorhanden ist, nicht im generierten Maschinencode.

Um jedoch zu beantworten, was Sie bedeuten, Schauen Sie sich den Motorola 68000 CPUs an. Ich glaube, sie haben separate Register für Ganzzahlen und Speicheradressen. Dies bedeutet, dass sie solche unsinnigen Operationen leicht verbieten können.

Alle Zeigerwerte können an eine einzelne Ganzzahl gegossen werden.

Du bist dort sicher. Die C- und C ++ - Standards garantieren, dass dies immer möglich ist, unabhängig vom Speicherplatzlayout, der CPU -Architektur und irgendetwas anderem. Insbesondere garantieren sie eine Implementierungsdefinierte Zuordnung. Mit anderen Worten, Sie können immer einen Zeiger in eine Ganzzahl konvertieren und diese Ganzzahl zurück konvertieren, um den ursprünglichen Zeiger zu erhalten. Aber die C/C ++ - Sprachen sagen nichts darüber aus, was der Zwischenwert für den Zwischenstudium sein sollte. Das liegt bei dem einzelnen Compiler und der Hardware, die es abzielt.

Das Inkrementieren eines Zeigers entspricht der Hinzufügung von Größe (dem spitzen Datentyp) in die vom Zeiger gespeicherte Speicheradresse.

Auch dies ist garantiert. Wenn Sie dies konzeptionell berücksichtigen, verweist ein Zeiger nicht auf eine Adresse, er zeigt auf eine Objekt, Dann macht das durchaus sinnvoll. Wenn Sie einen zum Zeiger hinzufügen, wird es offensichtlich auf die hinweisen nächste Objekt. Wenn ein Objekt 20 Bytes lang ist, verschiebt das Inkrementieren des Zeigers ihn 20 Bytes, damit er zum nächsten bewegt wird Objekt.

Wenn ein Zeiger lediglich eine Speicheradresse in einem linearen Adressraum wäre, wenn er im Grunde genommen eine Ganzzahl wäre, würde das Inkrementieren der Adresse 1 hinzugefügt - das heißt, er würde zum nächsten übergehen Byte.

Beachten Sie, wie ich in einem Kommentar zu Ihrer Frage erwähnt habe, dass C ++ nur eine Sprache ist. Es ist egal, welche Architektur es zusammengestellt wird. Viele dieser Einschränkungen mögen bei modernen CPUs unklar erscheinen. Aber was ist, wenn Sie auf die CPUs von Gosteryear abzielen? Was ist, wenn Sie auf die CPUs des nächsten Jahrzehnts abzielen? Sie wissen nicht einmal, wie sie funktionieren, also können Sie nicht viel über sie ausgehen. Was ist, wenn Sie auf eine virtuelle Maschine abzielen? Es gibt bereits Compiler, die Bytecode für Flash generieren und bereit sind, von einer Website zu laufen. Was ist, wenn Sie Ihr C ++ in Python -Quellcode kompilieren möchten?

Bleiben Sie in den in den Standard garantierten Regeln, in denen Ihr Code funktioniert alle diese Fälle.

Andere Tipps

Ich habe keine spezifischen Beispiele für reale Welt im Sinn, aber die "Autorität" ist der C -Standard. Wenn vom Standard nicht etwas erforderlich ist, können Sie eine konforme Implementierung erstellen, die absichtlich andere Annahmen entspricht. Einige dieser Annahmen sind die meiste Zeit der Fall, nur weil es zweckmäßig ist, einen Zeiger als Ganzzahl zu implementieren, die eine Speicheradresse darstellt, die direkt vom Prozessor abgerufen werden kann, dies ist jedoch nur ein Konsequenz von "Bequemlichkeit" und kann nicht als als als erachtet werden eine universelle Wahrheit.

  1. Nicht vom Standard erforderlich (Siehe diese Frage). Zum Beispiel, sizeof(int*) kann ungleich sein size(double*). void* kann garantiert jeden Zeigerwert speichern.
  2. Nicht vom Standard erforderlich. Die Größe ist per Definition ein Teil der Darstellung. Wenn die Größe unterschiedlich sein kann, kann auch die Darstellung unterschiedlich sein.
  3. Nicht unbedingt. Tatsächlich ist "die Bitlänge einer Architektur" eine vage Aussage. Was ist wirklich ein 64-Bit-Prozessor? Ist es der Adressbus? Größe der Register? Datenbus? Was?
  4. Es macht keinen Sinn, einen Zeiger zu "multiplizieren" oder "teilt". Es ist vom Compiler verboten, aber Sie können natürlich die zugrunde liegende Darstellung (was für mich nicht wirklich sinnvoll ist) multiplizieren oder dividieren, was zu undefiniertem Verhalten führt.
  5. Vielleicht verstehe ich Ihren Standpunkt aber nicht alles In einem digitalen Computer befindet sich nur eine Binärzahl.
  6. Ja; So'ne Art. Es wird garantiert auf einen Ort hinweisen, der a ist sizeof(pointer_type) weiter. Es entspricht nicht unbedingt der arithmetischen Zugabe einer Zahl (dh weiter ist hier ein logisches Konzept. Die tatsächliche Darstellung ist architekturspezifisch)

Für 6.: Ein Zeiger ist nicht unbedingt eine Speicheradresse. Siehe zum Beispiel "Die große Zeigerverschwörung"Durch Stack -Überlaufbenutzer JALF:

Ja, ich habe das Wort "Adresse" im obigen Kommentar verwendet. Es ist wichtig zu erkennen, was ich damit meine. Ich meine nicht „die Speicheradresse, bei der die Daten physikalisch gespeichert sind“, sondern lediglich ein abstrakter „Was auch immer wir brauchen, um den Wert zu lokalisieren. Die Adresse von Ich könnte alles sein, aber wenn wir sie haben, können wir immer immer finden und ändern. "

Und:

Ein Zeiger ist keine Speicheradresse! Ich habe das oben erwähnt, aber sagen wir es noch einmal. Zeiger werden normalerweise vom Compiler einfach als Speicheradressen implementiert, ja, aber sie müssen es nicht sein. "

Einige weitere Informationen zu Zeigern aus dem C99 -Standard:

  • 6.2.5 §27 garantiert das void* und char* Haben Sie identische Darstellungen, dh sie können ohne Konvertierung austauschbar verwendet werden. Die gleiche Adresse wird mit demselben Bitmuster bezeichnet (was für andere Zeigertypen nicht wahr sein muss)
  • 6.3.2.3 §1 gibt an, dass jeder Zeiger auf einen unvollständigen oder Objekttyp auf (und von) gegossen werden kann void* und wieder zurück und immer noch gültig sein; Dies enthält keine Funktionszeiger!
  • 6.3.2.3 §6 gibt an, dass void* Kann zu (und von) Ganzzahlen gegossen werden und 7.18.1.4 §1 liefert profile Typen intptr_t und uintptr_t; Das Problem: Diese Typen sind optional - der Standard erwähnt ausdrücklich, dass es keinen ganzzahligen Typ geben muss, der groß genug ist, um den Wert des Zeigers tatsächlich zu halten!

sizeof(char*) != sizeof(void(*)(void) ? - Nicht auf x86 im 36 -Bit -Adressierungsmodus (unterstützt in so ziemlich jeder Intel -CPU seit Pentium 1)

"Die In-Memory-Darstellung eines Zeigers ist die gleiche wie eine Ganzzahl der gleichen Bitlänge"-es gibt keine In-Memory-Darstellung in einer modernen Architektur. Tagged Memory hat sich noch nie aufgenommen und war bereits veraltet, bevor C standardisiert wurde. Das Gedächtnis hält in der Tat nicht einmal Ganzzahlen, nur Teile und wohlwörter (keine Bytes; die meisten physischen Erinnerungen erlauben es Ihnen nicht, nur 8 Bit zu lesen.)

"Multiplikation von Zeigern ist unmöglich" - 68000 Familie; Adressregister (diejenigen, die Zeiger halten), stützten das IIRC nicht.

"Alle Zeiger können auf Ganzzahlen gegossen werden" - nicht auf Bildern.

"Inkrementierung eines T* ist gleichbedeutend mit dem Hinzufügen von Größe (t) zur Speicheradresse" - true per Definition. Auch äquivalent zu &pointer[1].

Ich weiß nichts über die anderen, aber für DOS ist die Annahme in #3 falsch. DOS ist 16 Bit und verwendet verschiedene Tricks, um viel mehr als 16 Bits Gedächtnis abzubilden.

Die In-Memory-Darstellung eines Zeigers ist dieselbe wie eine Ganzzahl der gleichen Bitlänge wie die Architektur.

Ich denke, diese Annahme ist falsch, da beispielsweise bei 80186 ein 32-Bit-Zeiger in zwei Registern gehalten wird (ein Offset-Register ein Segmentregister), und das halbwort ging, in dem Register während des Zugangs von Bedeutung ist.

Die Multiplikation und Aufteilung der Zeigerdatentypen werden vom Compiler nur verboten.

Sie können nicht multiplizieren oder Typen teilen. ;P

Ich bin mir nicht sicher, warum Sie einen Zeiger multiplizieren oder teilen möchten.

Alle Zeigerwerte können an eine einzelne Ganzzahl gegossen werden. Mit anderen Worten, welche Architekturen verwenden immer noch Segmente und Offsets?

Mit dem C99 -Standard können Zeiger gespeichert werden intptr_t, was ein ganzzahliger Typ ist. Also ja.

Das Inkrementieren eines Zeigers entspricht der Hinzufügung von Größe (dem spitzen Datentyp) in die vom Zeiger gespeicherte Speicheradresse. Wenn P ein INT32* ist, ist P+1 nach p gleich der Speicheradresse 4 -Bytes.

x + y wo x ist ein T * und y Ist eine Ganzzahl eindeutig zu (T *)((intptr_t)x + y * sizeof(T)) Soweit ich weiss. Ausrichtung kann ein Problem sein, aber die Polsterung kann in der vorgelegt werden sizeof. Ich bin mir nicht wirklich sicher.

Im Allgemeinen lautet die Antwort auf alle Fragen ""Jawohl", und es liegt daran, dass nur jene Maschinen, die beliebte Sprachen implementieren Produkte, mit der möglichen Ausnahme von Artikeln 3 und 4, für die einige Wiederherstellungen universell wahr sind.

Es ist sicherlich möglich, segmentierte MMU-Designs zu erstellen, die grob mit den in den vergangenen Jahren akademisch beliebten Fähigkeiten basieren. In der Regel hat kein solches System bei solchen ermöglichten Funktionen in der Regel häufig verwendet. Ein solches System könnte mit den Behauptungen in Konflikt geraten sein, da es wahrscheinlich große Zeiger gehabt hätte.

Zusätzlich zu segmentierten/Fähigkeiten MMUs, die häufig große Zeiger haben, haben extremere Designs versucht, Datentypen in Zeigern zu codieren. Nur wenige davon wurden jemals gebaut. (Diese Frage zeigt alle Alternativen zu den grundlegenden wortorientierten, eine Zeiger-Is-a-Wort-Architekturen.)

Speziell:

  1. Die In-Memory-Darstellung aller Zeiger für eine bestimmte Architektur ist unabhängig vom Datentyp, auf das gezeigt wird. Richtig, bis auf extrem verrückte Vergangenheit, die versuchten, Schutz nicht in stark typischen Sprachen, sondern in Hardware zu implementieren.
  2. Die In-Memory-Darstellung eines Zeigers ist dieselbe wie eine Ganzzahl der gleichen Bitlänge wie die Architektur. Vielleicht ist sicherlich eine Art integraler Typ gleich, siehe LP64 gegen LLP64.
  3. Die Multiplikation und Aufteilung der Zeigerdatentypen werden vom Compiler nur verboten. Recht.
  4. Alle Zeigerwerte können an eine einzelne Ganzzahl gegossen werden. Mit anderen Worten, welche Architekturen verwenden immer noch Segmente und Offsets? Nichts benutzt heute Segmente und Offsets, aber ein c int ist oft nicht groß genug, Sie brauchen möglicherweise eine long oder long long einen Zeiger halten.
  5. Das Inkrementieren eines Zeigers entspricht der Hinzufügung von Größe (dem spitzen Datentyp) in die vom Zeiger gespeicherte Speicheradresse. Wenn P ein INT32* ist, ist P+1 nach p gleich der Speicheradresse 4 -Bytes. Ja.

Es ist interessant festzustellen, dass jede Intel -Architektur -CPU, dh jeder einzelnen Peecee, eine aufwändige Segmentierungseinheit mit epischem, legendärem, Komplexität enthält. Es ist jedoch effektiv deaktiviert. Immer wenn ein PC -Betriebssystem aufbaut, setzt es die Segmentbasen auf 0 und die Segmentlängen auf ~ 0, null, die die Segmente auszuräumen und ein Flachspeichermodell anzugeben.

In den 1950er, 1960er und 1970er Jahren gab es viele "Wort behandelt" -Architekturen. Aber ich kann mich nicht an Mainstream -Beispiele erinnern, die einen C -Compiler hatten. Ich erinnere mich an die ICL / Drei Flüsse PERQ -Maschinen In den 1980er Jahren wurde das Wort angesprochen und hatte einen beschreibbaren Steuerspeicher (Mikrocode). Eine seiner Instanziationen hatte einen C -Compiler und einen Geschmack von Unix genannt PNX, Aber der C -Compiler benötigte einen speziellen Mikrocode.

Das grundlegende Problem ist, dass char* -Typen auf mit wörgerichteten Maschinen umständlich sind, sie jedoch implementieren. Sie oft mit sizeof(int *) != sizeof(char *) ...

Interessanterweise wurde vor C eine Sprache genannt BCPL in dem der grundlegende Zeigertyp eine Wortadresse war; Das heißt, das Inkrementieren eines Zeigers gab Ihnen die Adresse des nächsten Wortes und ptr!1 gab dir das Wort bei ptr + 1. Es gab einen anderen Operator für die Behandlung eines Byte: ptr%42 Wenn ich mich erinnere.

Bearbeiten: Beantworten Sie keine Fragen, wenn Ihr Blutzucker niedrig ist. Ihr Gehirn (sicherlich meins) funktioniert nicht, wie Sie es erwarten. :-(

Minor Nitpick:

p ist ein int32* dann p+1

ist falsch, es muss unsigned int32 sein, sonst wickelt es bei 2 GB.

Interessante Kuriosität - Ich habe dies vom Autor des C -Compilers für den Transvers -Chip bekommen - er erzählte mir, dass Null für diesen Compiler als -2 GB definiert wurde. Wieso den? Weil der Transputer einen signierten Adressbereich hatte: -2 GB bis +2 GB. Kannst du das glauben? Erstaunlich, nicht wahr?

Ich habe seitdem verschiedene Leute getroffen, die mir gesagt haben, dass die Definition von Null so gebrochen ist. Ich stimme zu, aber wenn Sie nicht am Ende Null -Zeiger in der Mitte Ihres Adressbereichs sind.

Ich denke, die meisten von uns können froh sein, dass wir nicht an den Getränken arbeiten!

Ich würde gerne Architekturen wissen, die gegen die Annahmen verstoßen, die ich unten aufgeführt habe.

Ich sehe, dass Stephen C PERQ -Maschinen und MSAgerter 68000 und Bilder erwähnte.

Ich bin enttäuscht, dass niemand die Frage tatsächlich beantwortet hat, indem er eine der seltsamen und wunderbaren Architekturen benannte, die Standards-konforme C-Compiler haben, die nicht bestimmte ungerechtfertigte Annahmen passen.

sizeof (int *) == sizeof (char *) == sizeof (void *) == sizeof (func_ptr *)?

Nicht unbedingt. Einige Beispiele:

Die meisten Compiler für Harvard-Architecture 8-Bit-Prozessoren-PIC und 8051 und M8C-Machen Sie sizeof (int *) == sizeof (char *), unterscheiden sich jedoch von der Größe (func_ptr *).

Einige der sehr kleinen Chips in diesen Familien haben 256 Bytes RAM (oder weniger), aber mehrere Kilobyte Progmem (Blitz oder ROM), so Single 8-Bit-Byte), aber sizeof (func_ptr *) gleich 2 (zwei 8-Bit-Bytes).

Compiler für viele der größeren Chips in Familien mit ein paar Kilobyten RAM und 128 kilobyten Progmem machen sizeof (int *) == sizeof (char *) gleich 2 (zwei 8-Bit-Bytes), aber sizeof (signyof ( func_ptr *) gleich 3 (drei 8-Bit-Bytes).

Einige Harvard-Architecture-Chips können genau 2^16 ("64KByte") von Progmem (Flash oder ROM) und weitere 2^16 ("64KByte") von RAM + Memory-Made-Map-I/O speichern. Die Compiler für einen solchen Chip machen die Größe (func_ptr *) immer 2 (zwei Bytes); aber oft haben die anderen Arten von Zeigern die Größe von (int *) == sizeof (char *) == sizeof (void *) in aa "long ptr". 3-Byte generischer Zeiger Das hat das zusätzliche magische Bit, das angibt, ob dieser Zeiger in RAM oder Progmem richtet. (Das ist die Art von Zeiger, die Sie an eine "print_text_to_the_lcd ()" übergeben müssen, wenn Sie diese Funktion von vielen verschiedenen Unterprogrammen aufrufen, manchmal mit der Adresse einer variablen Zeichenfolge im Puffer, die sich überall im RAM befinden könnte, und manchmal mit einem mit einer von vielen ständigen Saiten, die überall in Progmem sein könnten). Solche Compiler haben oft spezielle Schlüsselwörter ("kurz" oder "in der Nähe", "lang" oder "weit"), damit Programmierer ausdrücklich drei verschiedene Arten von Zeichenzeigern in demselben Programm angeben - konstante Zeichenfolgen, die nur 2 Bytes benötigen, um anzuzeigen, wo In Progmem befinden sie sich nicht konstante Saiten, die nur 2 Bytes benötigen, um anzuzeigen, wo sie sich im RAM befinden, und welche Art von 3-Byte-Zeigern "print_text_to_the_lcd ()" akzeptiert.

Die meisten Computer, die in den 1950er und 1960er Jahren gebaut wurden, verwenden a 36-Bit-Wortlänge oder an 18-Bit-Wortlänge, mit einem 18-Bit (oder weniger) Adressbus. Ich höre, dass C -Compiler für solche Computer oft verwenden 9-Bit-Bytes, mit sizeof (int *) == sizeof (func_ptr *) = 2, die 18 Bit ergibt, da alle Ganzzahlen und Funktionen wort ausgerichtet sein müssen; aber sizeof (char *) == sizeof (void *) == 4, um die Vorteile zu nutzen Spezielle PDP-10-Anweisungen Das speichert solche Zeiger in einem vollen 36-Bit-Wort. Dieses vollständige 36-Bit-Wort enthält eine 18-Bit-Wortadresse und ein paar weitere Bits in den anderen 18-Bit, die (unter anderem) die Bitposition des Zeichens in diesem Wort angeben.

Die In-Memory-Darstellung aller Zeiger für eine bestimmte Architektur ist unabhängig vom Datentyp, auf das hingewiesen wird?

Nicht unbedingt. Einige Beispiele:

Auf einem der oben erwähnten Architekturen gibt es in verschiedenen Größen. Wie konnten sie möglicherweise "die gleiche" Darstellung haben?

Einige Compiler für einige Systeme verwenden "Deskriptoren" Charakterzeiger und andere Arten von Zeigern implementieren. Ein solcher Deskriptor ist anders Für einen Zeiger, der auf den ersten "Char" in einem "zeigt"char big_array[4000]"als für einen Zeiger, der auf den ersten" Char "in einem" zeigt "char small_array[10]", die wohl unterschiedliche Datentypen sind, selbst wenn das kleine Array an genau demselben Ort im Speicher beginnt, das zuvor vom großen Array besetzt war. Deskriptoren ermöglichen es solchen Maschinen, die Pufferüberläufe zu fangen und zu fangen, die solche Probleme auf anderen Maschinen verursachen.

Das "Fettarme Zeiger" Im Safelit und ähnlichen "weichen Prozessoren" haben analoge "zusätzliche Informationen" über die Größe des Puffers, in den der Zeiger zeigt. Fettarme Zeiger haben den gleichen Vorteil, Pufferüberläufe zu fangen und zu fangen.

Die In-Memory-Darstellung eines Zeigers ist dasselbe wie eine Ganzzahl der gleichen Bitlänge wie die Architektur?

Nicht unbedingt. Einige Beispiele:

Im "Tagged Architektur" Maschinen, jedes Gedächtniswort enthält einige Teile, die angeben, ob dieses Wort eine Ganzzahl oder ein Zeiger oder etwas anderes ist. Mit solchen Maschinen würden Sie sich die Tag -Bits ansehen, ob dieses Wort eine Ganzzahl oder ein Zeiger war.

Ich höre, dass Nova Minicomputer eine haben "Indirektion Bit" In jedem Wort, das inspiriert wurde "Indirekter Thread -Code". Es hört sich so an, als würde die Aufbewahrung einer Ganzzahl das Bit löschen, während ein Zeiger das Stück speichert.

Die Multiplikation und Aufteilung der Zeigerdatentypen werden vom Compiler nur verboten. Hinweis: Ja, ich weiß, dass dies unsinnig ist. Was ich meine ist - gibt es Hardware -Unterstützung, um diese falsche Verwendung zu verbieten?

Ja, einige Hardware unterstützt solche Vorgänge nicht direkt.

Wie andere bereits erwähnt haben, funktionieren die "Multiplikum" -Bäume im 68000 und der 6809 nur mit (einigen) "Datenregistern"; Sie können nicht direkt auf Werte in "Adressregistern" angewendet werden. (Für einen Compiler wäre es ziemlich einfach, solche Einschränkungen zu bearbeiten - diese Werte von einem Adressregister in das entsprechende Datenregister zu ziehen und dann MUL zu verwenden).

Alle Zeigerwerte können an einen einzelnen Datentyp gegossen werden?

Ja.

Damit memcpy () richtig funktioniert, der C -Standard schreibt vor, dass jeder Zeigerwert jeder Art auf einen Hohlraumzeiger geworfen werden kann ("void *").

Der Compiler ist erforderlich, um diese Arbeit zu machen, auch für Architekturen, die noch Segmente und Offsets verwenden.

Alle Zeigerwerte können einer einzigen Ganzzahl gegossen werden? Mit anderen Worten, welche Architekturen verwenden immer noch Segmente und Offsets?

Ich bin mir nicht sicher.

Ich vermute, dass alle Zeigerwerte in die integrierten Datentypen "size_t" und "ptrdiff_t" in "size_t" und "ptrdiff_t" gegossen werden können.<stddef.h>".

Das Inkrementieren eines Zeigers entspricht der Hinzufügung von Größe (dem spitzen Datentyp) in die vom Zeiger gespeicherte Speicheradresse. Wenn P ein INT32* ist, ist P+1 nach p gleich der Speicheradresse 4 -Bytes.

Es ist unklar, was Sie hier fragen.

F: Wenn ich ein Array einer Art Struktur oder primitiver Datentyp habe (z. B. a "#include <stdint.h> ... int32_t example_array[1000]; ..."), und ich erhöht einen Zeiger, der in dieses Array verweist (zum Beispiel" int32_t p = & example_array [99]; ... p ++; Array, welche Größe (der spitze Datentyp) Bytes weiter entlang im Speicher?

A: Ja, der Compiler muss den Zeiger nach dem Inkrementieren nach einem einmaligen Zeugnis auf die nächste unabhängige int32_t im Array, sizeof (der spitze Datentyp), weiter im Speicher zeigen, um Standards konform zu sein.

F: Also, wenn p ein int32* ist, dann ist p+1 gleich der Speicheradresse 4 Bytes nach p?

A: Wenn die Größe (int32_t) tatsächlich gleich 4 ist, ja. Andernfalls, wie für bestimmte wortadressible Maschinen, einschließlich einiger moderner DSPs, wobei die Größe von (int32_t) 2 oder sogar 1 entsprechen kann, ist p+1 nach p gleich der Speicheradresse 2 oder sogar 1 "C Bytes".

F: Also, wenn ich den Zeiger nehme und ihn in ein "int" werde ...

A: Eine Art von "Alle Welt ist eine Vax Häresie".

F: ... und dann diese "int" wieder in einen Zeiger werfen ...

A: Eine andere Art von "Alle Welt ist eine Vax Häresie".

F: Wenn ich also den Zeiger P nehme, der ein Zeiger auf einen INT32_T ist, und ihn in einen integralen Typ werfen, der groß genug ist, um den Zeiger zu enthalten, und dann hinzufügen sizeof( int32_t ) zu diesem integralen Typ und dann später diesen integralen Typ in einen Zeiger zurückzugeben - wenn ich das alles tue, ist der resultierende Zeiger gleich p+1?

Nicht unbedingt.

Viele DSPs und einige andere moderne Chips haben eine wortorientierte Adressierung und nicht die von 8-Bit-Chips verwendete Byte-orientierte Verarbeitung.

Einige der C -Compiler für solche Chips einteilen 2 Zeichen in jedes Wort, aber es braucht zwei solche Wörter, um ein INT32_T zu halten - also berichten sie darüber sizeof( int32_t ) ist 4. (Ich habe Gerüchte gehört, dass es einen C -Compiler für die gibt 24-Bit Motorola 56000 das tut dies).

Der Compiler muss Dinge so anordnen, dass das Durchführen von "p ++" mit einem Zeiger auf einen INT32_T den Zeiger auf den nächsten Int32_t -Wert erhöht. Es gibt verschiedene Möglichkeiten für den Compiler, dies zu tun.

Ein standardkonformer Weg besteht darin, jeden Zeiger auf ein INT32_T als "native Wortadresse" zu speichern. Da es 2 Wörter benötigt, um einen einzelnen Int32_t -Wert zu halten, kompiliert der C -Compiler "int32_t * p; ... p++"In eine Montagesprache, die diesen Zeigerwert für 2. erhöht, dagegen, wenn dieser tut"int32_t * p; ... int x = (int)p; x += sizeof( int32_t ); p = (int32_t *)x;"Dieser C -Compiler für den 56000 wird ihn wahrscheinlich in die Montagesprache kompilieren, die den Zeigerwert um 4 erhöht.

Ich bin am meisten daran gewöhnt, Zeiger in einem zusammenhängenden, virtuellen Speicherraum zu verwenden.

Mehrere PIC und 8086 und andere Systeme haben einen nicht verknüpften RAM-ein paar RAM-Blöcke bei Adressen, die "die Hardware einfacher gemacht" haben. Mit dem Speicher-abgebildeten E/A oder gar nichts, was an den Lücken im Adressraum zwischen diesen Blöcken angeschlossen ist.

Es ist noch unangenehmer als es sich anhört.

In einigen Fällen - wie mit dem Bit-Binding-Hardware verwendet, um Probleme zu vermeiden, die durch verursacht wurden durch Read-Modify-Write - Das genau gleiche Bit im RAM kann mit 2 oder mehr verschiedenen Adressen gelesen oder geschrieben werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top