Loading...
 

Crystal Pointers


Pointer sind Zeiger auf eine bestimmte Adresse im Speicher. Über diesen Zeiger kann man dann auf die Speicherstelle zugreifen.

Es gibt verschiedene Arten einen Pointer zu erstellen:

pointerof(var)

# Pointer über Variable
var1 = 61_938_u16           # reserviert 2 Byte im Speicher 0xF1F2
var2 = 254_u8               # reserviert 1 Byte im Speicher
var3 = 201_u8

# Pointer erzeugen
ptr1 = pointerof(var1)      # erzeugt einen Pointer auf var1
ptr2 = pointerof(var2)
ptr3 = pointerof(var3)

# Infos auf welche Speicherzelle gezeigt wird
p! ptr1                     # gibt Infos über den Pointer aus
p! ptr2
p! ptr3

# Zugriff auf den Inhalt der Speicherstelle
puts ptr1[0]                # gibt den Speicherinhalt aus, auf den der Pointer zeigt also 61938
puts ptr1.value          # das Gleiche wie ptr1[0]
puts ptr2[0]                # 254
puts ptr3[0]                # 201

# Pointer offset verwenden
puts ptr3[1]                # den Pointer um 1 erhöht und er zeigt auf var2 also 254
puts ptr3[2]                # von var1 das untere Byte 0xF2
puts ptr3[3]                # von var1 das obere Byte 0xF1


Gibt folgendes aus:
Die Adressen sind freilich immer wieder anders.

ptr1 # => Pointer(UInt16)@0x7ffdd9ac4b36
ptr2 # => Pointer(UInt8)@0x7ffdd9ac4b35
ptr3 # => Pointer(UInt8)@0x7ffdd9ac4b34
61938
254
201
254
242
241


In Crystal werden Pointer als unsafe bezeichnet. Dies beduetet, dass man damit unsicheren Code schreiben kann. Wie man im oberen Beispiel sieht, kann man damit auf Speicherstellen zugreifen, die man vielleicht gar nicht haben will. Niemand weiß, was z. B. in ptr4 steht.


So kann man auf einzelne Bytes in einer mehreren Bytes großen Speicherstelle zugreifen:

# Zugriff auf einzelne Bytes in einem 32 Bit Pointer
var32 = 0x0F0E0D0C_i32

ptr32 = pointerof(var32)    # dieser Pointer zeigt auf 32 Bit also 4 Bytes
p! ptr32
puts ptr32[0]

ptr32_8 = ptr32.as(Int8*)   # Pointer darf man casten; hier wird aus dem 4 Byte-Pointer ein 1 Byte Pointer

p! ptr32_8                  # der zeigt immer noch auf das erste Byte

puts ptr32_8[0]             # so kommt man zum 1. Byte
puts ptr32_8[1]             # 2. Byte
puts ptr32_8[2]             # 3. Byte
puts ptr32_8[3]             # 4. Byte


Ausgabe

ptr32 # => Pointer(Int32)@0x7fffb9d2be7c
252579084 # 0xF0E0D0C
ptr32_8 # => Pointer(Int8)@0x7fffb9d2be7c
12      # 0x0C
13      # 0x0D
14      # 0x0E
15      # 0x0F