static_cast reinterpret_cast dynamic_cast cast c++ casting integer-overflow openvms

c++ - reinterpret_cast - ¿Cómo se puede establecer una static_cast entre unsigned int e int?



static_cast c++ (4)

Aquí hay otra solución que funcionó para mí:

if (val <= INT_MAX) { return static_cast<int>(val); } else { int ret = static_cast<int>(val & ~INT_MIN); return ret | INT_MIN; }

Si encubro el bit alto, evito el desbordamiento al lanzar. Entonces puedo O regresar de manera segura.

Tengo una string 8 caracteres que representa un número hexadecimal y necesito convertirlo a un int . Esta conversión debe preservar el patrón de bits para las cadenas "80000000" y superiores, es decir, esos números deberían ser negativos. Desafortunadamente, la solución ingenua:

int hex_str_to_int(const string hexStr) { stringstream strm; strm << hex << hexStr; unsigned int val = 0; strm >> val; return static_cast<int>(val); }

no funciona para mi compilador si val > MAX_INT (el valor devuelto es 0). Cambiar el tipo de val a int también da como resultado un 0 para los números más grandes. He intentado varias soluciones diferentes de varias respuestas aquí en SO y todavía no he tenido éxito.

Esto es lo que sé:

  • Estoy usando el compilador C ++ de HP en OpenVMS (usando, creo, un procesador Itanium).
  • sizeof(int) será al menos 4 en cada arquitectura en la que se ejecute mi código.
  • La conversión desde un número> INT_MAX a int está definida por la implementación. En mi máquina, por lo general, resulta en un 0, pero curiosamente lanzando resultados long a int en INT_MAX cuando el valor es demasiado grande.

Esto es sorprendentemente difícil de hacer correctamente, o al menos lo ha sido para mí. ¿Alguien sabe de una solución portátil para esto?

Actualizar:

Cambiar static_cast para reinterpret_cast da como resultado un error de compilación. Un comentario me indujo a probar un molde de estilo C: return (int)val en el código anterior, y funcionó. En esta máquina ¿Seguirá siendo seguro en otras arquitecturas?


Citando el estándar C ++ 03, §4.7 / 3 (Conversiones integrales):

Si el tipo de destino está firmado, el valor no se modifica si se puede representar en el tipo de destino (y el ancho del campo de bits); de lo contrario, el valor está definido por la implementación .

Debido a que el resultado está definido por la implementación, por definición es imposible que haya una solución realmente portátil .


Puede negar un número de complemento a dos sin firmar tomando el complemento y agregando uno. Así que hagámoslo por los negativos:

if (val < 0x80000000) // positive values need no conversion return val; if (val == 0x80000000) // Complement-and-addition will overflow, so special case this return -0x80000000; // aka INT_MIN else return -(int)(~val + 1);

Esto supone que tus ints están representados con una representación de complemento a dos de 32 bits (o tienen un rango similar). No se basa en ningún comportamiento indefinido relacionado con el desbordamiento de entero con signo (tenga en cuenta que el comportamiento del desbordamiento de entero sin signo está bien definido, ¡aunque eso tampoco debería ocurrir aquí!).

Tenga en cuenta que si sus entradas no son de 32 bits, las cosas se vuelven más complejas. Es posible que necesite usar algo como ~(~0U >> 1) lugar de 0x80000000 . Además, si sus datos no son un complemento a dos, puede tener problemas de desbordamiento en ciertos valores (por ejemplo, en una máquina de complemento a -0x80000000 , -0x80000000 no se puede representar en un entero con signo de 32 bits). Sin embargo, las máquinas que no son de dos en dos son muy raras hoy en día, por lo que es poco probable que esto sea un problema.


Si bien hay formas de hacer esto usando conversiones y conversiones, la mayoría depende de un comportamiento indefinido que tiene comportamientos bien definidos en algunas máquinas / con algunos compiladores. En lugar de confiar en un comportamiento indefinido, copie los datos:

int signed_val; std::memcpy (signed_val, val, sizeof(int)); return signed_val;