enum c
Inicialización de una unión en C (5)
El tamaño de la unión se deriva del tamaño máximo para contener un solo elemento de la misma. Por lo tanto, aquí está el tamaño de int.
Suponiendo que sea de 4 bytes / int y 1 bytes / char, podemos decir: sizeof union a = 4 bytes
.
Ahora, veamos cómo se almacena realmente en la memoria:
Por ejemplo, una instancia de la unión, a
, se almacena en 2000-2003:
2000 -> último (4to / menos significativo / extremo derecho) de int x, y [0]
2001 -> 3er byte de int x, y [1]
2002 -> 2º byte de int x
2003 -> 1er byte de int x (el más significativo)
Ahora, cuando dices z = 512:
ya que z = 0x00000200,
M [2000] = 0x00
M [2001] = 0x02
M [2002] = 0x00
M [2003] = 0x00
Entonces, cuando imprima, y [0] y y [1], imprimirá los datos M [2000] y M [2001] que son 0 y 2 en decimal, respectivamente.
Me encontré con esta pregunta objetiva en el lenguaje de programación C. La salida para el siguiente código se supone que es 0 2
, pero no entiendo por qué.
Por favor explique el proceso de inicialización. Aquí está el código:
#include <stdio.h>
int main()
{
union a
{
int x;
char y[2];
};
union a z = {512};
printf("/n%d %d", z.y[0], z.y[1]);
return 0;
}
La memoria asignada para la unión es el tamaño del tipo más grande en 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
.
Represenataion se ve como:
0000 0010 0000 0000
| | |
-------------------
Byte 1 Byte 0
Así que el primer byte es 0
y el segundo es 2
(En sistemas Little Endian)
char
es un byte en todos los sistemas.
Por lo tanto, el acceso zy[0]
y zy[1]
es por acceso de byte.
z.y[0] = 0000 0000 = 0
z.y[1] = 0000 0010 = 2
Solo le presento cómo se asigna la memoria y se almacena el valor. Debe considerar los siguientes puntos ya que la salida depende de ellos.
Puntos a tener en cuenta:
- La salida es completamente dependiente del sistema.
- La endianess y el
sizeof(int)
importantes, los cuales variarán según los sistemas.
PD: La memoria ocupada por ambos miembros es la misma en unión.
La norma dice que
6.2.5 Tipos:
Un tipo de unión describe un conjunto no vacío superpuesto de objetos miembros , cada uno de los cuales tiene un nombre opcionalmente especificado y posiblemente un tipo distinto.
El compilador asigna solo el espacio suficiente para el mayor de los miembros, que se superponen entre sí dentro de este espacio . En su caso, la memoria se asigna para el tipo de datos int
(asumiendo 4 bytes). La línea
union a z = {512};
Inicializará el primer miembro de la unión z
, es decir, x
convierte en 512
. En binario se representa como 0000 0000 0000 0000 0000 0010 0000 0000
en una máquina 32.
La representación en 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 como (almacena 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 addrees 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
.
Sin embargo, debe tener en cuenta que la nota de pie de página 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 utilizado para almacenar un valor en el objeto , la parte apropiada de la representación del objeto del valor se reinterpreta como una representación del objeto en el nuevo tipo como descrito en 6.2.6 (un proceso a veces llamado "tipo punning"). Esto podría ser una representación trampa .
Para los miembros automáticos (no estáticos), la inicialización es idéntica a la asignación:
union a z;
z.x = 512;
Voy a suponer que usas un sistema little endian donde sizeof int
es de 4 bytes (32 bits)
y sizeof a char
es de 1 byte (8 bits)
, y uno en el que los 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 esta pieza exacta de memoria.
Ahora, estás 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 pequeña representación endiana y obtendrá:
00000000 00000010 00000000 00000000
|______| |______|
| |
y[0] y[1]
Ahora vea lo anterior que sucede cuando accede a él usando índices de una matriz de caracteres.
Por lo tanto, y[0]
es 00000000
que es 0
,
y y[1]
es 00000010
que es 2
.