2010-07-21 1429 views
10

De acuerdo con C++ Standard, un reinterpret_cast de un puntero T* a otro tipo de puntero Q*can change or not change the pointer value dependiendo de la implementación.¿Algún ejemplo real de reinterpret_cast que cambia el valor de un puntero?

Estoy muy interesado, ¿hay algún ejemplo real de una implementación en C++ donde el lanzamiento de un puntero a algún otro tipo de puntero con reinterpret_cast cambia el puntero? ¿Qué y por qué se cambia allí?

+0

quieres decir, "cambia el valor" al que apunta el puntero? – akira

+0

@akira: no, cambia el valor del puntero en sí – sharptooth

+0

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

Respuesta

6

Tenga en cuenta que cuando la norma establece que puede o no puede hacer algo, no significa que haya una implementación actual que tenga ese comportamiento, solo que podrían hacerlo.

Lo más parecido que puedo pensar es una arquitectura donde el hardware requirió alineación de tipo y una implementación que decidió corregir la alineación si fuera necesario. Algo así como:

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] 

No podría ser un requisito para que a sea un puntero válido que tiene que hacer frente a un múltiplo posición de memoria de 8, mientras que el argumento q con menores requisitos de alineación podría apuntar a cualquier dirección de 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 medios me dan el puntero a un objeto A2 dentro del objeto B. reinterpret_cast<A2*>(&b) significa dame el puntero a b y trátalo como un puntero A2. El resultado de este reinterpret_cast tiene el tipo 'puntero a A2', por lo tanto, no produce ninguna advertencia cuando se asigna a una variable void * (oa una variable A2 *).

+0

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

+5

En tu ejemplo, 'reinterpret_cast' no cambia el valor en absoluto ... estás fuera, me temo. –

+0

En 'A2 * p_a2 = & b;' utiliza la conversión implícita que es equivalente a 'static_cast', no' reinterpret_cast'. – sharptooth

0

Reinterpret_cast nunca devolverá una dirección diferente - se requiere copiar la dirección exacta.

En los casos de herencia múltiple, como dijo David Rodríguez, tomar la dirección de una de las bases puede devolver una dirección que tiene un desplazamiento a la dirección de la primera base. Reinterpret_cast devolverá esa dirección de desplazamiento, pero si la trata como la dirección actualizada, se producirá el infierno.

Para el upcasting, static_cast puede devolver una dirección diferente a la dada. Si la dirección que tiene es una de las bases, y esa dirección está siendo compensada con la dirección de la primera base, static_cast devolverá una dirección válida para el objeto presentado, que es igual a la dirección de la primera base y por lo tanto no igual al puntero pasado.

Para resumir: reinterpret_cast te da la misma dirección, siempre. Static_cast y dynamic_cast pueden devolver una dirección diferente, p. en ciertos casos que involucran herencia múltiple.

La diferencia entre static_cast y dynamic_cast es que static_cast no verifica si el puntero que le da es el objeto correcto para el molde, así que asegúrese de eso antes de llamarlo.

+1

Se debe hacer una copia de seguridad de una declaración que incluya "requerido" con una fuente. Todo lo que veo es que puede convertir a un puntero de tipo menos estrictamente alineado * y luego de nuevo *, y "El resultado de cualquier otra conversión de puntero no está especificado". (5.2.10/7) – Potatoswatter

+1

Um, me perdí los problemas de alineación por completo, puedo ver cómo eso cambiaría la dirección. Gracias por la corrección. – Alex

1

La fuente más probable de problemas está en una máquina vectorial donde las operaciones escalares se definen en términos de vectores, y un puntero escalar consiste en un puntero a vector con un índice en el vector. Históricamente, la arquitectura original de Cray era así y causaba dolores de cabeza. Hoy en día es posible que veas algo así en una GPU, pero no puedo señalar algo específico fuera de mi cabeza.

El efecto más probable es el truncamiento ya que el tipo de puntero de destino carece de bits para especificar la parte del índice.C++ 11 da un guiño en esta dirección al permitir que cualquier tipo de puntero sea reinterpret_cast ed siempre que tengan los mismos requisitos de alineación. Se permite que los bits "cero" por alineación rigurosa no existan.

Un puntero de objeto se puede convertir explícitamente en un puntero a objeto de un tipo diferente. Cuando un prvalue v de tipo "puntero a T1" es convertido al tipo "puntero a cv T2", el resultado es static_cast<cv T2*>(static_cast<cv void*>(v)) si tanto T1 como T2 son diseños estándar (3.9) y los requisitos de alineación de T2 son no más estricto que los de T1, o si cualquiera de los tipos es nulo. Convirtiendo un prvalue de tipo "puntero a T1" al tipo "puntero a T2" (donde T1 y T2 son tipos de objetos y donde los requisitos de alineación de T2 no son más estrictos que los de T1) y de vuelta a su tipo original produce el valor del puntero original. El resultado de cualquier otra conversión de dicho puntero no está especificado.

1

No creo que la pregunta sea significativamente diferente para C++ versus C puntero. De this answer cito solo uno de los ejemplos:

serie

El Eclipse MV de datos generales tiene tres formatos de puntero apoyados arquitectónicamente (Word, bytes, y los punteros bits), dos de los cuales son utilizados por los compiladores de C: Punteros byte para char* y void* y punteros de palabras para todo lo demás

Eso sugiere un reinterpret_cast<Word_Aligned_Type*>(char*) podría perder su sentido de qué personaje/byte de la palabra estaba siendo señaló, por lo que la operación irreversible.

Cuestiones relacionadas