Estoy algo confundido con la aplicabilidad de reinterpret_castfrente static_cast. Por lo que he leído, las reglas generales son usar reparto estático cuando los tipos se pueden interpretar en tiempo de compilación, de ahí la palabra static. Este es el reparto que el compilador de C ++ usa internamente también para los lanzamientos implícitos.
reinterpret_casts son aplicables en dos escenarios:
- convertir tipos enteros a tipos de puntero y viceversa
- convertir un tipo de puntero a otro. La idea general que tengo es que esto no es portátil y debe evitarse.
Cuando estoy un poco confundido es un uso que necesito, estoy llamando a C ++ desde C y el código C debe retener el objeto C ++, por lo que básicamente contiene un void*. ¿Qué reparto se debe usar para convertir entre el tipo void *y el de clase?
He visto el uso de ambos static_casty reinterpret_cast? Aunque, por lo que he estado leyendo, parece que statices mejor ya que el reparto puede suceder en tiempo de compilación. ¿Aunque dice usar reinterpret_castpara convertir de un tipo de puntero a otro?

reinterpret_castno sucede en tiempo de ejecución. Ambas son declaraciones en tiempo de compilación. De en.cppreference.com/w/cpp/language/reinterpret_cast : "A diferencia de static_cast, pero como const_cast, la expresión reinterpret_cast no se compila con ninguna instrucción de la CPU. Es puramente una directiva del compilador que le indica al compilador que trate la secuencia de bits (representación de objeto) de expresión como si tuviera el tipo new_type ".Respuestas:
El estándar C ++ garantiza lo siguiente:
static_castAl utilizar un puntero hacia y desde, sevoid*conserva la dirección. Es decir, a continuacióna,byctodos apuntan a la misma dirección:reinterpret_castsolo garantiza que si lanza un puntero a un tipo diferente y luegoreinterpret_castvuelve al tipo original , obtendrá el valor original. Entonces en lo siguiente:ayccontienen el mismo valor, pero el valor debno está especificado. (en la práctica, generalmente contendrá la misma dirección queayc, pero eso no se especifica en el estándar y puede que no sea cierto en máquinas con sistemas de memoria más complejos).Para lanzar hacia y desde
void*, sestatic_castdebe preferir.fuente
bya no se especifica en C ++ 11 cuando se usareinterpret_cast. Y en C ++ 03 se prohibió hacer un elenco deint*to (aunque los compiladores no implementaron eso y no era práctico, por lo tanto, se cambió para C ++ 11).void*reinterpret_castUn caso cuando
reinterpret_castes necesario es cuando se interactúa con tipos de datos opacos. Esto ocurre con frecuencia en las API de proveedores sobre las cuales el programador no tiene control. Aquí hay un ejemplo artificial en el que un proveedor proporciona una API para almacenar y recuperar datos globales arbitrarios:Para usar esta API, el programador debe enviar
VendorGlobalUserDatay volver sus datos .static_castno funcionará, uno debe usarreinterpret_cast:A continuación se muestra una implementación artificial de la API de muestra:
fuente
void*para eso?USpoofChecker*, dondeUSpoofCheckerhay una estructura vacía. Sin embargo, debajo del capó, cada vez que pasa unUSpoofChecker*, se sometereinterpret_casta un tipo interno de C ++.La respuesta corta: si no sabe lo que
reinterpret_castsignifica, no lo use. Si lo necesitará en el futuro, lo sabrá.Respuesta completa:
Consideremos los tipos de números básicos.
Cuando convierte, por ejemplo,
int(12)aunsigned float (12.0f)su procesador, debe invocar algunos cálculos, ya que ambos números tienen una representación de bits diferente. Esto es lo questatic_castsignifica.Por otro lado, cuando llama a
reinterpret_castla CPU no invoca ningún cálculo. Simplemente trata un conjunto de bits en la memoria como si tuviera otro tipo. Entonces, cuando convierteint*afloat*esta palabra clave, el nuevo valor (después de desreferenciar el puntero) no tiene nada que ver con el valor anterior en significado matemático.Ejemplo: es cierto que
reinterpret_castno es portátil debido a una razón: el orden de bytes (endianness). Pero esta es a menudo sorprendentemente la mejor razón para usarlo. Imaginemos el ejemplo: tiene que leer el número binario de 32 bits del archivo, y sabe que es big endian. Su código debe ser genérico y funciona correctamente en sistemas big endian (por ejemplo, algunos ARM) y little endian (por ejemplo, x86). Por lo tanto, debe verificar el orden de los bytes.Es bien conocido en tiempo de compilación, por lo que puede escribir unapuede escribir una función para lograr esto:constexprfunción:Explicación: la representación binaria de
xin memory podría ser0000'0000'0000'0001(big) o0000'0001'0000'0000(little endian). Después de reinterpretar el byte bajo elppuntero podría ser respectivamente0000'0000o0000'0001. Si usa fundición estática, siempre lo será0000'0001, sin importar qué endianness se esté utilizando.EDITAR:
En la primera versión hice una función de ejemplo
is_little_endianpara serconstexpr. Se compila bien en el nuevo gcc (8.3.0) pero el estándar dice que es ilegal. El compilador clang se niega a compilarlo (lo cual es correcto).fuente
shorttoma 16 bits en la memoria. CorregidoEl significado de
reinterpret_castno está definido por el estándar C ++. Por lo tanto, en teoría areinterpret_castpodría bloquear su programa. En la práctica, los compiladores intentan hacer lo que esperas, que es interpretar los bits de lo que estás pasando como si fueran del tipo al que estás enviando. Si sabes qué hacen los compiladores que vas a usar,reinterpret_castpuedes usarlo, pero decir que es portátil sería mentiroso.Para el caso que describe, y prácticamente cualquier caso en el que pueda considerar
reinterpret_cast, puede usarstatic_castu otra alternativa en su lugar. Entre otras cosas, el estándar tiene esto que decir sobre lo que puede esperar destatic_cast(§5.2.9):Entonces, para su caso de uso, parece bastante claro que el comité de estandarización pretendía que lo usara
static_cast.fuente
reinterpret_crash. De ninguna manera un error del compilador me impedirá bloquear mi programa de reinterpretación. ¡Informaré un error lo antes posible! </irony>template<class T, U> T reinterpret_crash(U a) { return *(T*)nullptr; }Un uso de reinterpret_cast es si desea aplicar operaciones bit a bit a flotantes (IEEE 754). Un ejemplo de esto fue el truco Fast Inverse Square-Root:
https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code
Trata la representación binaria del flotador como un número entero, lo desplaza a la derecha y lo resta de una constante, reduciendo a la mitad y negando el exponente. Después de volver a convertir a un flotador, se somete a una iteración de Newton-Raphson para que esta aproximación sea más exacta:
Esto se escribió originalmente en C, por lo que utiliza los moldes de C, pero el elenco análogo de C ++ es reinterpret_cast.
fuente
error: invalid cast of an rvalue expression of type 'int64_t {aka long long int}' to type 'double&' reinterpret_cast<double&>((reinterpret_cast<int64_t&>(d) >> 1) + (1L << 61))- ideone.com/6S4ijcreinterpret_castpormemcpy, ¿sigue siendo UB?memcpyDefinitivamente lo haría legal.Puede usar reinterprete_cast para verificar la herencia en tiempo de compilación.
Mire aquí: Uso de reinterpret_cast para verificar la herencia en tiempo de compilación
fuente
Traté de concluir y escribí un elenco seguro simple usando plantillas. Tenga en cuenta que esta solución no garantiza lanzar punteros en una función.
fuente
reinterpret_castya hace en esta situación: "Un puntero de objeto puede convertirse explícitamente en un puntero de objeto de un tipo diferente. [72] Cuando un valorvde tipo de puntero de objeto se convierte en el tipo de puntero de objeto" puntero a cvT", el resultado esstatic_cast<cv T*>(static_cast<cv void*>(v))". - N3797.c++2003norma que puedo no encontrar quereinterpret_castlo hacestatic_cast<cv T*>(static_cast<cv void*>(v))C++03lo fueraC++98. Toneladas de proyectos utilizaron C ++ antiguo en lugar de C. portátil. A veces hay que preocuparse por la portabilidad. Por ejemplo, debe admitir el mismo código en Solaris, AIX, HPUX, Windows. En lo que respecta a la dependencia y portabilidad del compilador es complicado. Entonces, un buen ejemplo de la introducción de un infierno de portabilidad es usar unreinterpret_casten su códigoPrimero tienes algunos datos en un tipo específico como int aquí:
Entonces desea acceder a la misma variable que otro tipo como flotante: puede decidir entre
o
BREVE: significa que se usa la misma memoria que un tipo diferente. Por lo tanto, podría convertir representaciones binarias de flotantes como tipo int como arriba en flotantes. 0x80000000 es -0 por ejemplo (la mantisa y el exponente son nulos pero el signo, el msb, es uno. Esto también funciona para dobles y dobles largos.
OPTIMIZE: Creo que reinterpret_cast se optimizaría en muchos compiladores, mientras que el c-casting se realiza mediante pointeraritmética (el valor debe copiarse en la memoria, porque los punteros no pueden apuntar a registros de CPU).
NOTA: ¡En ambos casos, debe guardar el valor emitido en una variable antes de lanzarlo! Esta macro podría ayudar:
fuente
reinterpret_castformaintquefloat&es un comportamiento indefinido.Una razón para usar
reinterpret_castes cuando una clase base no tiene una vtable, pero una clase derivada sí. En ese caso,static_castyreinterpret_castdará como resultado diferentes valores de puntero (este sería el caso atípico mencionado por jalf arriba ). Solo como descargo de responsabilidad, no estoy afirmando que esto sea parte del estándar, sino la implementación de varios compiladores generalizados.Como ejemplo, tome el siguiente código:
Lo que genera algo como:
En todos los compiladores que probé (MSVC 2015 y 2017, clang 8.0.0, gcc 9.2, icc 19.0.1 - ver godbolt para los últimos 3 ) el resultado del
static_castdifiere del dereinterpret_cast2 por 4 (4 para MSVC). El único compilador que advirtió sobre la diferencia fue el sonido metálico, con:Una última advertencia es que si la clase base no tiene miembros de datos (por ejemplo, el
int i;) entonces clang, gcc e icc devuelven la misma dirección parareinterpret_castque parastatic_cast, mientras que MSVC todavía no.fuente
Aquí hay una variante del programa de Avi Ginsburg que ilustra claramente la propiedad
reinterpret_castmencionada por Chris Luengo, flodin y cmdLP: que el compilador trata la ubicación de memoria apuntada como si fuera un objeto del nuevo tipo:Lo que da como resultado una salida como esta:
Se puede ver que el objeto B se construye en la memoria como datos específicos de B primero, seguido por el objeto A incrustado. El
static_castdevuelve correctamente la dirección del objeto A incrustado, y el puntero creado porstatic_castcorrectamente da el valor del campo de datos. El puntero generado por la ubicación de la memoria dereinterpret_casttratabcomo si fuera un objeto A simple, por lo que cuando el puntero intenta obtener el campo de datos, devuelve algunos datos específicos de B como si fueran los contenidos de este campo.Un uso de
reinterpret_castes convertir un puntero a un entero sin signo (cuando los punteros y los enteros sin signo son del mismo tamaño):int i;unsigned int u = reinterpret_cast<unsigned int>(&i);fuente
Respuesta rápida: use
static_castsi se compila, de lo contrario recurra areinterpret_cast.fuente
¡Lea las preguntas frecuentes ! Mantener datos de C ++ en C puede ser arriesgado.
En C ++, un puntero a un objeto se puede convertir
void *sin ninguna conversión . Pero no es cierto al revés. Necesitaría unstatic_castpara recuperar el puntero original.fuente