我有一个三个整数的数组的联合类型(每个4个字节),一个浮点数(4个字节),一个双精度数(8个字节)和一个字符(1个字节)。
如果我为每个三个整数元素分配0x31313131然后打印了union的字符,我会得到数字1.为什么?
我不明白输出我知道3 0x31313131的位是 001100010011000100110001001100010011000100110001001100010011000100110001001100010011000100110001
答案 0 :(得分:3)
因为'1'== 0x31。您将其打印为字符,而不是整数。
因为它是一个联合所有的int和char共享相同的内存位置(在这种情况下float和double无关紧要)。因此,将0x31313131分配给int 确实会影响char值 - 没有什么比这更令人困惑。
答案 1 :(得分:1)
工会的每个成员都有相同的起始地址;不同的成员可能有不同的大小。整个联合的大小至少任何成员的最大大小;最后可能会有额外的填充以满足对齐要求。
将值0x31313131
存储在union对象的前三个int
大小的内存区域中。 0x31313131
是4个字节,每个字节的值为0x31
。
然后通过访问字符成员读取第一个字节(来自偏移0)。该字节的值为0x31
,恰好是ASCII和类似字符集中字符'1'
的编码。 (如果您在基于EBCDIC的系统上运行程序,则会看到不同的结果。)
由于您没有向我们展示任何实际的源代码,我将根据您的描述:
#include <stdio.h>
#include <string.h>
void hex_dump(char *name, void *base, size_t size) {
unsigned char *arr = base;
char c = ' ';
printf("%-8s : ", name);
for (size_t i = 0; i < size; i ++) {
printf("%02x", arr[i]);
if (i < size - 1) {
putchar(' ');
}
else {
putchar('\n');
}
}
}
int main(void) {
union u {
int arr[3];
float f;
double d;
char c;
};
union u obj;
memset(&obj, 0xff, sizeof obj);
obj.arr[0] = 0x31323334;
obj.arr[1] = 0x35363738;
obj.arr[2] = 0x393a3b3c;
hex_dump("obj", &obj, sizeof obj);
hex_dump("obj.arr", &obj.arr, sizeof obj.arr);
hex_dump("obj.f", &obj.f, sizeof obj.f);
hex_dump("obj.d", &obj.d, sizeof obj.d);
hex_dump("obj.c", &obj.c, sizeof obj.c);
printf("obj.c = %d = 0x%x = '%c'\n",
(int)obj.c, (unsigned)obj.c, obj.c);
return 0;
}
hex_dump
函数通过以十六进制显示每个字节的值来转储任何对象的原始表示,而不管其类型如何。
我首先使用0xff
字节填充union对象。然后,如您所述,我初始化int[3]
成员arr
的每个元素 - 但为了更清楚地显示正在发生的事情,我为每个字节使用不同的值。
我在一个系统上获得的输出(恰好是little-endian)是:
obj : 34 33 32 31 38 37 36 35 3c 3b 3a 39 ff ff ff ff
obj.arr : 34 33 32 31 38 37 36 35 3c 3b 3a 39
obj.f : 34 33 32 31
obj.d : 34 33 32 31 38 37 36 35
obj.c : 34
obj.c = 52 = 0x34 = '4'
如您所见,每个成员的初始字节彼此一致,因为它们存储在同一个地方。尾随ff
字节不受向arr
赋值的影响(这不是唯一有效的行为;标准表示它们采用未指定的值)。由于系统是little-endian,因此每个int
值的高位字节存储在内存中的最低位置。
big-endian系统的输出是:
obj : 31 32 33 34 35 36 37 38 39 3a 3b 3c ff ff ff ff
obj.arr : 31 32 33 34 35 36 37 38 39 3a 3b 3c
obj.f : 31 32 33 34
obj.d : 31 32 33 34 35 36 37 38
obj.c : 31
obj.c = 49 = 0x31 = '1'
如您所见,每个int
的高位字节位于内存中的最低位置。
在所有情况下,obj.c
的值是obj.arr[0]
的第一个字节 - 它将是高阶或低阶字节,具体取决于关于字节序。
有一种很多方式可以在不同的系统中发生变化。 int
,float
和double
的尺寸可能会有所不同。表示浮点数的方式可以变化(尽管此示例未显示)。甚至一个字节中的位数也可以变化;它至少是8,但可能更大。 (在你可能遇到的任何系统上都是8)。标准允许整数表示中的填充位;在我展示的例子中没有。