我对计算机内存的工作有疑问。我试图自己得到答案,但我无法弄清楚它是如何工作的。因此,想象一个人声明指向未来字符串的指针的情况;但是,初始化会稍晚:
char *str;
之后,他或她想宣布另一个变量。
char her;
在此之后,两个变量都被初始化,它们的地址和值被打印到STDOUT。整个程序看起来像这样:
int main(void)
{
char *str;
char her;
her = 'Y';
str = "HelloMuraMana";
printf("%p\n", (void *)&str);
printf("%p\n", (void *)&(str[1]));
printf("%p\n", (void *)&(str[2]));
printf("%p\n", (void *)&(str[3]));
printf("%p\n", (void *)&(str[4]));
printf("%p\n", (void *)&her);
return (0);
}
现在,我的问题是:计算机如何为两个变量分配内存(尤其是字符串字符)。我想添加一张图片,我的macOS机器显示了我的结果:
编辑:
我特别感兴趣的是记忆在这里工作的方式。另请注意,str [0]有一个地址,str 1,str [2],str [3]和str [4]有其他,与第一个元素地址不连续。
答案 0 :(得分:0)
从概念上讲,当程序加载到内存中时,它有3个区域(段):
在您的情况下,char her
变量是main()
函数中的局部变量,该变量使用值Y
进行初始化。因此,它存储在堆栈中并可以修改。
char *str
变量是指向"HelloMuraMana\0"
地址的指针,export default function users
是位于代码段中的常量。作为只读区域,您无法修改其内容。
答案 1 :(得分:0)
就像我在评论中所说的那样,内存中具体化内容的细节会因平台而异。但是,这是一个非常高级的视图,应该给出一些有用的东西。
首先,在C编程语言的上下文中,对象可以具有多个存储持续时间之一:static
,automatic
,allocated
和{ {1}}。程序启动时会分配具有thread local
存储持续时间的对象,并在程序退出时释放。具有static
存储持续时间的对象在进入其封闭范围(函数或块)时分配,并在该范围退出时立即释放。存储时间automatic
的对象通过调用allocated
进行分配,并通过调用malloc/calloc/realloc
释放。我不打算进入free
,因为它与这个讨论并不相关。
当你的程序被加载到内存中时,它的布局是这样的(假设是x86或类似的):
thread local
具体图片取决于您的系统。请注意,这是虚拟地址空间中的内容,而不是物理内存。
当您的程序运行时, +------------------------+
high address | Command line arguments |
| and environment vars |
+------------------------+
| stack | <-- str and her live here, but
| - - - - - - - - - - - | only for the duration of main()
| | |
| V |
| |
| ^ |
| | |
| - - - - - - - - - - - |
| heap |
+------------------------+
| global and read- | <-- "HelloMuraMana" lives here for
| only data | duration of the program
+------------------------+
| program text |
low address | (machine code) |
+------------------------+
变量的存储(函数参数和函数本地变量或auto
和her
之类的块)将从标记为{{1}的区域中分配}。 str
个对象的存储空间是从标有stack
的区域分配的。
allocated
个对象的存储以及字符串文字的存储(如heap
)来自不同的段;在上图中,它将是标记为static
的细分。根据您的系统,字符串文字可能存储在只读段(例如"HelloMuraMana"
或global and read-only data
)中,或者它们可能位于可写段中。字符串文字假定是不可变的(因此称为“文字”),因此尝试修改字符串文字将导致未定义的行为。
在上面的布局中,全局数据对象的地址低于堆栈或堆对象,这些对象由输出显示。当您输入.rodata
时,变量.rdata
将从堆栈中分配;它的值是字符串文字的地址,它是在程序首次启动时从全局数据段分配的。
答案 2 :(得分:-1)
你应该选择一个稍微简单的例子:
int main(void)
{
char *str;
char her;
her = 'Y';
str = "HelloMuraMana";
puts(str);
putchar(her);
return (0);
}
.LC0:
.string "HelloMuraMana"
main:
pushq %rbp
movq %rsp, %rbp //frame setup
subq $16, %rsp //allocate 2*8bit words for the 2 variables
movb $89, -1(%rbp) //initialize her
movq $.LC0, -16(%rbp) //initialize str
movq -16(%rbp), %rax //prepare the argument to puts
movq %rax, %rdi
call puts //self-descriptive
movsbl -1(%rbp), %eax //prepare the argument to putchar
movl %eax, %edi
call putchar //self-descriptive
movl $0, %eax //prepare the main return value
leave
ret
现在,正如您从反汇编中看到的那样,两个堆栈变量由堆栈指针减法(subq $16, %rsp
)分配(因为堆栈通常向下增长)。字符串文字字符数组是一个静态生命周期变量,它进入程序加载程序在程序加载时将分配的段。