我很困惑。自动,静态和全局变量的分配是在编译时还是在运行时进行?
我知道的是,在编译时,源代码被翻译成机器语言。
当编译器找到类似int a;
的语句时,它会写入指令。在编译时是否会发生任何额外的事情,例如内存分配?
执行.exe文件会发生什么?
计算机(OS)或编译器是否会在运行时或编译时分配足够的内存来保存整数。
据说全局变量的地址是编译时常量。这是什么意思? 请帮助解决每个问题,特别是最后一个问题。
答案 0 :(得分:6)
静态全局变量在编译时或运行时分配内存资源。这取决于静态变量是否为零初始化,或者它们是否具有初始常量值。例如,像
这样的代码//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中,在链接器创建可执行文件之前,您无法知道任何全局变量的确切内存地址,并且操作系统已将可执行文件加载到内存中。这样做的唯一方法就是手动组装文件并创建一个由操作系统专门加载到给定地址的平面二进制文件,但现代操作系统不允许你这样做。相反,链接器为全局变量的地址赋予占位符,以便在操作系统在运行时加载可执行文件时,可以用正确的值替换它们。因此,虽然内存地址是“常量”,因为它在程序运行时不会随时间改变,但它的实际值不会在编译时分配。
答案 1 :(得分:1)
这取决于变量的类型:
堆栈变量在运行时完成(虽然它们的大小在编译时已知,但堆栈内存仅在函数入口上保留,这使得它可以进行运行时分配)。还有一个特别的警告,alloca
在运行时从堆栈中分配,即使它看起来像是动态堆内存。
堆变量在运行时分配,通常是通过new
/ malloc
,但是,指针的存储可能仍在堆栈中。
全局变量和静态变量以几种方式分配。初始值将由编译器在二进制文件中分配,其初始值(或初始化程序将在启动时调用对象)。未初始化的数据将通过读取PE通过OS加载程序分配,这就是数据在各个段之间分配的原因,例如.rdata
,.data
& .bss
。
现在使用全局/静态变量,编译器可以为它们绑定相对或首选的常量地址,因为它们是在二进制文件中分配的。
答案 2 :(得分:1)
编译器在Windows下生成一个目标文件.obj
,.o
下
Unix)包含的不仅仅是机器指令,而不是全部
C ++中的构造将导致机器指令。当记忆
发生的分配是(正式地,至少)未指定的。在实践中,
因为在编译时不知道自动和动态对象的数量
时间(因为函数可能是递归的),它们只能在
编译时,编译器将生成代码来执行此操作(尽管如此)
它通常会在a中分配所有自动变量
函数顶部有一个或两个指令的函数)。上
另一方面,编译器确切知道有多少个静态对象
一生将存在。我熟悉的所有实现
在目标文件中生成最终导致的加载器记录
系统加载程序将这些作为初始过程映像的一部分进行分配
加载程序时;加载的程序中没有代码
分配它们。 (如果初始化不是静态的,则会有代码
初始化它们。)
答案 3 :(得分:0)
你这里有很多问题。在C中,您有堆栈内存和堆内存。全球都在堆。所有非全局的非malloc变量都在堆栈中。将堆栈内存视为您在函数内创建的内存。每个函数调用都会向堆栈添加另一个层。函数返回时,返回在该函数内分配的非malloc内存。全局变量的内存位置永远不会改变,这就是为什么它的位置在编译时可以是静态的。
答案 4 :(得分:0)
当编译器找到类似int a;的语句时,它会写入 指令。任何额外的事情都会发生,例如内存分配 编译时间?
是的,空间是为堆栈上的变量保留的。
执行.exe文件会发生什么?
这里的答案太长了。缩小你的问题。
计算机(os)或编译器是否会分配足够的内存 在运行时或编译时持有一个整数。
取决于如何在代码上分配内存。
据说全局变量的地址是编译时间 常数。这意味着什么?
这意味着内存在编译时保留,因此全局变量的地址在执行期间不会改变。
答案 5 :(得分:0)
当编译器在函数中找到int a;
语句时,他会编写类似sub esp,sizeof(int)
的内容,当程序运行并获取此行时,它会分配内存。
如果它是全局变量,编译器会写一条resb
指令,告诉操作系统在加载程序时分配内存。