编译期间何时分配内存?

问题描述 投票:2回答:8

我写的时候

int main()
{
    int j;
}

j的内存是在编译时分配的,但是在编译时分配的?

将内存分配给变量时,编译的各个阶段是什么?

如果j是全局的怎么办?

c memory-management compilation
8个回答
8
投票

我想你正在把事情混在一起。

编译器不会为变量分配内存-它会在运行时生成为变量分配内存的代码。对于全局变量,将添加到程序启动代码中。


5
投票

在C中,main的编译与其他函数相同:在main中声明的任何变量都将“分配”在堆栈上。堆栈框架是单个函数调用使用的堆栈部分。该框架包含一个函数中使用的所有本地变量的插槽。该内存被视为临时内存,因为当函数返回时,该帧将从堆栈中弹出。

C编译器将为全局变量分配一个静态地址。该地址被认为是二进制文件“映像”的一部分,因此在内存中具有静态位置。 C编译器知道每种类型的大小,因此它可以为每个全局变量在二进制文件的内存布局中留出适当的空间。然后,访问此变量的任何代码都将仅引用该地址。

您可以使用以下代码检查变量的地址:

#include<stdio.h>

int i;

void foo(int n)
{
    if(n > 2)
        return;

    printf("From foo &n = %xd\n", &n);
    printf("From foo &i = %xd\n", &i);

    foo(n+1);
}


int main()
{
    printf("&i = %xd\n", &i);
    foo(0);
    return 0;
}

运行此代码会产生类似于以下内容的输出:

./a.out 
&i = 600934d
From foo &n = 38bc4efcd
From foo &i = 600934d
From foo &n = 38bc4eccd
From foo &i = 600934d
From foo &n = 38bc4e9cd
From foo &i = 600934d

您应该在这里注意两件事:

  1. i的地址每次被引用都是常数
  2. n的地址(函数foo的局部变量随对foo的每次调用而变化。实际上,由于堆栈向下增长,因此每次都会减少。

5
投票

不是在编译时,您的'int j'将在应用程序启动时分配,当应用程序进入main()范围(实际上,由于使用堆栈,从技术上讲,不会分配),全局变量将被分配在进入main()范围之前在运行时。


2
投票

编译生成程序的可执行代码。运行该可执行代码时,将分配程序内存。


2
投票

编译过程不会分配内存。它生成分配内存的代码:)

在这种情况下,j将是所谓的堆栈变量,在执行进入main()函数时将对其进行分配。全局变量和静态变量将分配在堆上。

以下是简短说明:http://www.costech.or.tz/cs231/websites/C%20Programming/www-ee.eng.hawaii.edu/Courses/ee150/Book/chap14/subsection2.1.1.8.html。我会看看是否能找到更好的一个。


0
投票

取决于编译器在何处放置j。通常,局部变量放在堆栈上,因此对于您的特定示例,编译器可能会在main函数期间保留堆栈上的空间。请注意,这不同于全局变量内存,后者可能会接收自己的内存。


0
投票

[内存不是在编译时分配的,而是在运行时分配的。编译器刚刚生成了将执行您的程序的机器代码,实际分配发生在运行时。在这种情况下,不使用该变量,并且不会为此发出任何代码。


0
投票

我认为您正在查看编译的阶段,而不是'j'的内存分配。既然如此,这就是发生的情况:

一旦将源代码提供给C编译器,第一阶段就是词法和语义分析,其中分析源代码的语法和语义是否正确。如果发现错误,编译器将相应地报告,并且不会继续。如果未发现错误,则通常在进行各种优化之后继续进行源代码的中间表示。这种中间表示可以是本机语言(类似于C / OS /体系结构),也可以是平台无关的字节码(例如Python / Java ..)。编译器的功能到此结束。

执行内存分配在执行代码时。这是程序的运行时。这仅在编译阶段之后才出现,您可能不想在这里知道。如果您愿意,请告诉我。我将尝试添加我所知道的。

HTH。

© www.soinside.com 2019 - 2024. All rights reserved.