float c casting truncate

c - float to int java



Cuando un int se convierte en corto y truncado, ¿cómo se determina el nuevo valor? (6)

De acuerdo con el estándar ISO C, cuando se convierte un entero en un tipo con signo y el valor está fuera del rango del tipo de destino, el resultado está definido por la implementación. (O se puede generar una señal definida por la implementación, pero no conozco ningún compilador que haga esto).

En la práctica, el comportamiento más común es que los bits de orden superior se descartan. Entonces, asumiendo que int es de 32 bits y short es de 16 bits, la conversión del valor 0x1248642 probablemente producirá un patrón de bits que se parece a 0x8642 . Y suponiendo una representación de complemento a dos para los tipos firmados (que se utiliza en casi todos los sistemas), el bit de orden superior es el bit de signo, por lo que el valor numérico del resultado será -31166 .

int y = sx;

Esto también implica una conversión implícita, de short a int . Dado que se garantiza que el rango de int cubre al menos todo el rango de short , el valor no se modifica. (Dado que, en su ejemplo, el valor de sx es negativo, es probable que este cambio de representación implique una extensión de signo , propagando el bit de signo 1 a los 16 bits de alto orden del resultado).

Como indiqué, ninguno de estos detalles es requerido por el estándar de idioma. Si realmente desea truncar los valores a un tipo más estrecho, probablemente sea mejor usar tipos sin signo (que tienen un comportamiento de envoltura especificada por el idioma) y quizás operaciones de enmascaramiento explícitas, como esta:

unsigned int x = 0x1248642; unsigned short sx = x & 0xFFFF;

Si tiene una cantidad de 32 bits que desea incluir en una variable de 16 bits, lo primero que debe hacer es decidir cómo desea que se comporte su código si el valor no se ajusta. Una vez que hayas decidido eso, puedes averiguar cómo escribir un código C que haga lo que quieres. A veces, el truncamiento es lo que usted desea, en cuyo caso su tarea será fácil, especialmente si utiliza tipos sin firma. A veces, un valor fuera de rango es un error, en cuyo caso debe verificarlo y decidir cómo manejar el error. A veces, es posible que desee que el valor se sature, en lugar de truncar, por lo que deberá escribir código para hacerlo.

Saber cómo funcionan las conversiones en C es importante, pero si comienza con esa pregunta, podría estar abordando su problema desde la dirección equivocada.

¿Alguien puede aclarar qué sucede cuando se lanza un entero a un short en C? Estoy usando Raspberry Pi, así que soy consciente de que un int es de 32 bits, y por lo tanto, un short debe ser de 16 bits.

Digamos que uso el siguiente código C, por ejemplo:

int x = 0x1248642; short sx = (short)x; int y = sx;

Entiendo que x estaría truncada, pero ¿puede alguien explicar cómo exactamente? ¿Se utilizan turnos? ¿Cómo se trunca exactamente un número de 32 bits a 16 bits?


El truncamiento ocurre en los registros de la CPU. Estos tienen diferentes tamaños: 8/16/32/64 bits. Ahora, puedes imaginar un registro como:

<--rax----------------------------------------------------------------> (64-bit) <--eax----------------------------> (32-bit) <--ax-----------> (16-bit) <--ah--> <--al--> (8-bit high & low) 01100011 01100001 01110010 01110010 01111001 00100000 01101111 01101110

Primero se le da a x el valor de 32 bits 0x1248642 . En la memoria *, se verá como:

----------------------------- | 01 | 24 | 86 | 42 | ----------------------------- 31..24 23..16 15..8 7..0

Ahora, el compilador carga x en un registro. Desde allí, simplemente puede cargar los 16 bits menos significativos (a saber, ax ) y almacenarlos en sx .

* El endianismo no se tiene en cuenta por simplicidad.


El valor de 32 bits se trunca a 16 bits de la misma manera que se cortaría un pan de plátano de 32 cm de largo si se lo introduce en una bandeja de 16 cm de largo. La mitad de eso encajaría y aún sería un pan de plátano, y el resto se habrá "ido".


Simplemente los 16 bits altos se cortan del entero. Por lo tanto, su corto se convertirá en 0x8642 que en realidad es un número negativo -31166 .


Tal vez deje que el código hable por sí mismo:

#include <stdio.h> #define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d" #define BYTETOBINARY(byte) / ((byte) & 0x80 ? 1 : 0), / ((byte) & 0x40 ? 1 : 0), / ((byte) & 0x20 ? 1 : 0), / ((byte) & 0x10 ? 1 : 0), / ((byte) & 0x08 ? 1 : 0), / ((byte) & 0x04 ? 1 : 0), / ((byte) & 0x02 ? 1 : 0), / ((byte) & 0x01 ? 1 : 0) int main() { int x = 0x1248642; short sx = (short) x; int y = sx; printf("%d/n", x); printf("%hu/n", sx); printf("%d/n", y); printf("x: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"/n", BYTETOBINARY(x>>24), BYTETOBINARY(x>>16), BYTETOBINARY(x>>8), BYTETOBINARY(x)); printf("sx: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"/n", BYTETOBINARY(y>>8), BYTETOBINARY(y)); printf("y: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"/n", BYTETOBINARY(y>>24), BYTETOBINARY(y>>16), BYTETOBINARY(y>>8), BYTETOBINARY(y)); return 0; }

Salida:

19170882 34370 -31166 x: 00000001 00100100 10000110 01000010 sx: 10000110 01000010 y: 11111111 11111111 10000110 01000010

Como puede ver, int -> short produce los 16 bits más bajos, como se esperaba.

Si se short a int obtiene el short con los 16 bits altos establecidos. Sin embargo, sospecho que esto es un comportamiento específico e indefinido de la implementación. Básicamente, estás interpretando 16 bits de memoria como un entero, que lee 16 bits adicionales de cualquier basura que esté allí (o 1 si el compilador es bueno y quiere ayudarte a encontrar errores más rápido).

Creo que debería ser seguro hacer lo siguiente:

int y = 0x0000FFFF & sx;

Obviamente, no recuperarás los bits perdidos, pero esto garantizará que los bits altos estén correctamente puestos a cero.

Si alguien puede verificar el comportamiento de bit corto -> alto con una referencia autorizada, eso sería apreciado.

Nota: Macro binaria adaptada de esta respuesta .


sx valor de sx será el mismo que 2 bytes menos significativos de x , en este caso será 0x8642, que (si se interpreta como un entero con signo de 16 bits) da -31166 en decimal.