首先 union 和 struct 不同的一点就是一个 Union 中的所有成员都是共用一个内存空间的,大小由成员中要求空间最大的来决定。也就是说你给其中一个成员赋值以后,其他成员就都是这个值,只不过因为成员类型不同导致这个值的表现不同。现在看这个程序,定义了一个 union
union {
int i[2];
long k;
char c[4];
} t;
所有成员的大小分别如下:
i: 2 * sizeof(int) = 2 * 4 = 8
k: sizeof(long) = 4
c: 4 * sizeof(char) = 4 * 1 = 4
可见最大的是那个整数数组 i,占 8 个字节,所以这个 union t 的大小就是 8。
然后,你通过
s->i[0] = 0x39;
s->i[1] = 0x38;
给 i 数组赋值,也就是 i 的前四个字节存储的是十六进制整数 0×39,后四个字节存储的是十六进制整数 0×38。因为 union 的所有成员共享一个内存空间,所以 k 和 c 的值同 i 的值是一样的。然而 k 和 c 只有四个字节的长度,所以后面的 0×38 就被忽略了,因为 0×39 已经占据了前 4 个字节。也就是说,现在 k 的值是 0×39,c 的值也是 0×39。
然后看你的输出
printf("%1x\n", s->k);
printf("%c\n", s->c[0]);
你要将 k 以十六进制整数的方式输出到屏幕上,c 以字符的方式输出到屏幕上,也就是将 0×39 分别以十六进制整数和字符的方式输出到屏幕上。0×39 代表的十六进制整数当然还是 39,而 0×39 所代表的字符是 '9'(注意这个 9 是字符而不是整数),这个你可以查一下 ASCII 表看看十六进制的 39 对应的字符是不是 '9'。所以输出的结果自然就是 39 和 9 了。
下图为 ASCII 表的一部分,可见十进制的 57,也就是十六进制的 39 所代表的字符是 '9'。
为了更好理解 union,你也可以使用
printf("%c\n", s->c[4]);
打印出来 c[4],看看结果是不是 '8'。这是因为虽然定义 c 的长度是 4,但由于整个 union 在内存中的长度有 8,所以 c[4] 到 c[7] 这四个字节在内存中仍然是存在的,而它的值就是刚才存在 i 中的第二个整数 0×38。然后因为十六进制的 38 对应的字符是 '8'(见上图),所以打印出 c[4] 的值是 8。
一点题外话是,包含系统头文件时请使用
#include
而不是
#include "stdio.h"
这样会稍微提高执行效率。还有就是请让 main 函数返回整数 0 而不是 void,返回 void 是不规范的写法。
int和long一样都是4个字节,所以s->k取的就是i[0]的值。
printf("%c\n",s->c[0]) 算出是9和大小端有关,只有小端才是9。就是ANSI char '9',换成十六进制就是39。char[0]取了i[0]的低八位。