为什么书上说,“编译器为内存中的变量分配空间”。这样做的不是可执行文件吗?我的意思是,例如,如果我编写以下程序,
#include <iostream>
using namespace std;
int main()
{
int foo = 0;
cout<<foo;
return 0;
}
并编译它,并得到一个可执行文件(让它成为Program. exe),现在,如果我运行plan.exe,这个可执行文件本身将命令为变量foo分配一些空间。不会吗?请解释为什么书籍一直在说,“编译器会这样做…那样做”,而实际上,编译后的可执行文件会这样做。
在这个问题中添加另一个相关问题,为什么sizeof
被称为编译时运算符?它实际上不是运行时运算符吗?
当我们聘请建筑师设计房子时,他或她定义房间的大小等,并通知工人(工人)。工人相应地做工作。但我们仍然会说“建筑师这样建造了房子”,而不是“工人这样建造了房子”。
劳动者只是执行架构师定义的步骤。编译器实际上在运行时完成了检查和定义要分配多少内存等所有工作,然后这些指令就被遵循了。
从技术上讲,创建空间本身的行为是在运行时完成的,但是编译器是确定在您的情况下为您的foo
变量在堆栈上保留多少空间的人。
编译器知道int
类型的大小,因此可以生成正确的汇编器指令,该指令将在堆栈上保留足够的空间,以便让foo
驻留在那里。
如果您查看下面为您展示的程序生成的汇编器(使用MSVC2012),我已经注释了其中的一些以向您展示会发生什么:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
//Setup stack frame for main by storing the stack pointer from the calling function and
//reserving space for local variables and storing commonly used registers on the stack
002E4390 push ebp
002E4391 mov ebp,esp
// reserve space for local variables, which is 204 bytes here, no idea why so much.
// this is where the compiler calculated the size of your foo and added that to whatever else needs to be stored on the stack. Subtract from stack pointer (esp) because stack grows downward.
002E4393 sub esp,0CCh
002E4399 push ebx
002E439A push esi
002E439B push edi
002E439C lea edi,[ebp-0CCh] // load effective address of [ebp-0CCh], which I suspect would be your foo variable into edi register
002E43A2 mov ecx,33h
002E43A7 mov eax,0CCCCCCCCh
002E43AC rep stos dword ptr es:[edi] //fill block of memory at es:[edi] with stuff
int foo;
return 0;
002E43AE xor eax,eax //set eax to zero for return value
}
// restore everything back to how it was before main was called
002E43B0 pop edi
002E43B1 pop esi
002E43B2 pop ebx
002E43B3 mov esp,ebp
002E43B5 pop ebp
002E43B6 ret
这只是术语的松散使用。当然编译器不会为程序分配内存。更准确的描述是,它告诉运行时在程序运行时分配多少内存。
在程序真正运行之前,它不在内存中(除非它是动态加载的,但即使在运行时也会发生这种情况,因此超出了编译器的范围),因此没有内存可言。
这些书所谈论的是分配其大小在编译时已知的变量,而不是动态分配cin