我最近正在学习工会,即使在阅读了很多相关内容之后也会感到困惑。
#include<stdio.h>
union test
{
int x;
char arr[4];
int y;
};
int main()
{
union test t;
t.x = 0;
t.arr[1] = 'G';
printf("%s\n", t.arr);
printf("%d\n",t.x);
return 0;
}
我的理解是:
由于x
和arr[4]
共享相同的内存,因此当我们设置x = 0
时,arr的所有字符都设置为0
。 0
是'\0'
的ASCII值。当我们执行&#34; t.arr[1] = 'G'
&#34;时,arr[]
变为&#34; \0G\0\0
&#34;。当我们使用"%s"
打印字符串时,printf函数从第一个字符开始并保持打印直到找到\0
。由于第一个字符本身为\0
,因此不会打印任何内容。
我没有得到的是第二份printf声明
现在arr[]
是&#34; \0G\0\0
&#34; ,x
和y
共享相同的位置。
所以我认为x
是以下
00000000 01000111 00000000 00000000
(&#34; \0G\0\0
&#34;)
所以t.x应该打印4653056
。
但它的打印是18176
。
我哪里错了?
这在技术上是不确定的还是由于一些愚蠢的错误或者我错过了一些概念?
答案 0 :(得分:8)
Union的所有成员将分享same common memory
。假设union的起始地址是0x100。
当你写t.x = 0;
时,整个4个字节的初始化为零,为
-------------------------------------------------
| 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000 |
-------------------------------------------------
0x104 0x103 0x102 0x101 0x100
x,arr,y
当你写作t.arr[1] = 'G';
时,arr [1]将覆盖&#39; G&#39; ascii值,看起来像
-------------------------------------------------
| 0000 0000 | 0000 0000 | 0100 0111 | 0000 0000 |
-------------------------------------------------
0x104 0x103 0x102 0x101 0x100
现在计算这个值为18176。
答案 1 :(得分:1)
tl; dr:endianity!
当printf从你的工会指向的内存中读取数据时,它会查看系统的字节顺序并读取存储在little endian中的数据。 因此,不是打印存储在内存中的数据(0x00470000),而是获得数字0x00004700,这与18176相关,就像你得到的那样。
代码示例:
#include<stdio.h>
union test
{
int x;
char arr[4];
int y;
};
int main()
{
union test t;
t.x = 0;
t.arr[1] = 'G';
printf("%s\n", t.arr);
printf("%d\n",t.x); // prints 18176
t.x = 0;
t.arr[2] = 'G';
printf("%d\n",t.x); // prints 4653056
return 0;
}
或者在Python中:
import struct
union_data = "\x00G\x00\x00"
print struct.unpack("<I", a)[0] # This is little endian. Prints 18176
print struct.nupack(">I", a)[0] # This is big endian. Prints 4653056
奖金!您还可以使用函数htonl
将读取为小端的整数转换为大端。 See more at the docs