今天在做编译器测试的时候遇到了一个关于union的赋值问题,在这里分享给大家
先写两个代码的例子
#include <stdio.h>
int main() {
// 对 union 做初始化,不指定成员
union _uni {
int a;
float b;
} _u = {0x34};
// 给出这这两个数据类型的内存表示
float f = 0x34;
int i = 0x34;
// 打印内存表示
printf("%x\n", *(int*)&(_u.a));
printf("%x\n", *(int*)&(_u.b));
printf("%x\n", *(int*)&(f));
printf("%x\n", *(int*)&(i));
return 0;
}
输出:
34
34
42500000
34
#include <stdio.h>
int main() {
// 在这里调换了成员顺序
union _uni {
float b;
int a;
} _u = {0x34};
float f = 0x34;
int i = 0x34;
printf("%x\n", *(int*)&(_u.a));
printf("%x\n", *(int*)&(_u.b));
printf("%x\n", *(int*)&(f));
printf("%x\n", *(int*)&(i));
return 0;
}
输出:
42500000
42500000
42500000
34
-
通过指针转换为 int*, printf 可以输出内部 4B 内存十六进制表示
-
问题出现在 union 的赋值方式,存入0x34是按照 float 去存储还是 int 呢?实验结果看来是按照成员的顺序,按照排在前面的成员进行优先存储。
-
42500000 表示什么意思呢?0x34 = 3*16+4 = 52,float 的内存表示是 1 符号位 8 指数位 23 尾数位,而 52 = 0b110100 = 1.101 * 2^5 ,符号位为 0,指数位为 127(偏移量) + 5 = 128 +4 = 1000 0100,尾数为 101,所以二进制表示应该为 0b0100 0010 0101 0000 0000 0000 0000 0000 = 0x42500000
-
C 的规范里面怎么规定的呢?这个行为是编译器指定的(Implementation-defined behavior),还是C语言规范中指定的呢(Well-defined behavior)?答案是C语言规范中已经规定好了,在C99规范中可以找到明确规定,是Well-defined Behavior
When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union
当没有明确指定成员的时候,这些对象的子对象(成员)会根据他们的类型按照一定顺序进行初始化:array 按照下标顺序,struct 按照声明顺序,union 用第一个有名字的成员进行初始化
综上,union 类型在进行不指定成员的初始化的时候,是按照第一个有名字成员的内存表示进行储存的,其余的类型会按照这个内存表示进行解码。