2011-11-12 17 views
6

Hoy tengo una pregunta extraña.Unión C++ para representar la memoria de datos frente a la variable escalar C tipo

El código (C++)

#include <iostream> 

union name 
{ 
    int num; 
    float num2; 

}oblong; 


int main(void) 
{ 
    oblong.num2 = 27.881; 

    std::cout << oblong.num << std::endl; 

    return 0; 
} 

El código (C)

#include <stdio.h> 

int main(void) 
{ 
    float num = 27.881; 

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

    return 0; 
} 

La pregunta sindicatos

  1. Como sabemos, C++ pueden hol d más de un tipo de elemento de datos, pero solo un tipo a la vez. Así que, básicamente, el name oblong solo reservará una parte de la memoria que es de 32 bits (porque el tipo más grande en la unión es de 32 bits, int y float) y esta parte podría contener un número entero o flotar.

  2. Así que solo asigno un valor de 27.881 en oblong.num2 (como se puede ver en el código anterior). Pero por curiosidad, accedo a la memoria usando oblong.num que apunta a la misma ubicación de memoria.

  3. Como era de esperar, me dio un valor que no es 27, porque la forma de flotador y número entero representado dentro de una memoria es diferente, por eso cuando uso oblong.num acceder a la parte de memoria que va a tratar esa parte de valor de la memoria como entero e interpretarlo usando la forma de representación entera.

  4. Sé que este fenómeno ocurrirá también en C, es por eso que inicializar una variable de tipo float con un valor y más tarde leí utilizando el %d .So Sólo trato a cabo utilizando el mismo valor 27.881 las cuales se puede véase más arriba. Pero cuando lo ejecuto, sucede algo raro, ese es el valor de lo que obtengo en C es diferente de C++.

  5. ¿Por qué sucede esto? Por lo que sé, los dos valores que obtengo de los dos códigos al final no son valores basura, pero ¿por qué obtengo valores diferentes? También uso el sizeof para verificar el entero y el flotador de C y C++, y ambos son de 32 bits. Entonces, el tamaño de la memoria no es el que causa que esto suceda, entonces, ¿qué es lo que provoca esta diferencia en los valores?

+1

Mismo caso: http://stackoverflow.com/questions/2377733/how-does-this-program-work y esto también: http://stackoverflow.com/questions/2398791/how-is-conversion- of-float-double-to-int-handled-in-printf –

+0

La diferencia no es C versus C++. También puede compilar el segundo ejemplo en C++ y obtener el mismo resultado de C y C++. El primer ejemplo con 'union' necesitaría un pequeño cambio para usar' printf', en lugar de 'std :: cout <<', pero después obtendría los mismos resultados de C y C++ nuevamente. – MSalters

Respuesta

9

En primer lugar, teniendo la cadena equivocada printf() formato es un comportamiento indefinido. Ahora eso dicho, aquí es lo que está sucediendo realmente en su caso:

En vararg funciones tales como printf(), números enteros más pequeños que son promovidos a intint y flota más pequeña que double son promovidos a double.

El resultado es que su 27.881 se está convirtiendo en un doble de 8 bytes, ya que se pasa al printf(). Por lo tanto, la representación binaria ya no es la misma que float.

La cadena de formato %d espera un entero de 4 bytes. Entonces, en efecto, imprimirá los 4 bytes inferiores de la representación de precisión doble de 27.881.(Suponiendo ascendente hacia la izquierda)

* En realidad (suponiendo estricta-FP), que está viendo el fondo 4 bytes de 27.881 después de que se echó a float, y luego promovido a double.

2

En ambos casos, usted encontrará un comportamiento indefinido. Su implementación simplemente hace algo extraño.

+0

Ambos casos? Pensé que solo el segundo printf no está definido. El primero es un volcado con un patrón de bit bien definido que proviene del flotador. (Por lo que tiene sentido es otra pregunta, por supuesto) – Bort

+0

El primer caso es UB porque está accediendo al objeto 'float (27.881)' a través de una expresión de tipo 'int'. Se debe acceder a los objetos a través de una expresión de su propio tipo o mediante (sin signo) 'char []'. La última regla es para que puedas objetos 'memcpy' (en C; C++ restringe' memcpy' a Plain Old Data). – MSalters

Cuestiones relacionadas