C中联合的初始化

Initialization of a union in C

我遇到了这个 objective 关于 C 编程语言的问题。以下代码的输出应该是 0 2,但我不明白为什么。

请说明初始化过程。这是代码:

#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;
}

为联合分配的内存是联合中最大类型的大小,在本例中为int。假设您系统上 int 的大小是 2 个字节,那么

512 将是 0x200.

代表看起来像:

0000 0010 0000 0000
|        |         |
------------------- 
Byte 1     Byte 0

所以第一个字节是0,第二个字节是2。(在小端系统上)

char 在所有系统上都是一个字节。

所以访问 z.y[0]z.y[1] 是按字节访问。

z.y[0] = 0000 0000 = 0
z.y[1] = 0000 0010 = 2

我只是告诉你内存是如何分配的,值是 stored.You 需要考虑以下几点,因为输出取决于它们。

注意事项:

  1. 输出完全取决于系统。
  2. endianesssizeof(int) 很重要,这会因系统而异。

PS: union中两个成员占用的内存是一样的

对于自动(非静态)成员,初始化与赋值相同:

union a z;
z.x = 512;

并集的大小是由容纳它的单个元素的最大大小导出的。所以,这里是 int 的大小。

假设是4bytes/int和1bytes/char,我们可以说:sizeof union a = 4 bytes.

现在,让我们看看它实际上是如何存储在内存中的:

例如,联合实例 a 存储在 2000-2003:

  • 2000 -> int x, y[0]

  • 的最后(第 4 个/最低有效/最右边)字节
  • 2001 -> int x, y[1]

  • 的第 3 个字节
  • 2002 -> int x

  • 的第二个字节
  • 2003 -> int x 的第一个字节(最高有效位)

现在,当你说 z=512 时:

因为 z = 0x00000200,

  • M[2000] = 0x00

  • M[2001] = 0x02

  • M[2002] = 0x00

  • M[2003] = 0x00

所以,当你打印 y[0] 和 y[1] 时,它会打印数据 M[2000] 和 M[2001],分别是十进制的 0 和 2。

我将假设您使用小端系统,其中 sizeof int4 bytes (32 bits) 和 sizeof a char1 byte (8 bits),其中整数以二进制补码形式表示。 Aunion只有最大成员的大小,所有成员都指向这块内存。

现在,您正在向此内存写入一个整数值 512

512 的二进制是 1000000000.

或 32 位二进制补码形式:

00000000 00000000 00000010 00000000.

现在将其转换为小端表示法,您将得到:

00000000 00000010 00000000 00000000
|______| |______|
   |         |
  y[0]      y[1]

现在看看当你使用 char 数组的索引访问它时会发生什么。

因此,y[0]000000000

y[1]000000102.

标准说

6.2.5 类型:

A union type describes an overlapping nonempty set of member objects, each of which has an optionally specified name and possibly distinct type.

编译器只为最大的成员分配足够的 space,这些成员在此 space 中相互重叠。在您的情况下,内存分配给 int 数据类型(假设 4 字节)。行

union a z = {512};

将初始化 union z 的第一个成员,即 x 变为 512。在二进制中,它在 32 位计算机上表示为 0000 0000 0000 0000 0000 0010 0000 0000

对此的内存表示将取决于机器架构。在 32 位机器上,它要么像(将最低有效字节存储在最小地址中-- Little Endian

Address     Value
0x1000      0000 0000
0x1001      0000 0010
0x1002      0000 0000 
0x1003      0000 0000

或类似(将最高有效字节存储在最小地址中——Big Endian

Address     Value
0x1000      0000 0000
0x1001      0000 0000
0x1002      0000 0010 
0x1003      0000 0000

z.y[0] 将访问地址 0x1000 的内容,z.y[1] 将访问地址 0x1001 的内容,这些内容将取决于上述表示。
看来你的机器支持 Little Endian 表示,因此 z.y[0] = 0z.y[1] = 2 输出将是 0 2.

但是,您应该注意 第 6.5.2.3 节的脚注 95 指出

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.