Per aggiungere alla risposta di Dean, ecco qualcosa sulle conversioni puntatore in generale. Ho dimenticato qual è il termine, ma un puntatore al cast del puntatore non esegue alcuna conversione (nello stesso modo in cui int è float). È semplicemente una reinterpretazione dei bit a cui puntano (tutto per il beneficio del compilatore). "Conversione non distruttiva" penso che sia stato. I dati non cambiano, solo come il compilatore interpreta ciò che viene indicato.
esempio,
Se ptr
è un puntatore a un object
, il compilatore sa che esiste un campo con un offset particolare denominato type
di tipo enum type
. D'altra parte se ptr
viene lanciato su un puntatore a un tipo diverso, cons_object
, di nuovo saprà come accedere ai campi dello cons_object
ciascuno con i propri offset in modo simile.
Per illustrare immaginare il layout di memoria per un cons_object
:
+---+---+---+---+
cons_object *ptr -> | t | y | p | e | enum type
+---+---+---+---+
| c | a | r | | object *
+---+---+---+---+
| c | d | r | | object *
+---+---+---+---+
Il campo type
ha compensato 0, car
è 4, cdr
è 8. Per accedere al campo auto, tutto il compilatore ha bisogno di fare è aggiungere 4
al puntatore alla struttura.
Se il puntatore è stato lanciato ad un puntatore ad un object
:
+---+---+---+---+
((object *)ptr) -> | t | y | p | e | enum type
+---+---+---+---+
| c | a | r | |
+---+---+---+---+
| c | d | r | |
+---+---+---+---+
Tutto il compilatore ha bisogno di sapere è che c'è un campo denominato type
con all'offset 0. Tutto ciò che è in memoria è in memoria.
I puntatori non devono nemmeno essere correlati. È possibile avere un puntatore a int
e convertirlo in un puntatore a cons_object
. Se si dovesse accedere al campo car
, è proprio come qualsiasi normale accesso alla memoria. Ha un certo offset dall'inizio della struttura. In questo caso, ciò che è in quella posizione di memoria è sconosciuto ma non è importante. Per accedere a un campo, è necessario solo l'offset e tali informazioni sono reperibili nella definizione del tipo.
un puntatore ad un int
punti per un blocco di memoria:
+---+---+---+---+
int *ptr -> | i | n | t | | int
+---+---+---+---+
Casted a un puntatore cons_object
:
+---+---+---+---+
((cons_object *)ptr) -> | i | n | t | | enum type
+---+---+---+---+
| X | X | X | X | object *
+---+---+---+---+
| X | X | X | X | object *
+---+---+---+---+
interessante. questa conoscenza sta semplificando molto il mio codice. Grazie. –
Si dovrebbe menzionare che questo è C legittimo con un comportamento ben definito, e non un "hack" o invocazione di "comportamento non definito". –
ri. object-in-cons_object: puoi anche utilizzare macro per rendere un po 'più sicuro il typecasting in questo caso, ad es. #define OBJECT (x) & ((x) -> parent). Questo non ha costi di runtime (è un indirizzo di memoria uguale a x), ma significa che non casualmente casti qualcosa di strano. –