我是C语言的新手,我试图了解编译器如何完成内存分配。这是我写的一段代码,用来了解正在发生的事情:
#include<stdio.h>
int main(void){
int x=10;
char y='A';
printf("x: %p \ny: %p\n", &x, &y);
return 0;
}
输出:
x: 0x7fffcc33e10c
y: 0x7fffcc33e10b
Int占用4个字节,而Char占用1个字节。那么这些变量的存储位置又是如何连续的呢?我无法理解这一点。
正如@Rup在下面的注释中建议的那样,我尝试在代码中添加更多整数:
#include<stdio.h>
int main(void){
int x=10;
int m = 11;
int n = 11;
int o = 11;
char y='A';
printf("x: %p \nm: %p\nn: %p\no: %p\ny: %p\n", &x, &m, &n, &o, &y);
return 0;
}
我得到以下输出:
x: 0x7fff825c2e68
m: 0x7fff825c2e6c
n: 0x7fff825c2e70
o: 0x7fff825c2e74
y: 0x7fff825c2e67
y的空间分配为1个字节,x,m,n,o整数分配4个字节。 谢谢您的所有答复。
答案 0 :(得分:5)
如何为变量分配内存完全取决于实现方式-答案因平台而异。变量不必按照声明的顺序进行排列,并且根据对齐要求,一个变量的结尾与另一个变量的开头之间可能会有“空洞”(未使用的字节)。
以下是您的系统上可能发生的情况(所有字节值均为十六进制格式):
+----+
y: | 41 | 0x7fffcc33e10b
+----+
x: | 0a | 0x7fffcc33e10c // assuming little-endian representation
+----+
| 00 | 0x7fffcc33e10d
+----+
| 00 | 0x7fffcc33e10e
+----+
| 00 | 0x7fffcc33e10f
+----+
在x86和类似平台上,堆栈朝着地址减少的方向“向下”增长(x86也是低位字节序,因此寻址的字节是多字节对象的最低有效字节)。因此,x
在地址0x7fffcc33e10c
处被“首先”分配,然后y
在下一个可用对象地址处被分配。由于y
是char
,并且只有一个字节宽,因此下一个可用地址是0x7fffcc33e10b
。如果y
也是4字节的int
,则下一个可用地址将是0x7fffcc33e108
,布局将如下所示:
+----+
y: | 41 | 0x7fffcc33e108
+----+
| 00 | 0x7fffcc33e109
+----+
| 00 | 0x7fffcc33e10a
+----+
| 00 | 0x7fffcc33e10b
+----+
x: | 0a | 0x7fffcc33e10c
+----+
| 00 | 0x7fffcc33e10d
+----+
| 00 | 0x7fffcc33e10e
+----+
| 00 | 0x7fffcc33e10f
+----+
编辑
一个有趣的练习是声明
int x = 10;
char y = 'A';
int z = 20;
并查看它们的布局。如果以声明的顺序排列它们,则您可能会看到y
和z
之间的一个或多个未使用的字节,因为大多数平台要求多字节对象以偶数地址开头。如果编译器决定将它们布置为x
,z
,y
,我不会感到惊讶,因为这样可以最大程度地减少此类“漏洞”。
编辑编辑
我自己尝试过,得到以下结果:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee73b8a78 0a 00 00 00 ....
y 0x7ffee73b8a77 41 0a 00 00 A...
z 0x7ffee73b8a70 14 00 00 00 ....
y
和z
之间的三个未使用字节,因此显然必须将4字节对象对齐为4的倍数的地址。
+----+
z : | 14 | 0x7ffee73b8a70
+----+
| 00 | 0x7ffee73b8a71
+----+
| 00 | 0x7ffee73b8a72
+----+
| 00 | 0x7ffee73b8a73
+----+
| ?? | 0x7ffee73b8a74
+----+
| ?? | 0x7ffee73b8a75
+----+
| ?? | 0x7ffee73b8a76
+----+
y: | 41 | 0x7ffee73b8a77
+----+
x: | 0a | 0x7ffee73b8a78
+----+
| 00 | 0x7ffee73b8a79
+----+
| 00 | 0x7ffee73b8a7a
+----+
| 00 | 0x7ffee73b8a7b
+----+
答案 1 :(得分:3)
我添加了两个额外的变量:
#include<stdio.h>
int main(void){
int x=10;
char y='A';
int z = 3;
char m = 'a';
printf("x: %p \ny: %p\nz: %p\nm: %p\n", &x, &y, &z, &m);
return 0;
}
这是输出:
x: 0x7ffd2e8e0630
y: 0x7ffd2e8e062e
z: 0x7ffd2e8e0634
m: 0x7ffd2e8e062f
所以我想编译器首先分配char
,然后分配int
。