繁体   English   中英

memory中的c语言存储数组的机制是什么

[英]what is the mechanism of the c language storing array in memory

我正在学习 c 语言并练习自己。 我想知道 c 如何为数组分配 memory 。 因为我有这样的代码:

#include<stdio.h>

int main(void)
{
     char a[] = {1,2,3,4,5,6,7,8,9,10};
     int i = 578;
     char * p1;
     int * p2;
     printf("\nAddress of pointer p1 : %p", &p1);
     printf("\nAddress of pointer p2 : %p", &p2);
     printf("\nAddress of int i : %p", &i);
     p1 = 0x0028FF34;
     p2 = 0x0028FF35;
     /* Print the Addresses */
     for (i = 0; i < 10; i++)
     {
          printf("\nAddress of a[%d] : %p", i, (void *) &a[i]);
     }
     printf("\nThe content in the address 0x0028FF34: %x", *p1);
     printf("\nThe content in the address 0x0028FF35: %x", *p2);
     return 0;
}

在我的电脑上运行此代码会得到 output 像这样

Address of pointer p1 : 0028FF2C
Address of pointer p2 : 0028FF28
Address of int i : 0028FF30
Address of a[0] : 0028FF36
Address of a[1] : 0028FF37
Address of a[2] : 0028FF38
Address of a[3] : 0028FF39
Address of a[4] : 0028FF3A
Address of a[5] : 0028FF3B
Address of a[6] : 0028FF3C
Address of a[7] : 0028FF3D
Address of a[8] : 0028FF3E
Address of a[9] : 0028FF3F
The character content in the addresss 0x0028FF34: ffffff80
The character content in the addresss 0x0028FF35: 3020100

字符指针 p 占用 32 位,即 4 个字节。 因此,指针 p2 与指针 p1 的距离为 4 个字节长,指针 p1 与 int i 的距离也是如此。 int i 在我的系统中也是 4 个字节。 在我看来,int i 与数组 a[] 的距离应该是 4 个字节。 数组a[]的起始地址应该是0028FF34,为什么是0028FF36?

0028FF34和0028FF35的内容是什么意思? 0028FF34 指向一个字符,output 是 ffffff80 并且 0028ff35 指向一个 int,output 是 3020100。

您想知道 C 如何为数组分配 memory ... 和其他数据类型。 好的。 好吧,这取决于如何定义数组(或其他变量)。 在您的情况下,您已将它们定义为自动分配(“本地”)变量,因此它们存储在 C 运行时堆栈中。 (从技术上讲,对于具有自动存储的变量,可能还有另一种分配机制,但实际上大多数系统都使用运行时堆栈。)如果您在int main(void)上方的几行中定义了数组和其他变量,它们将是“全局变量”并将静态分配并使用外部链接,因此它们对其他编译单元(other.c 文件)可见。 如果您将关键字static放在它们前面,它们仍将被静态分配,但它们的链接将是内部的,因此它们对其他编译单元(.c 文件)不可见。 无论您在 function 主体内部还是外部定义变量,最后一部分都是正确的; 如果您在 function 主体之外将它们定义为static ,则它们可用于同一编译单元中的其他功能; 如果您在 function 主体内将它们定义为static ,则编译器仅允许一个 function 访问它们; 实际上,它们仅在定义它们的 scope 可见。

至于它们的确切放置位置,编译器/链接器可以自由地将它们放置在它选择的存储类区域内的任何位置; 在这种情况下,编译器将它们放置在运行时堆栈中,但它们的顺序和相对位置不是由语言定义的,因此编译器可以自由地以它喜欢的任何方式排列它们。

通常变量会在它们之间分配填充以确保它们对齐,以便它们从数据大小的最佳边界开始,因为(由于硬件问题)访问与其数据宽度匹配的字节边界上的数据通常更快,这正是这里发生的事情。 您可能会说,“但是i以 4 字节边界结束,并且a[]没有 alignment 要求,那么为什么它会在分配a[]之前在i之后添加填充?” 但那是因为您正在考虑按 memory 地址增加的顺序进行分配。 您是否注意到您的变量看起来像是“向后”分配在 memory 中的? 实际上他们不是,在大多数系统上。 堆栈在 memory 中从高地址向低地址增长,考虑到这一点,很明显,分配的变量集中的第一个变量是a[] ,然后是i (在较低地址)。 因为a[]后面的字节地址不是 4 的倍数,所以在编译器分配i之前,它添加了 2 个字节的填充!

现在,至于您在 0x0028FF34 和 0x0028FF35 处读取的值:无论最后写入这些地址的任何内容都留下了垃圾。 0x0028FF34 处的字节是 0x80,它通过... varargs 作为 integer 传递给“printf()”,并且在您的系统上, char必须被签名,所以当它被提升为 integer 时,它是符号扩展的,因为0x80 的位为 1,结果值为 0xFFFFFF80。 您读取为 0x0028FF35 的 integer 显示该地址的字节是 0x00,其他字节是 03、02 和 01,您应该注意的是a[]的前 3 个字节。 我们还可以从中看出您的系统是小端(如 x86),因为 integer 的高位字节位于高位字节可寻址位置。

没有要求连续分配变量变量。

大多数数据类型需要在 4 的倍数(在某些情况下为 8)的地址处对齐。 例外是char ,它不需要任何特殊的 alignment。

正如您所注意到的, int和指针变量与 4 字节 alignment 连续分配(尽管有趣的是它们的分配顺序与声明不同)。

char数组在它之后分配,并使用 10 个字节。 堆栈中很可能还有其他内部数据使用数组后的 memory,它需要 4 字节 alignment。 所以某处会有 2 个浪费的字节——它可能在数组之前或之后。 编译器选择将它放在数组之前。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM