C中联合的内存分配
Memory allocation for union in C
我最近在研究 union,即使阅读了很多关于它的内容,最终还是感到困惑。
#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
是 '[=16=]'
的 ASCII 值。当我们执行“t.arr[1] = 'G'
”时,arr[]
变为“[=19=]G[=19=][=19=]
”。当我们使用 "%s"
打印字符串时,printf 函数从第一个字符开始打印,直到找到 [=21=]
。由于第一个字符本身是 [=21=]
,因此不会打印任何内容。
我没有得到的是第二个 printf 语句
现在由于 arr[]
是“[=19=]G[=19=][=19=]
”,所以与 x
和 y
共享相同的位置。
所以我认为 x
是以下
00000000 01000111 00000000 00000000
("[=19=]G[=19=][=19=]
")
所以 t.x 应该打印 4653056
。
但是它打印的是 18176
.
我哪里错了?
这在技术上是未定义的还是由于一些愚蠢的错误或者我错过了一些概念??
tl;dr:字节顺序!
当 printf 从你的 union 指向的内存中读取数据时,它会查看你系统的字节序并读取存储在小端的数据。
因此,它不是打印存储在内存 (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.
联盟所有成员将共享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] 将被 'G' ascii 值覆盖,看起来像
-------------------------------------------------
| 0000 0000 | 0000 0000 | 0100 0111 | 0000 0000 |
-------------------------------------------------
0x104 0x103 0x102 0x101 0x100
现在计算这个值是 18176。
我最近在研究 union,即使阅读了很多关于它的内容,最终还是感到困惑。
#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
是 '[=16=]'
的 ASCII 值。当我们执行“t.arr[1] = 'G'
”时,arr[]
变为“[=19=]G[=19=][=19=]
”。当我们使用 "%s"
打印字符串时,printf 函数从第一个字符开始打印,直到找到 [=21=]
。由于第一个字符本身是 [=21=]
,因此不会打印任何内容。
我没有得到的是第二个 printf 语句
现在由于 arr[]
是“[=19=]G[=19=][=19=]
”,所以与 x
和 y
共享相同的位置。
所以我认为 x
是以下
00000000 01000111 00000000 00000000
("[=19=]G[=19=][=19=]
")
所以 t.x 应该打印 4653056
。
但是它打印的是 18176
.
我哪里错了?
这在技术上是未定义的还是由于一些愚蠢的错误或者我错过了一些概念??
tl;dr:字节顺序!
当 printf 从你的 union 指向的内存中读取数据时,它会查看你系统的字节序并读取存储在小端的数据。 因此,它不是打印存储在内存 (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.
联盟所有成员将共享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] 将被 'G' ascii 值覆盖,看起来像
-------------------------------------------------
| 0000 0000 | 0000 0000 | 0100 0111 | 0000 0000 |
-------------------------------------------------
0x104 0x103 0x102 0x101 0x100
现在计算这个值是 18176。