#include <stdio.h> int main() { typedef union{ int a ; char c; float f; } myu; myu sam; sam.a = 10; sam.f=(float)5.99; sam.c= 'H'; printf("%d\n %c\n %f\n",sam.a,sam.c,sam.f); return 0; }Producción
1086303816
H
5.990025
¿Cómo es que el valor del entero ha cambiado tan drásticamente mientras que el flotante es casi el mismo?
Todos los campos de una union comparten la misma dirección de memoria inicial. Esto significa que escribir en un miembro sobrescribirá el contenido de otro.
Cuando escribe un miembro y luego lee un miembro diferente, la representación del miembro escrito (es decir, cómo se presenta en la memoria) se reinterpreta como la representación del miembro leído. Los tipos enteros y de punto flotante tienen representaciones muy diferentes, por lo que tiene sentido que la lectura de un float como si fuera un int puede variar mucho.
Las cosas se complican aún más si los dos tipos no son del mismo tamaño. Si se escribe un campo más pequeño y se lee un campo más grande, es posible que los bytes sobrantes no se hayan inicializado.
En su ejemplo, primero escribe el valor 10 en el miembro int . Luego escribe el valor 5.99 en el miembro float . Suponiendo que tanto int como float tienen 4 bytes de longitud, todos los bytes utilizados por el miembro int se sobrescriben con el miembro float .
Cuando cambia el miembro char , esto solo cambia el primer byte. Suponiendo que un float se representa en little-endian IEEE754, esto cambia solo el byte de orden inferior de la mantisa, por lo que solo se ven afectados los dígitos más a la derecha.
Prueba esto. En lugar de usar printf (que principalmente generará sin sentido), muestre la memoria sin procesar después de cada modificación.
El siguiente código asume que int y float son tipos de 32 bits y que su compilador no agrega bytes de relleno en esta unión.
#include <string.h> #include <stdio.h> #include <assert.h> void showmemory(void* myu) { unsigned char memory[4]; memcpy(memory, myu, 4); for (int i = 0; i < 4; i++) { printf("%02x ", memory[i]); } printf("\n"); } int main() { typedef union { int a; char c; float f; } myu; assert(sizeof(myu) == 4); // assume size of the union is 4 bytes myu sam; sam.a = 10; showmemory(&sam); sam.f = (float)5.99; showmemory(&sam); sam.c = 'H'; showmemory(&sam); }Salida posible en un sistema little endian:
0a 00 00 00 // 0a is 10 in hexadecimal 14 ae bf 40 // 5.99 in float 48 ae bf 40 // 48 is 'H'¿Cómo es que el valor del entero ha cambiado tan drásticamente mientras que el flotante es casi el mismo?
Eso es solo una coincidencia. Su unión se almacenará en 4 bytes. Cuando asigna el campo "a" a 10, la representación binaria de la unión es 0x0000000A. Y luego, cuando asigna el campo f a 5.99, se convierte en 0x40bfae14. Finalmente, configura la c en 'H' (0x48 en hexadecimal), sobrescribirá el primer byte, que corresponde a la mantisa del valor flotante. Por lo tanto, la parte flotante cambia ligeramente. Para obtener más información sobre la codificación de coma flotante, puede consultar este práctico sitio web.