书籍为什么说“编译器为内存中的变量分配空间”?

时间:2013-04-04 08:19:36

标签: c++ compiler-construction runtime sizeof

为什么书会说,“编译器为内存中的变量分配空间”。这不是可执行文件吗?我的意思是,例如,如果我写下面的程序,

#include <iostream>
using namespace std;

int main()
{
   int foo = 0;
   cout<<foo;
   return 0;
}

并编译它,并获得一个可执行文件(让它成为program.exe),现在,如果我运行program.exe,这个可执行文件本身将命令为变量foo分配一些空间。不是吗?请解释为什么书继续说“编译器会这样做......那样做”而实际上,编译后的可执行文件会这样做。

在这个问题中添加另一个相关问题,为什么sizeof被称为编译时运算符?它实际上不是运行时运算符吗?

7 个答案:

答案 0 :(得分:20)

当我们聘请建筑师设计房屋时,他或她会定义房间的大小等,并告知工人(劳动者)。劳动者相应地做了工作。但我们仍然会说“建筑师以这种方式建造房屋”而劳动者以这种方式建造房屋”。

劳动者只是执行建筑师定义的步骤。编译器实际上在运行时完成了检查和定义要分配多少内存的所有工作,然后只是遵循这些指令。

答案 1 :(得分:11)

从技术上讲,创建空间本身的行为是在运行时完成的,但是在你的情况下,编译器可以找出在堆栈中预留多少空间,{{1变量。

编译器知道foo类型的大小,因此可以生成正确的汇编程序指令,该指令将在堆栈上保留足够的空间,以便让int存在。

如果您查看下面生成的汇编程序(使用MSVC2012)来显示您所显示的程序,我已经对其中的一些进行了评论,以向您展示会发生什么:

foo

答案 2 :(得分:7)

这只是对术语的松散使用。当然编译器不为程序分配内存。更准确的描述是它告诉运行时程序运行时要分配多少内存。

在程序实际运行之前,它不在内存中(除非它是动态加载的,但即使这种情况发生在运行时,因此超出了编译器的范围),所以没有内存可言。< / p>

这些书正在讨论的是分配大小在编译时已知的变量,而不是动态分配cin >> x; int * y = new[x];,其中大小未知。

答案 3 :(得分:3)

它说编译器为内存中的变量分配空间,因为否则你需要用new/malloc等自己分配(和释放!)内存。

答案 4 :(得分:1)

当然编译器不“为变量分配空间”。编译器生成一个代码,为内存中的变量分配空间。

即。如果你有

int foo;
foo = 1;

在源代码中,编译器可能会生成类似

的代码
int* fooPtr = allocate sizeof(int)
*fooPtr = 1;

在x86架构中,通常allocate事物将是单个汇编指令:

sub esp, 4    ; allocate 4 == sizeof(int) bytes on stack
              ; now the value of "esp" is equal to the address of "foo",
              ; i.e. it's "fooPtr"
mov [esp], 1  ; *fooPtr = 1

如果您有多个局部变量,编译器会将它们打包到一个结构中并将它们分配在一起:

int foo;
int bar;
bar = 1;

将编译为

struct Variables { int foo; int bar; };
Variables* v = allocate sizeof(Variables);
v->bar = 1;

sub esp, 4+4       ; allocate sizeof(Variables) on stack
mov [esp + 4], 1   ; where 4 is offsetof(Variables, bar)

答案 5 :(得分:0)

编译器生成机器指令并计算出局部变量占用的内存地址。每个局部变量都有一个相对于堆栈顶部的地址,例如foo将被假定为存储器地址stack_pointer。如果您有一个变量foo2,它将被放置在地址stack_pointer + 4,其中4是int的大小。

当访问局部变量foo时,编译器将替换stack_pointer中保存的地址。硬件有一个特殊的stack_pointer寄存器,它总是指向当前堆栈的顶部。

编译器知道每个变量的大小,因为它负责查看structclass声明并确定它在内存中的布局方式。所以sizeof在编译时是已知的,并被视为常量表达式。已知int等原始类型具有一定的大小,例如sizeof(int)为4.

答案 6 :(得分:-1)

建议你阅读编译器构造。专注于存储阶段,您的查询将得到解决。

程序编译后,将其转换为目标代码,即汇编语言代码。高级语言程序的每一行都被转换为许多汇编语言步骤。翻译的程序被放入执行的汇编程序中。  在编译器构造中存在STORAGE分配阶段,其转换为机器操作表(在装配级别的MOT指令)。这是变量/寄存器的空间分配完成的地方。 C ++中也有一个register modifier关键字。

相关问题