编译过程中何时分配内存?

3
当我写下


int main()
{
    int j;
}

j 的内存是在编译时分配的,但是在编译期间的哪个时间?

在分配变量内存时,编译有哪些不同的阶段?

如果 j 是全局的会怎样?


1
请格式化您的问题。 双空格换行。 - undefined
1
我有一种感觉,你的问题有些含糊不清,而且你的问题名称和描述不一致。 - user59634
如果问题是关于C语言中不同作用域的内存分配,那么标题应该被编辑以匹配这个主题。 - undefined
8个回答

9

我猜你把事情搞混了。

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


6
在 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()函数作用域之前被分配内存。


这个答案是错误的:变量'j'的存储空间在应用程序启动时不会被分配(通常在进程启动和进入'main'之间有很多千条指令)。而全局变量在进程启动时就已经被分配,远在'main'之前。 - undefined
我会考虑进入应用程序启动的main()部分。移除了'just'。 - undefined

3

缺少一个 'not' 或者类似的词在第一句话中吗? - undefined
现在你的答案几乎正确:全局变量和静态变量并不是在堆上分配的;它们是由程序加载器在进程启动时进行内存映射的。我觉得很讽刺,一个如此简单的问题竟然引发了这么多错误的答案。也许我应该把这个问题作为面试题。 - undefined
全局和静态变量不会在堆上分配。 - undefined
实际上,ANSI C并没有指定它们应该如何分配。重要的是它们在整个程序的运行期间存在。 - undefined

2

编译会生成程序的可执行代码。当运行这个可执行代码时,程序内存被分配。


在编程中,用“数据内存”而不是“程序内存”这样说会更好吗? - undefined

0

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


0

编译器决定将变量 j 放在哪里。通常情况下,局部变量会被放置在栈上,因此对于你的特定示例,编译器可能会在整个 main 函数的执行期间为其保留栈空间。请注意,这与全局变量内存不同,全局变量可能会有自己的内存。


0

我觉得你关注的是编译的阶段,而不是变量 'j' 的内存分配。因为我这么认为,以下是发生的情况:

当你将源代码输入C编译器时,首先进行的是词法和语义分析阶段,用于分析源代码的语法和语义是否正确。如果发现错误,编译器会相应地报告并停止继续执行。如果没有发现错误,它会继续生成源代码的中间表示形式,通常在进行各种优化后。这个中间表示可以是本地语言(与操作系统/架构相关,比如C)或平台无关的字节码(比如Python/Java..)。编译器的功能到此结束。

内存分配仅在执行代码时发生,这是程序的运行时。这仅发生在编译阶段之后,也许你不想在这里了解。如果你想知道,请告诉我,我会尽力添加我所知道的内容。

希望对你有帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接