tipos sirven que punteros puntero para los funciones estructura declaracion datos con cadenas aritmetica apuntadores c++ pointers casting reinterpret-cast static-cast

c++ - sirven - Forma correcta de lanzar tipos de puntero



punteros a cadenas (3)

Deberías static_cast . Utilice static_cast en los casos en que está deshaciendo una conversión implícita.

En este caso particular, sin embargo, no hay diferencia porque está convirtiendo de void* . Pero, en general, la reinterpret_cast entre dos punteros de objeto se define como (§5.2.10 / 7):

Un puntero de objeto se puede convertir explícitamente a un puntero de objeto de un tipo diferente. Cuando un prvalue v de tipo "puntero a T1 " se convierte al tipo "puntero a cv T2 ", el resultado es static_cast<cv T2*>(static_cast<cv void*>(v)) si ambos T1 y T2 son estándar -los tipos de instalación y los requisitos de alineación de T2 no son más estrictos que los de T1 , o si cualquiera de los tipos es void . 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 regresa a su tipo original, se obtiene el original valor del puntero El resultado de cualquier otra conversión de puntero no se especifica.

Énfasis mío Como T1 para ti ya está void* , el lanzamiento al void* en reinterpret_cast no hace nada. Esto no es cierto en general, que es lo que dice Drew Dormann :

#include <iostream> template <typename T> void print_pointer(const volatile T* ptr) { // this is needed by oversight in the standard std::cout << static_cast<void*>(const_cast<T*>(ptr)) << std::endl; } struct base_a {}; struct base_b {}; struct derived : base_a, base_b {}; int main() { derived d; base_b* b = &d; // implicit cast // undo implicit cast with static_cast derived* x = static_cast<derived*>(b); // reinterpret the value with reinterpret_cast derived* y = reinterpret_cast<derived*>(b); print_pointer(&d); print_pointer(x); print_pointer(y); }

Salida:

00CBFD5B
00CBFD5B
00CBFD5C

(Tenga en cuenta que porque y realidad no apunta a un derived , usarlo es un comportamiento indefinido).

Aquí, reinterpret_cast viene con un valor diferente porque pasa por void* . Es por eso que debes usar static_cast cuando puedas, y reinterpret_cast cuando sea necesario.

Teniendo en cuenta el siguiente código (y el hecho de que VirtualAlloc() devuelve un void* ):

BYTE* pbNext = reinterpret_cast<BYTE*>( VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));

¿Por qué se elige reinterpret_cast lugar de static_cast ?

Yo solía pensar que reinterpret_cast está bien para, por ejemplo, lanzar punteros DWORD_PTR desde tipos enteros (como por ejemplo, DWORD_PTR ), pero para convertir de un void* a un BYTE* , ¿no static_cast bien el static_cast ?

¿Hay alguna diferencia (¿sutil?) En este caso en particular, ¿o son solo dos lanzamientos de puntero válidos?

¿El estándar C ++ tiene una preferencia para este caso, sugiriendo una forma en lugar de la otra?


El uso de static_cast para lanzar un puntero static_cast desde void* está garantizado para preservar la dirección.

reinterpret_cast por otro lado, garantiza que si se transfiere el puntero de un tipo a otro y vuelve al tipo original, la dirección se conserva.

Aunque con la mayoría de las implementaciones, vería los mismos resultados en el uso de cualquiera de estos, se preferiría static_cast .

Y con C++11 , recuerdo que usar reinterpret_cast para void* tiene un comportamiento bien definido. Antes de eso, este comportamiento estaba prohibido.

It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.

Resolución propuesta (agosto de 2010):

Cambie 5.2.10 [expr.reinterpret.cast] párrafo 7 de la siguiente manera:

Un puntero de objeto se puede convertir explícitamente a un puntero de objeto de un tipo diferente. Cuando un prvalue v de tipo "puntero a T1" se convierte al tipo "puntero a cv T2", el resultado es static_cast (static_cast (v)) si tanto T1 como T2 son tipos de disposición estándar (3.9 [basic.types] ) y los requisitos de alineación de T2 no son más estrictos 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 regresa a su tipo original, se obtiene el original valor del puntero El resultado de cualquier otra conversión de puntero no está especificado.

Más información here .

Gracias a Jesse Good por el enlace.


Para punteros a tipos fundamentales ambos moldes tienen el mismo significado; así que tienes razón de que static_cast está bien.

Al convertir entre algunos tipos de punteros, es posible que la dirección de memoria específica mantenida en el puntero necesite cambiar .

Ahí es donde los dos moldes difieren. static_cast hará el ajuste apropiado. reinterpret_cast no lo hará.

Por esa razón, es una buena regla general para static_cast entre los tipos de punteros a menos que sepa que se desea reinterpret_cast .