内存分配变量

我很困惑。 自动,静态和全局变量的分配是在编译时还是在运行时进行?

我知道的是,在编译时,源代码被转换为机器语言。

当编译器找到类似int a;的语句时int a; ,它写了指令。 在编译时是否会发生任何额外的事情,比如内存分配?

执行.exe文件时会发生什么?

计算机(OS)或编译器是否会在运行时或编译时分配足够的内存来保存整数。

还有人说全局变量的地址是编译时常量。 这是什么意思? 请帮助解决每个问题,尤其是最后一个问题。

静态全局变量在编译时或运行时分配内存资源。 这取决于静态变量是否为零初始化,或者它们是否具有初始常量值。 例如,代码就像

 //global variable with internal linkage static int array[100]; 

不会占用可执行文件中的任何空间…换句话说,编译器/链接器将不会在该数组的可执行文件中分配内存,因为它不包含任何内容。 它将留下一个存根,指示何时启动可执行文件,必须为该数组分配内存。 一旦启动可执行文件,操作系统就会看到链接器留下的存根,并为数组(以及堆的其他内存等)分配和零初始化内存。 另一方面,

 //global variable with internal linkage static int array[100] = { 1, 2, 3}; 

将占用可执行文件中的空间,因为它在编译时使用常量值进行初始化。 因此,编译器将在它生成的程序集文件的data部分中发出代码,为数组分配存储空间。 然后,链接器将正确布局链接到最终可执行文件的所有程序集文件的数据部分和代码部分。 当操作系统将可执行文件加载到内存中时,该数组的内存已经是可执行文件内存“foot-print”的一部分。

自动变量,因为它们在代码执行期间在堆栈上分配,在运行时分配。

还有人说全局变量的地址是编译时常量。

这有点误导……在C中,在链接器创建可执行文件之前,您无法知道任何全局变量的确切内存地址,并且操作系统已将可执行文件加载到内存中。 这样做的唯一方法就是手动组装文件并创建一个由操作系统专门加载到给定地址的平面二进制文件,但现代操作系统不允许你这样做。 相反,链接器为全局变量的地址赋予占位符,以便在操作系统在运行时加载可执行文件时,可以用正确的值替换它们。 因此,虽然内存地址是“常量”,因为它在程序运行时不会随时间变化,但它的实际值不会在编译时分配。

这取决于变量的类型:

  • 堆栈变量在运行时完成(虽然它们的大小在编译时是已知的,但堆栈内存仅在函数入口上保留,这使得它在运行时分配)。 还有一个特别的警告, alloca在运行时从堆栈分配,即使它看起来像它的动态堆内存。

  • 堆变量在运行时分配,通常通过new / malloc分配,但是,指针的存储仍然可以在堆栈上。

  • 全局变量和静态变量以几种方式分配。 初始值将由编译器在二进制文件中分配,其初始值(或初始化程序将在启动时调用对象)。 未初始化的数据将通过读取PE通过OS加载程序进行分配,这就是数据在各个段之间分配的原因,例如.rdata.data.bss

现在使用全局/静态变量,编译器可以为它们绑定相对或首选的常量地址,因为它们是在二进制文件中分配的。

编译器生成一个目标文件(Windows下的.obj ,Unix下的.o ),它不仅包含机器指令,而且C ++中的所有结构都不会产生机器指令。 当发生内存分配时(正式地,至少)未指定。 实际上,由于在编译时不知道自动和动态对象的数量(因为函数可能是递归的),所以它们只能在编译时分配,并且编译器将生成代码来执行此操作(尽管它通常会分配)函数顶部有一条或两条指令的函数中的所有自动变量。 另一方面,编译器确切地知道具有静态生存期的对象将存在多少。 我熟悉的所有实现都在目标文件中生成加载器记录,最终导致系统加载程序在加载程序时将这些记录分配为初始过程映像的一部分; 加载的程序中没有代码分配它们。 (如果初始化不是静态的,则会有代码初始化它们。)

你这里有很多问题。 在C中,您有堆栈内存和堆内存。 全球都在堆。 所有非全局的非malloc变量都在堆栈中。 将堆栈内存视为您在函数内部创建的内存。 每个函数调用都会向堆栈添加另一个层。 函数返回时,返回在该函数内分配的非malloc内存。 全局变量的内存位置永远不会改变,这就是为什么它的位置在编译时可以是静态的。

当编译器找到类似int a;的语句时,它会写入指令。在编译时是否会发生任何额外的事情,比如内存分配?

是的,空间是为堆栈上的变量保留的。

执行.exe文件时会发生什么?

太久没在这里回答了。 缩小你的问题。

计算机(os)或编译器是否会在运行时或编译时分配足够的内存来保存整数。

取决于如何在代码上分配内存。

还有人说全局变量的地址是编译时常量。这意味着什么?

这意味着内存在编译时保留,因此全局变量的地址在执行期间不会改变。

当编译器找到int a; 在函数中的语句,他写了类似sub esp,sizeof(int) ,当程序运行并得到这一行时,它会分配内存。

如果它是一个全局变量,编译器会写一个resb指令,告诉操作系统在加载程序时分配内存。