2012-02-08 97 views
1

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

我知道的事情是,在编译时,源代码被翻译成机器语言。

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

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

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

另外据说全局变量的地址是编译时常量。这是什么意思? 请帮助解决每个问题,特别是最后一个问题。

+1

像'int a;'这样的声明并不直接对应于机器指令。 – 2012-02-08 16:13:36

+0

这是功课吗? – Francois 2012-02-08 16:13:56

+0

这不是我家庭作业的一部分。问题出现在我的脑海里,为什么旧​​的学习会与新的学习冲突。我总是Google它,直到我怪异 – 2012-02-08 16:17:43

回答

6

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

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

不会占用执行体的任何房间......换句话说,编译器/连接不会在执行该阵列,因为它不包含任何分配内存。它会留下一个存根,表示何时启动可执行文件,必须为该数组分配内存。一旦启动可执行文件,操作系统就会看到链接程序留下的存根,并为该数组分配和初始化内存(以及堆的其他内存等)。在其他手,因为它是在编译时间常数的值初始化

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

将占用空间的可执行文件。因此,编译器将在它生成的程序集文件的data部分发出代码,为该阵列分配存储空间。然后链接程序将正确地布置链接到最终可执行文件的所有程序集文件的数据段和代码段。当操作系统将可执行文件加载到内存中时,数组的内存已经是可执行文件内存“脚印”的一部分。

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

另外据说全局变量的地址是编译时间常数。

这是一个有点误导...用C你可以不知道任何全局变量的确切的内存地址,直到连接器已经创建了可执行文件,操作系统加载可执行文件到内存中。唯一的办法是如果你手工组装一个文件并创建一个平台二进制文件,这个二进制文件被操作系统专门加载到一个给定的地址中,但是现代操作系统不允许你这样做。相反,全局变量的地址由链接器给予占位符,这样当操作系统在运行时加载可执行文件时,它们可以用正确的值代替。因此,尽管内存地址在程序运行时不会随时间变化,但内存地址为“常量”,但其实际值在编译时不会被分配。

+0

你只谈论全局变量与内部链接。全局变量与外部linkage – 2012-02-08 17:07:35

+0

同样的事情本质上......内部和外部链接仅仅决定了来自另一个代码模块的内存位置的可见性。 – Jason 2012-02-08 17:11:31

+0

您的意思是一种常量占位符(地址在OS给定时将是常量)赋予全局变量 – 2012-02-08 17:24:12

0

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

0

当编译器发现如int一个;,它写入 instruction.Does任何额外的事情发生,如内存分配在 声明编译时间?

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

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

在这里回答太长。缩小你的问题。

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

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

另外据说全局变量的地址是编译时间 常量。它是什么意思?

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

0

当编译器在函数中发现int a;语句时,他写了类似sub esp,sizeof(int)的东西,并且当程序运行并获取此行时,它会分配内存。

如果它是一个全球性的varibale,编译器写resb指令,该指令告诉操作系统分配内存在加载程序。

1

这取决于变量的类型:

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

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

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

与被全局/静态变量

现在,编译器可以为他们结合相对或者优先常地址,导致它们在二进制中分配。

1

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