Why do books say, \"the compiler allocates space for variables in memory\". Isn\'t it the executable which does that? I mean, for example, if I write the following program
It says the compiler allocates space for variables in memory, because otherwise you need to allocate (and free!) memory yourself with new/malloc
etc.
It's just a loose use of terminology. Of course the compiler doesn't allocate memory for the program. A more accurate description is that it tells the runtime how much memory to allocate when the program is running.
Until the program is actually run, it isn't in memory (unless it's loaded dynamically, but even that happens during run-time, so out of the scope of the compiler), so there's no memory to speak of.
What those books are talking about is allocating variables whose size is known at compile-time, as opposed to dynamic allocation cin >> x; int * y = new[x];
, where the size isn't known.
Of course compiler doesn't "allocate space for variables". Compiler generates a code which allocates space for variables in memory.
I.e. if you have
int foo;
foo = 1;
in source code, compiler may generate a code like
int* fooPtr = allocate sizeof(int)
*fooPtr = 1;
In the x86 architecture, usually that allocate
thing will be a single assembly instruction:
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
If you have more than one local variable, compiler will pack them into a structure and allocate them together:
int foo;
int bar;
bar = 1;
will be compiled as
struct Variables { int foo; int bar; };
Variables* v = allocate sizeof(Variables);
v->bar = 1;
or
sub esp, 4+4 ; allocate sizeof(Variables) on stack
mov [esp + 4], 1 ; where 4 is offsetof(Variables, bar)
When we hire an architect to design a house, he or she defines the size of the rooms, etc. and informs the workers (labourers) about it. The labourers do the work accordingly. But still we would say "The architect made the house this way" and not "The labourer made the house this way".
The labourer is just performing the steps defined by the architect. The compiler actually does all the work for checking and defining how much memory is to be allocated, etc. at run time and then those instructions are just followed.
Technically the act of creating the space itself is done at run time, however the compiler is the one to figure out how much space to reserve on the stack in your case, for your foo
variable.
The compiler knows the size of the int
type and therefore can generate the right assembler instruction that will reserve enough space on the stack in order to let foo
live there.
If you look at the below generated assembler (using MSVC2012) for the program you showed, I have commented some of it to show you what happens:
#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
Suggest you to read compiler construction. Focus on the storage phase, your query would be resolved.
After the program gets compiled its converted to object code, which is an assembly language code. every line of a high level language program gets translated to many assembly language steps. The translated program is put into the assembler which is executed. There is STORAGE assignment phase in comiler construction which translates to Machine Operation table(MOT instructions at assembly level). This is where space allocation for variables/registers is done. There is a register modifier keyword in C++ as well.