Kann man 4-Bit-, 8-Bit-, 16-Bit- oder 32-Bit-Zeiger auf einer 64-Bit-Maschine verwenden?

613
Lance Pollard

Ich habe gerade eine grobe Berechnung um die maximale Größe eines unsigned 64-Bit - Integer, die lautet:

18,446,744,073,709,551,615 q5 q4 t b m t h 

Wenn Sie sich die Hardwarespezifikationen von AWS auf ihren größten Maschinen ansehen, können Sie Folgendes erreichen 3,904GB:

3,904,000,000,000,000,000 bytes 5 q4 t b m t h 

Für mich bedeutet das, dass die Zeiger als 64-Bit-Ganzzahlen gespeichert werden . Ich denke neu über Gedanken und Zeiger nach, wollte das aber nur klarstellen.

Ich bin trotzdem etwas verwirrt. Ein Zeiger ist ein "Programmiersprachen-Konstrukt". Wenn Sie also selbst auf einem 64-Bit-Computer nur weniger als ~ 4 Milliarden Ganzzahlen (max. 32-Bit-Ganzzahl) verwenden, frage ich mich, warum Sie nicht einfach die Zeiger auf 32 Bit setzen können. Auf diese Weise sind Zeiger 32 Bit lang, bis der Speicherplatz ausgeht. Dann können Sie 64-Bit-Zeiger verwenden. Dann hätten Sie etwas mehr Platz, um mehr Objekte zu haben.

Immer noch verwirrt. Ein Zeiger enthält den Ort einer Adresse im Speicher . Es heißt, die "Adresse" sei 64 Bit. Wenn wir also 32-Bit-Zeiger haben, die auf 32-Bit-Blöcke im 64-Bit-Speicher verweisen, bin ich mir nicht sicher, wie das aussehen oder bedeuten soll. Es hat den Anschein, dass Sie Offsets machen müssten (obwohl ich das nicht gut verstehe).

Fragen Sie sich, ob Sie in C, Assembly oder JavaScript zeigen könnten, wie 32-Bit-Zeiger in einem 64-Bit-Adressraum gespeichert werden sollen. Wenn C es automatisch für Sie erledigt, wie wird es von Assembly ausgeführt?


Ich würde gerne wissen, wie ich einen großen Speicher wie oben verwenden könnte, aber 32-Bit-Zeiger speichere, bis das Maximum erreicht ist, dann 64-Bit-Zeiger verwenden und nicht sicher, wie das genau aussehen würde. Ich werde versuchen, ein Diagramm zu zeichnen, in dem erklärt wird, wie ich darüber denke.

 | The bars and . are like a ruler and mark the bit positions. - Each row under a number (1, 2, 3, ...) means a memory address. ⬚ Means no data in memory address. ⬒ Means data of type 1 in memory address. ■ Means data of type 2 in memory address. ● Means a bit of integer pointer is plugged into memory address slot. ◌ Means no bit of integer pointer is plugged into memory address slot. | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |  1. Empty 64-bit memory. ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ... ... ...  2. 64-bit memory filled with 32-bit pieces of data (type 1 ⬒, type 2 ■). ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ... ... ...  3. 64-bit memory filled with 64-bit pieces of data. ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ... ... ...  4. 64-bit memory filled with 4-bit pieces of data. ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ... ... ...  5. 64-bit memory filled with 32-bit pieces of data, with second 32-bits accessed by a 32-bit pointer. ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒  ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ...  ... ...  6. 64-bit memory filled with 64-bit pieces of data, with second 64-bits accessed by a 64-bit pointer. ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ... ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ... ... ...  7. 64-bit memory filled with 4-bit pieces of data, with second piece of data accessed by a pointer. ◌ ◌ ◌ ◌ ● ● ● ● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ... ... ...  8. 64-bit memory filled with 8-bit pieces of data, with second piece of data accessed by a pointer. ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ● ● ● ● ● ● ● ● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒  ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ... ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ... ... ... 

Ich stelle mir vor, dass die ganzen Zahlen wie Schlüssel eines Schlosses sind (was die Speicheradresse ist). Ein leeres Schlüsselloch sieht aus wie die 64er in einer Reihe in (1). Ein vollständiges Schlüsselloch für eine 64-Bit-Adresse sieht wie die 64 in Reihe (6) aus. Wenn ich dem 64-Bit-Speicheradressraum einen 32-Bit- Schlüssel gebe, würde es aussehen (5). Das 64-Bit-Schlüsselloch würde also nicht vollständig ausgefüllt, sondern nur die zweite Hälfte (in diesem Fall). Und so scheint es, als würde es nicht mit der Adresse übereinstimmen. Aber ich versuche, auf die 32-Bit-Daten genau in der zweiten Hälfte zu zeigen! Um die Adresse abzugleichen, müssen Sie die Schlüssellöcher in der gesamten 64-Bit-Zeile wie in (6) ausfüllen. Ich frage mich, ob mein Verständnis hier versaut ist, bitte lassen Sie mich wissen, wo ich gerade bin.

Falls dies nicht klar ist, zeigen die ersten Zahlen 1 bis 4 im Diagramm die im Speicher befindlichen Daten (wobei 1 ein leerer Speicher ist). Die zweiten Zahlen 5-8 zeigen, wie wir versuchen, auf die Daten mit einem Zeiger zuzugreifen (die schwarzen Kreise in einer Zeile sind der Zeiger / die Taste auf die Speicheradressensperre).

Zum Schluss habe ich noch eine letzte Ausgabe. Ich frage mich, ob Sie weiter gehen und Daten in noch kleineren Brocken speichern können. B. das Speichern von 4 Datenbits wie in (7). Dies zeigt nur, wie das Zeiger / Adress-System etwas detaillierter funktioniert. Ich weiß nicht, ob Sie einen 4-Bit-Zeiger auf einen 4-Bit-Speicherblock zeigen können. Es scheint, als würden Sie aufgrund von Ausrichtungsanforderungen am Ende mindestens 8 Bits auf einmal abrufen. Aber das ist OK. Ich möchte nur sicherstellen, dass ein N-Bit-Zeiger für den Zugriff auf N-Bit-Daten in einem 64-Bit-Speicherplatz verwendet werden kann oder nicht.

Und wenn ja, wie würde das aussehen, entweder in C oder Assembly oder JavaScript würde auch funktionieren.

Ich möchte dies wissen, um zu wissen, wie Sie Daten in einem 64-Bit-Speicher ablegen sollen, und was Sie mit den Zeigern machen dürfen, wenn "Speicheradressen sind 64-Bit". Das heißt, wenn ich memory.get(a32BitPointer)32 Bit Daten aus einem 32-Bit-ausgerichteten Speicherslot zurückgeben kann. (Oder äquivalent ein 4, 8, 16 usw. Bit-Datenstück oder ein Größenzeiger).

1
Sie denken, dass tausend 10⁶ (10 ^ 6) und eine Million 10⁹ (10 ^ 9) sind? Scott vor 5 Jahren 1
Ihre Nummer ist viel zu falsch. 3,904 GB ist [`3 904 000 000 000`] (https://www.google.com/search?q=3904gb+in+bytes&ie=utf-8&oe=utf-8) (nur 9 Nullen) und nicht 3.904.000.000.000.000.000. Es ist einfacher, in Form von ISO-Präfixen KMGTE zu denken ... anstelle von htmbt ... wie Sie geschrieben haben. Ich habe eine Weile gebraucht, um zu verstehen, was t und h bedeuten, wenn sie weit entfernt von der Tausend- und Einheitssäule sind phuclv vor 5 Jahren 0

2 Antworten auf die Frage

4
LawrenceC

Ein Zeiger zeigt auf enthält eine absolute Adresse.

Wenn Sie einen Wert hinzufügen müssen, bevor Sie den Zeiger verwenden, haben Sie einen Versatz und keinen echten Zeiger.

In C kann ein Leerzeiger ein Funktionszeiger sein, z. B. können Sie eine Funktion über ihn aufrufen. Damit dies funktioniert, benötigen Sie alle 64 Bit, wenn sich die CPU im 64-Bit-Modus befindet.

Wenn Ihre CPU 64 Adreßzeilen unterstützt (es kann physisch weniger haben), dann hat sie einen Adressraum von 2 ^ 64, was 0x1 0000 0000 0000 0000von 0x0000 0000 0000 0000bis reicht 0xFFFF FFFF FFFF FFFF.

Wenn Sie möchten, dass Ihr Zeiger von CPU-Anweisungen verwendet werden kann, ohne zusätzliche CPU-Anweisungen zu benötigen, um herauszufinden, was Sie wirklich bedeuten (nativer CPU-Code kann Zeiger direkt verarbeiten), muss er so breit sein wie der Adressraum der CPU.

Offsets sind langsamer, da die CPU hinzufügen muss, um die Adresse zu erhalten, die Sie möchten, obwohl CPUs über native Anweisungen verfügen, die dies ebenfalls tun.

Ich bin kein Superexperte für den x86-64-ISA, aber es gibt wahrscheinlich CPU-Anweisungen, die 32-Bit-Werte als 64-Bit-Werte behandeln, wobei die ersten 32 Bit als 0 angenommen werden. Die CPU muss das Reale intern noch "erweitern" Wert auf 64 Bit.

In x86 und x86-64 können Sie sicherlich 8-, 16-, 32- und 64-Bit- Offsets verwenden (keine x86 / x86-CPU-Anweisungen funktionieren nur mit 4-Bit-Werten)

Ein Zeiger "zeigt nicht auf eine absolute Adresse". Der Wert des Zeigers ist eine absolute Adresse - ein Ort im Speicher. (Nun, ok. Worauf ein Zeiger verweist, dh was dieser Speicherort enthält, könnte _ eine absolute Adresse sein, es könnte aber auch die Adresse eines Datenelements oder die Startadresse einer Datenstruktur usw. sein. Jamie Hanrahan vor 5 Jahren 1
1
phuclv

Erstens benötigen 3904 GB Speicher nur 42 Bits, um zu adressieren. Es besteht nur aus 3 904 000 000 000Bytes statt dem, was Sie berechnet haben

PS C:\> [math]::Log(3904GB, 2) 41.9307373375629 

Wenn Sie also selbst auf einem 64-Bit-Computer nur weniger als ~ 4 Milliarden Ganzzahlen (max. 32-Bit-Ganzzahl) verwenden, frage ich mich, warum Sie nicht einfach die Zeiger auf 32 Bit setzen können. Auf diese Weise sind Zeiger 32 Bit lang, bis der Speicherplatz ausgeht. Dann können Sie 64-Bit-Zeiger verwenden. Dann hätten Sie etwas mehr Platz, um mehr Objekte zu haben.

x32-ABI ist eine 64-Bit-x86-ABI, die 32-Bit-Zeiger verwendet. Prozesse haben nur einen 32-Bit-Adressraum, was bedeutet, dass sie nicht mehr als 4 GB Arbeitsspeicher benötigen (kein Problem für die meisten Benutzeranwendungen), sie können jedoch den größeren und breiteren Registerbereich nutzen. Der globale Speicherplatz beträgt immer noch 64 Bit, da dies hardwaremäßig festgelegt ist. Daher wird der 32-Bit-Zeiger anstelle eines direkten Zeigers als Versatz zur Basisadresse des Prozesses verwendet. Die Implementierung ist einfach so

void* getRealPointer(uintptr_t base_addr, uint32_t ptr) { return (void*)(base_addr + ptr); // value stored in pointer is the offset/distance from base } 

Diese Technik ist auch auf vielen anderen 64-Bit-Architekturen wie Sparc üblich ( warum verwendet Linux in der Sparc64-Architektur 32-Bit-Zeiger im Benutzerbereich und 64-Bit-Zeiger im Kernel-Space? ), MIPS oder PowerPC seit dem Übergang auf 64-Bit haben sie die Anzahl der Register wie x86 und ARM nicht erhöht, was bedeutet, dass ein 32-Bit-Prozess wahrscheinlich schneller als ein 64-Bit-Register ist, es sei denn, er benötigt 64-Bit-Berechnungen oder mehr als 2/3/4 GB RAM

Auf 64-Bit-Prozessoren wie dem G5 verwendet Debian PPC einen 64-Bit-Kernel mit 32-Bit-Benutzerplatz. Dies liegt daran, dass die 64-Bit-PowerPC-Prozessoren keinen "32-Bit-Modus" wie die Intel 64 / AMD64-Architektur aufweisen. Daher laufen 64-Bit-PowerPC-Programme, die keine mathematischen 64-Bit-Funktionen benötigen, etwas langsamer als ihre 32-Bit-Pendants, da 64-Bit-Zeiger und lange Ganzzahlen doppelt so viel Speicher verbrauchen, den CPU-Cache schneller füllen und daher mehr benötigen häufige Speicherzugriffe.

https://lwn.net/Articles/395894/

Trotzdem können Sie nicht einfach 32-Bit-Zeiger verwenden until you run out of space then start using 64-bit pointers, das macht keinen Sinn. Ein Typ hat immer eine feste Größe. Wenn Sie Platz für nur 32 Bit des Zeigers reservieren, was passiert dann, wenn Sie 64-Bit-Zeiger verwenden müssen? Wo lagern Sie den hohen Teil?


Wenn wir also 32-Bit-Zeiger haben, die auf 32-Bit-Blöcke im 64-Bit-Speicher verweisen, bin ich mir nicht sicher, wie das aussehen oder bedeuten soll

Das heißt wortadressierbares Gedächtnis . Statt auf jedes Byte zu zeigen, zeigt nun jeder Wert einfach auf ein anderes Wort

Es ist einfacher, sich vorzustellen, dass der Speicher aus einer Reihe linearer Zellen besteht, die durch eindeutige IDs identifiziert werden. Diese IDs nennen wir normalerweise "Adresse" und werden in Zeigern gespeichert. Die Zellengröße beträgt in modernen Systemen normalerweise 1 Byte (dh byteadressierbarer Speicher). Jedoch viele ältere Systeme wie die Unisys oder PDP tun Verwendung Wort-Speicher mit einer Zelle, die ein Wort enthält (36 Bit lang bei diesen Architekturen). Daher wäre in diesen Systemen char*eine größere int*Anzahl erforderlich, da Sie mehr Bits benötigen, um die Position des Bytes zu speichern, das Sie adressieren möchten

Ich verstehe dein Diagramm nicht ganz, aber die Leute müssen selten jedes Bit so ansprechen, da dies den gesamten Speicherplatz reduziert, den wir ansprechen können. Obwohl dies fair ist, gibt es einige Architekturen mit bitadressierbarem Speicher, hauptsächlich eingebettete Systeme. Wenn es so aussieht, als würden Sie das niedrige 32-Bit eines 64-Bit-Werts wünschen, wenn Sie der CPU eine 32-Bit-Adresse geben, dies funktioniert jedoch nicht. Um jede Hälfte zu adressieren, benötigen Sie ein weiteres signifikantes Bit anstelle der halben Anzahl solcher Bits. Das Prinzip ist einfach: Wenn wir eine größere Zellengröße als die gleiche Speichermenge verwenden, werden weniger Zellen benötigt, was bedeutet, dass weniger Bits für die ID benötigt werden. und umgekehrt. Auf der Hardwareebene ist die Zellengröße normalerweise festgelegt.

Nachfolgend finden Sie ein Beispiel für die ersten 16 Bytes im Speicher

╔══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╗ ║ 0000 │ 0001 │ 0010 │ 0011 │ 0100 │ 0101 │ 0110 │ 0111 │ 1000 │ 1001 │ 1010 │ 1011 │ 1100 │ 1101 │ 1110 │ 1111 ║ ╠══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╣ ║ b0 │ b1 │ b2 │ b3 │ b4 │ b5 │ b6 │ b7 │ b8 │ b9 │ b10 │ b11 │ b12 │ b13 │ b14 │ b15 ║ ╟──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────╢ ║ w0 000 │ w1 001 │ w2 010 │ w3 011 │ w4 100 │ w5 101 │ w6 110 │ w7 111 ║ ╟─────────────┴─────────────┼─────────────┴─────────────┼─────────────┴─────────────┼─────────────┴─────────────╢ ║ dw0 00 │ dw1 01 │ dw2 10 │ dw3 11 ║ ╟───────────────────────────┴───────────────────────────┼───────────────────────────┴───────────────────────────╢ ║ o0 │ o1 ║ ╚═══════════════════════════════════════════════════════╧═══════════════════════════════════════════════════════╝ 

Sie können sich auch die Illustration in dieser Antwort ansehen

Wenn wir jedes 2-Byte-Wort adressieren, hat das N-te Wort die Byteadresse als N * 2. Dies gilt für alle anderen Blockgrößen, bei denen der tatsächliche Versatz berechnet werden kann offset*sizeof(chunk). Als Ergebnis sind die 2 niedrigen Bits in einer 4-Byte-ausgerichteten Adresse die 3 niedrigen Bits in einer 8-Byte-ausgerichteten Adresse immer Null. Wenn Sie keine wortadressierbaren Zeiger verwenden, können diese niedrigen Bits zum Speichern von Daten verwendet werden, die als markierter Zeiger bezeichnet werden

64-Bit-JVM verwendet diese Technik mit komprimierten Oops . Siehe den Trick hinter JVMs komprimierten Oops- Objekten in Java sind immer auf 8 Byte ausgerichtet, sodass sie 8 * 4 = 32 GB Speicher mit 32-Bit-Adresse adressieren können.

Verwaltete Zeiger im Java-Heap zeigen auf Objekte, die an 8-Byte-Adressgrenzen ausgerichtet sind. Komprimierte Oops stellen verwaltete Zeiger (an vielen, aber nicht allen Stellen in der JVM-Software) als 32-Bit-Objektversätze von der 64-Bit-Java-Heap-Basisadresse dar. Da es sich um Objekt-Offsets anstelle von Byte-Offsets handelt, können sie verwendet werden, um bis zu vier Milliarden Objekte (keine Bytes) oder eine Heap-Größe von bis zu etwa 32 Gigabyte zu adressieren. Um sie verwenden zu können, müssen sie um den Faktor 8 skaliert und zur Basisadresse des Java-Heap hinzugefügt werden, um das Objekt zu finden, auf das sie sich beziehen. Objektgrößen mit komprimierten Oops sind vergleichbar mit denen im ILP32-Modus.

https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#compressedOop

Anweisungen, die auf den meisten RISC-Architekturen sofort ausgeführt werden, speichern auch die Wortadresse, da es keinen Sinn macht, wertvollen Speicherplatz zu sparen, um diese immer Null-Bits zu sparen. Zum Beispiel MIPS-Verzweigungs- und Sprunganweisungen : JAL, J, BEQ, BLEZ, BGTZ ...