Encontré esta pregunta objetiva sobre el lenguaje de programación C. Se supone que el resultado del siguiente código es 0 2
, pero no entiendo por qué.
Explique el proceso de inicialización. Aquí está el código:
#include <stdio.h> int main() { union a { int x; char y[2]; }; union az = {512}; printf("\n%d %d", zy[0], zy[1]); return 0; }
Voy a suponer que usa un sistema little endian donde el tamaño de un int
es 4 bytes (32 bits)
y el tamaño de un char
es 1 byte (8 bits)
, y uno en el que los números enteros se representan en forma de complemento a dos. Una union
solo tiene el tamaño de su miembro más grande, y todos los miembros apuntan a este recuerdo exacto.
Ahora, está escribiendo en esta memoria un valor entero de 512
.
512 en binario es 1000000000
.
o en forma de complemento a dos de 32 bits:
00000000 00000000 00000010 00000000
.
Ahora convierta esto a su representación little endian y obtendrá:
00000000 00000010 00000000 00000000 |______| |______| | | y[0] y[1]
Ahora vea lo anterior, lo que sucede cuando accede a él usando índices de una char
de caracteres.
Por lo tanto, y[0]
es 00000000
, que es 0
,
y y[1]
es 00000010
que es 2
.
La memoria asignada para la unión es del tamaño del tipo más grande de la unión, que es int
en este caso. Digamos que el tamaño de int
en su sistema es de 2 bytes, entonces
512
será 0x200
.
La representación se parece a:
0000 0010 0000 0000 | | | ------------------- Byte 1 Byte 0
Entonces, el primer byte es 0
y el segundo es 2
(En sistemas Little Endian)
char
es un byte en todos los sistemas.
Entonces, el acceso zy[0]
y zy[1]
es un acceso por byte.
zy[0] = 0000 0000 = 0 zy[1] = 0000 0010 = 2
Solo le estoy dando cómo se asigna la memoria y cómo se almacena el valor. Debe considerar los puntos a continuación, ya que la salida depende de ellos.
Puntos a tener en cuenta:
sizeof(int)
son importantes, que variarán entre los sistemas.PD: La memoria que ocupan ambos miembros es la misma en unión.
La norma dice que
Un tipo de unión describe un conjunto superpuesto no vacío de objetos miembro , cada uno de los cuales tiene un nombre especificado opcionalmente y posiblemente un tipo distinto.
El compilador asigna solo el espacio suficiente para el miembro más grande, que se superponen entre sí dentro de este espacio . En su caso, la memoria se asigna para el tipo de datos int
(suponiendo 4 bytes). La línea
union az = {512};
inicializará el primer miembro de la unión z
, es decir x
se convierte en 512
. En binario se representa como 0000 0000 0000 0000 0000 0010 0000 0000
en una máquina 32.
La representación de memoria para esto dependería de la arquitectura de la máquina. En una máquina de 32 bits, será como (almacene el byte menos significativo en la dirección más pequeña: Little Endian )
Address Value 0x1000 0000 0000 0x1001 0000 0010 0x1002 0000 0000 0x1003 0000 0000
o similar (almacene el byte más significativo en la dirección más pequeña: Big Endian )
Address Value 0x1000 0000 0000 0x1001 0000 0000 0x1002 0000 0010 0x1003 0000 0000
zy[0]
accederá al contenido en la dirección 0x1000
y zy[1]
accederá al contenido en la dirección 0x1001
y ese contenido dependerá de la representación anterior.
Parece que su máquina admite la representación de Little Endian y, por lo tanto zy[0] = 0
y zy[1] = 2
y la salida sería 0 2
.
Pero, debe tener en cuenta que la nota al pie 95 de la sección 6.5.2.3 establece que
Si el miembro utilizado para leer el contenido de un objeto de unión no es el mismo que el último miembro utilizado para almacenar un valor en el objeto , la parte correspondiente de la representación de objeto del valor se reinterpreta como una representación de objeto en el nuevo tipo como descrito en 6.2.6 (un proceso a veces llamado ''juego de palabras''). Esto podría ser una representación trampa .