【问题标题】:Memory allocation of variables [closed]变量的内存分配[关闭]
【发布时间】:2012-02-08 16:09:28
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • int a; 这样的声明并不直接对应机器指令。
  • 这不是我作业的一部分。我的脑海中出现了一个问题,为什么旧​​的学习与新的发生冲突。我总是用谷歌搜索,直到我吓坏了

标签: c++ c variables


【解决方案1】:

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

这样的代码
//global variable with internal linkage
static int array[100];

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

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

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

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

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

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

【讨论】:

  • 您只谈论具有内部链接的全局变量。具有外部链接的全局变量会发生什么
  • 本质上是一样的......内部和外部链接只是确定内存位置从另一个代码模块的可见性。
  • 你的意思是给全局变量一个常量占位符(OS给定时地址是常量)
  • 注意:“也有人说全局变量的地址是编译时常量”C++中不是这种情况
【解决方案2】:

这取决于变量的类型:

  • 堆栈变量在运行时完成(尽管它们的大小在编译时就知道了,但堆栈内存只保留在函数入口处,这使其成为运行时分配)。还有一个特殊的警告,alloca 在运行时从堆栈中分配,即使它看起来像它的动态堆内存。

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

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

        这里太长了,无法回答。缩小您的问题范围。

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

        取决于您在代码上分配内存的方式。

        还有说全局变量的地址是编译时 常数。是什么意思??

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            猜你喜欢
            • 2013-10-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多