在这段代码中如何占用内存?

时间:2019-07-01 08:35:59

标签: c

我是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个字节。 谢谢您的所有答复。

2 个答案:

答案 0 :(得分:5)

如何为变量分配内存完全取决于实现方式-答案因平台而异。变量不必按照声明的顺序进行排列,并且根据对齐要求,一个变量的结尾与另一个变量的开头之间可能会有“空洞”(未使用的字节)。

以下是您的系统上可能发生的情况(所有字节值均为十六进制格式):

   +----+
y: | 41 | 0x7fffcc33e10b    
   +----+
x: | 0a | 0x7fffcc33e10c    // assuming little-endian representation
   +----+
   | 00 | 0x7fffcc33e10d
   +----+
   | 00 | 0x7fffcc33e10e
   +----+
   | 00 | 0x7fffcc33e10f
   +----+

在x86和类似平台上,堆栈朝着地址减少的方向“向下”增长(x86也是低位字节序,因此寻址的字节是多字节对象的最低有效字节)。因此,x在地址0x7fffcc33e10c处被“首先”分配,然后y在下一个可用对象地址处被分配。由于ychar,并且只有一个字节宽,因此下一个可用地址是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;

并查看它们的布局。如果以声明的顺序排列它们,则您可能会看到yz之间的一个或多个未使用的字节,因为大多数平台要求多字节对象以偶数地址开头。如果编译器决定将它们布置为xzy,我不会感到惊讶,因为这样可以最大程度地减少此类“漏洞”。

编辑编辑

我自己尝试过,得到以下结果:

       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    ....

yz之间的三个未使用字节,因此显然必须将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)

我的答案不准确也不完整,因此,请参考John Bode's answer

我添加了两个额外的变量:

#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