2010-03-04 24 views
8

Supongamos defino una unión como esta:Comprender el contenido de la memoria de una unión

#include <stdio.h> 

int main() { 
    union u { 
     int i; 
     float f; 
    }; 
    union u tst; 
    tst.f = 23.45; 

    printf("%d\n", tst.i); 

    return 0; 
} 

¿Puede alguien decirme lo que la memoria donde se almacena tst se parecerá?

Estoy tratando de entender la salida 1102813594 que produce este programa.

Respuesta

12

Depende de la implementación (compilador, sistema operativo, etc.) pero puede usar el depurador para ver los contenidos de la memoria si lo desea.

Por ejemplo, en mi MSVC 2008:

0x00415748 9a 99 bb 41 

es el contenido de memoria. Lea desde LSB en el lado izquierdo (Intel, máquina little-endian), esto es 0x41bb999a o en realidad 1102813594.

En general, sin embargo, el entero y el flotante se almacenan en los mismos bytes. Dependiendo de cómo acceda a la unión, obtendrá el número entero o coma flotante de esos bytes. El tamaño del espacio de memoria, nuevamente, depende de la implementación, aunque generalmente es el más grande de sus componentes alineado a un límite fijo.

¿Por qué es el valor tal como está en su (o el mío) caso? Debería leer acerca de la representación de números en coma flotante para eso (consulte ieee 754)

+0

Hmm, en lugar de "el mayor de sus componentes", probablemente se refiera a la más restrictiva. –

+4

@rogue: según el estándar: "El tamaño de una unión es suficiente para contener el mayor de sus miembros" –

+0

iirc, de k & r, "Aunque las máquinas varían, para cada máquina hay un tipo más restrictivo: si el más tipo restrictivo se puede almacenar en una dirección particular, todos los otros tipos pueden ser también ". - pero supongo que tienes razón, ya que el estándar siempre es correcto, + 1 en ambos sentidos. –

5

El resultado depende de la implementación del compilador, pero para la mayoría de los compiladores x86, float e int tendrán el mismo tamaño. Wikipedia tiene un diagrama bastante bueno del diseño de un flotador de 32 bits http://en.wikipedia.org/wiki/Single_precision_floating-point_format, que puede ayudar a explicar 1102813594.

Si imprime el int como un valor hexadecimal, será más fácil averiguarlo.

printf("%x\n", tst.i); 
4

Con una unión, ambas variables se almacenan comenzando en la misma ubicación de memoria. Un flotador se almacena en un formato IEEE (no puede recordar el número estándar, puede buscarlo [editar: como lo señalaron otros, IEEE 754]). Pero, será un complemento de dos normalizado (la mantisa siempre está entre 0 y 10, el exponente puede ser cualquier cosa) número de coma flotante.

está tomando los primeros 4 bytes de ese número (de nuevo, puede buscar qué bits van donde en los 16 o 32 bits que ocupa un flotador, no puede recordar). Entonces básicamente no significa nada y no es útil como int. Es decir, a menos que sepa por qué querría hacer algo así, pero por lo general, un combo float e int no es muy útil.

Y, no, no creo que se haya definido su implementación. Creo que el estándar dicta en qué formato está un flotante.

+3

C++ estándar no impone la representación de FP compatible con IEEE-754, pero lo alienta con el miembro std :: numeric_limits :: is_iec559 (equivalente a IEEE-754). Además, los números desnormalizados también son válidos. –

+0

Es probable que recuerdes mejor que yo. Gracias. ¿Es esto lo mismo para C? –

3

En unión, los miembros compartirán la misma memoria. para que podamos obtener el valor flotante como valor entero.

El formato del número flotante será diferente del almacenamiento entero. para que podamos entender la diferencia usando la unión.

Por ejemplo: Si almaceno el valor de 12 enteros en (32 bits). podemos obtener este valor de 12 como formato de coma flotante.

Se almacenará como firmado (1 bit), exponente (8 bits) y precisión significativa (23 bits).

1

Escribí un pequeño programa que muestra lo que sucede cuando se conserva el patrón de bits de un flotador de 32 bits en un entero de 32 bits. Le da exactamente la misma salida que está experimentando:

#include <iostream> 

int main() 
{ 
    float f = 23.45; 
    int x = *reinterpret_cast<int*>(&f); 

    std::cout << x; // 1102813594 
} 
Cuestiones relacionadas