Pregunta

Estoy tratando de convertir 65529 desde un unsigned int a un firmado int. Intenté hacer un elenco como este:

unsigned int x = 65529;
int y = (int) x;

Pero y sigue devolviendo 65529 cuando debe regresar -7. ¿Porqué es eso?

¿Fue útil?

Solución

Parece que estás esperando int y unsigned int ser un entero de 16 bits. Aparentemente, ese no es el caso. Lo más probable es que sea un entero de 32 bits, que es lo suficientemente grande como para evitar la envoltura que está esperando.

Tenga en cuenta que no existe una forma totalmente compatible con esto porque el lanzamiento entre firmado/sin firmar para valores fuera de rango está definido por la implementación. Pero esto seguirá funcionando en la mayoría de los casos:

unsigned int x = 65529;
int y = (short) x;      //  If short is a 16-bit integer.

o alternativamente:

unsigned int x = 65529;
int y = (int16_t) x;    //  This is defined in <stdint.h>

Otros consejos

Sé que es una pregunta antigua, pero es buena, entonces, ¿qué tal esto?

unsigned short int x = 65529U;
short int y = *(short int*)&x;

printf("%d\n", y);

@Mysticial lo consiguió. Un corto suele ser de 16 bits e ilustrará la respuesta:

int main()  
{
    unsigned int x = 65529;
    int y = (int) x;
    printf("%d\n", y);

    unsigned short z = 65529;
    short zz = (short)z;
    printf("%d\n", zz);
}

65529
-7
Press any key to continue . . .


Un poco más de detalle. Se trata de cómo se almacenan los números firmados en la memoria. Busque la notación de TwoS-Complement para obtener más detalles, pero aquí están los conceptos básicos.

Así que veamos 65529 decimal. Se puede representar como FFF9h en hexadecimal. También podemos representar eso en binario como:

11111111 11111001

Cuando declaramos short zz = 65529;, el compilador interpreta 65529 como un valor firmado. En la notación de Twos-Complement, el bit superior significa si un valor firmado es positivo o negativo. En este caso, puede ver que la parte superior es un 1, por lo que se trata como un número negativo. Por eso se imprime -7.

Por un unsigned short, no nos importa el signo ya que es unsigned. Entonces, cuando lo imprimimos usando %d, usamos los 16 bits, por lo que se interpreta como 65529.

Para entender por qué, debe saber que la CPU representa los números firmados usando el complemento de los dos (tal vez no todo, sino muchos).

    byte n = 1; //0000 0001 =  1
    n = ~n + 1; //1111 1110 + 0000 0001 = 1111 1111 = -1

Y también, que el tipo int y un sin firmado pueden ser de diferentes tamaños dependiendo de su CPU. Al hacer cosas específicas como esta:

   #include <stdint.h>
   int8_t ibyte;
   uint8_t ubyte;
   int16_t iword;
   //......

La representación de los valores 65529U y -7 son idénticos para los INT de 16 bits. Solo la interpretación de los bits es diferente.

Para INTS más grandes y estos valores, debe firmar la extensión; Una forma es con operaciones lógicas

int y = (int )(x | 0xffff0000u); // assumes 16 to 32 extension, x is > 32767

Si la velocidad no es un problema o la división es rápida en su procesador,

int y = ((int ) (x * 65536u)) / 65536;

El múltiple cambia a la izquierda 16 bits (nuevamente, suponiendo 16 a 32 extensión), y la división cambia a la derecha manteniendo el signo.

Estás esperando que tu int El tipo tiene 16 bits de ancho, en cuyo caso obtendrá un valor negativo. Pero lo más probable es que tengan 32 bits de ancho, por lo que un firmado int puede representar 65529 muy bien. Puede verificar esto imprimiendo sizeof(int).

Para responder la pregunta publicada en el comentario anterior, intente algo como esto:

unsigned short int x = 65529U;
short int y = (short int)x;

printf("%d\n", y);

o

unsigned short int x = 65529U;
short int y = 0;

memcpy(&y, &x, sizeof(short int);
printf("%d\n", y);

Dado que la conversión de valores sin firmar se usa para representar números positivos para convertirlo, se puede hacer estableciendo el bit más significativo en 0. Por lo tanto, un programa no interpretará eso como valor del complemento de dos. Una advertencia es que esto perderá información para números que sean casi máximos del tipo sin firmar.

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top