2010-07-21 4 views
10

In base allo standard C++, un reinterpret_cast di un puntatore T* a un altro puntatore di tipo Q*can change or not change the pointer value a seconda dell'implementazione.Qualche esempio reale di reinterpret_cast che modifica il valore di un puntatore?

Sono molto interessato: esiste un vero esempio di implementazione in C++ in cui il cast di un puntatore a un altro tipo di puntatore con reinterpret_cast modifica il puntatore? Cosa e perché è cambiato lì?

+0

significa "modifica il valore" a cui punta il puntatore? – akira

+0

@akira: no, cambia il valore del puntatore stesso – sharptooth

+0

intendendo: 'T * t = 0x13; Q * q = 0x42; t = reintrepret_cast (q); 'produce' t! = 0x42'? – akira

risposta

6

Si noti che quando lo standard afferma che può o non può eventualmente fare qualcosa, ciò non significa che ci sia qualche implementazione corrente che ha quel comportamento, solo che potrebbero farlo.

Il più vicino a cui riesco a pensare è un'architettura in cui è richiesto l'allineamento dei tipi da parte dell'hardware e un'implementazione che ha deciso di correggere l'allineamento, se necessario. Qualcosa di simile:

aligned8 var; 
aligned1 *p = reinterpret_cast<aligned1*>(&var); 
aligned1 *q = p + 1; // assuming aligned 1 size is not multiple of 8 
aligned8 *a = reinterpret_cast<aligned8*>(q); // [1] 

Ci potrebbe essere un requisito che per a essere un puntatore valido deve affrontare una posizione di memoria multiplo di 8, mentre l'argomento q con requisiti di allineamento minori potrebbe puntare a qualsiasi indirizzo di memoria.

2
class A1 { int a1; }; 
class A2 { int a2; }; 

class B: public A1, public A2 { }; 

#define DBG(val) cout << #val << ": " << val << endl 

// test code 
B b; 
DBG(&b);           // prints 0x42 

void *p_blank = &b; 
DBG(p_blank);          // prints 0x42 
A2 *p_a2 = &b; 
DBG(p_a2);           // prints 0x46 
void *p_reinterpreted = reinterpret_cast<A2*>(&b); 
DBG(p_reinterpreted);        // prints 0x42 
A2 *p_reinterpreted2 = reinterpret_cast<A2*>(&b); 
DBG(p_reinterpreted2);        // prints 0x42 

A2 *p_a2 = &b mezzi mi danno il puntatore a un oggetto A2 all'interno dell'oggetto B. significa dammi il puntatore a b e trattalo come un puntatore A2. Il risultato di questo reinterpret_cast ha il tipo 'puntatore a A2', quindi non produce alcun avviso quando viene assegnato a una variabile void * (oa una variabile A2 *).

+0

'A2 * p_a2 = & b;' mi sorprende ... – akira

+5

Nel tuo esempio il 'reinterpret_cast' non cambia affatto il valore ... sei fuori che ho paura. –

+0

In 'A2 * p_a2 = & b;' usi la conversione implicita che è equivalente a 'static_cast', non' reinterpret_cast'. – sharptooth

0

Reinterpret_cast non restituirà mai un indirizzo diverso: è necessario copiare l'indirizzo esatto.

In caso di ereditarietà multipla, come ha affermato David Rodriguez, l'indirizzo di una delle basi può restituire un indirizzo che ha un offset all'indirizzo della prima base. Reinterpret_cast restituirà quell'indirizzo offset, ma se lo tratti come indirizzo upcast, ne conseguirà l'inferno.

Per l'upcasting, static_cast può restituire un indirizzo diverso da quello specificato. Se l'indirizzo che hai è una delle basi e quell'indirizzo è in offset rispetto al primo indirizzo di base, static_cast restituirà un indirizzo valido per l'oggetto upcasted, che è uguale all'indirizzo della prima base e quindi non è uguale al puntatore passato.

Per farla breve: reinterpret_cast ti dà lo stesso indirizzo, sempre. Static_cast e dynamic_cast potrebbero restituire un indirizzo diverso, ad es. in alcuni casi che coinvolgono eredità multiple.

La differenza tra static_cast e dynamic_cast è che static_cast non controlla se il puntatore che gli dai è l'oggetto giusto per il cast, quindi assicurati di farlo prima di chiamarlo.

+1

Un'istruzione che coinvolge "richiesto" deve essere sottoposta a backup con un'origine. Tutto quello che vedo è che ti è permesso di convertire in un puntatore di tipo meno strettamente allineato * e poi di nuovo *, e "Il risultato di qualsiasi altra conversione del puntatore non è specificato." (5.2.10/7) – Potatoswatter

+1

Um, ho perso completamente i problemi di allineamento, posso vedere come questo cambierebbe l'indirizzo. Grazie per la correzione. – Alex

1

La fonte più probabile di problemi è su una macchina vettoriale in cui le operazioni scalari sono definite in termini di vettori e un puntatore scalare è costituito da un puntatore al vettore con un indice nel vettore. Storicamente l'architettura Cray originale era così e causava mal di testa. Al giorno d'oggi potresti vedere qualcosa di simile su una GPU, ma non riesco a indicare qualcosa di specifico in cima alla mia testa.

L'effetto più probabile è il troncamento poiché il tipo di puntatore di destinazione non contiene bit per specificare la parte dell'indice.C++ 11 dà un cenno in questa direzione consentendo a qualsiasi tipo di puntatore di essere reinterpret_cast a condizione che abbiano gli stessi requisiti di allineamento. I bit "azzerati" da un allineamento rigoroso non possono esistere.

Un puntatore di oggetto può essere convertito esplicitamente in un puntatore di oggetto di di un tipo diverso. Quando un valore di v di tipo "puntatore a T1" è convertito nel tipo "puntatore a cv T2", il risultato è static_cast<cv T2*>(static_cast<cv void*>(v)) se T1 e T2 sono di tipo standard (3.9) e i requisiti di allineamento di T2 sono non più rigidi di quelli di T1, o se uno dei due tipi è nullo. Conversione di un valore di tipo "puntatore a T1" al tipo "puntatore a T2" (dove T1 e T2 sono tipi e dove i requisiti di allineamento di T2 non sono più rigidi di quelli di T1) e tornano al suo tipo originale restituisce il valore del puntatore originale . Il risultato di qualsiasi altra conversione di questo puntatore non è specificato.

1

Non penso che la domanda sia significativamente diversa per i cast di puntatore C++ versus C. Da this answer cito solo uno degli esempi:

serie

The Eclipse MV da dati generali ha tre formati puntatore architettonicamente supportati (Word, byte, e puntatori bit), due dei quali vengono utilizzati da compilatori C: puntatori di byte per char* e void*, e puntatori parola per tutto il resto

Questo suggerisce una reinterpret_cast<Word_Aligned_Type*>(char*) potrebbe perdere il suo senso di quale personaggio/byte nella parola veniva puntato, rendendo l'operazione irreversibile.

Problemi correlati