This is very much compiler dependent under the covers, but logically the storage is assigned as soon as the variable is declared.
Consider this simplistic C++ example:
// junk.c++
int addtwo(int a)
{
int x = 2;
return a + x;
}
When GCC compiles this, the following code is generated (; comments mine):
.file "junk.c++"
.text
.globl _Z6addtwoi
.type _Z6addtwoi, @function
_Z6addtwoi:
.LFB2:
pushl %ebp ;store the old stack frame (caller's parameters and locals)
.LCFI0:
movl %esp, %ebp ;set up the base pointer for our parameters and locals
.LCFI1:
subl $16, %esp ;leave room for local variables on the stack
.LCFI2:
movl $2, -4(%ebp) ;store the 2 in "x" (-4 offset from the base pointer)
movl -4(%ebp), %edx ;put "x" into the DX register
movl 8(%ebp), %eax ;put "a" (+8 offset from base pointer) into AX register
addl %edx, %eax ;add the two together, storing the results in AX
leave ;tear down the stack frame, no more locals or parameters
ret ;exit the function, result is returned in AX by convention
.LFE2:
.size _Z6addtwoi, .-_Z6addtwoi
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits
Everything between _Z6addtwoi and .LCFI2 is boilerplate code used to set up the stack frame (store the previous function's variables, etc. safely out of the way). That last "subl $16, %esp" is the allocation of the local variable x.
.LCFI2 is the first bit of actual executing code that you've typed. "movl $2, -4(%ebp)" is putting the value 2 into the variable. (Initialization, in other words.) Now your space is allocated AND initialized. After that it loads the value into register EDX and follows that by moving your parameter, found in "8(%ebp)", into another register EAX. It then adds the two together, leaving the result in EAX. This is now the end of any code you've actually typed. The rest is again just boilerplate. Since GCC mandates that integers are returned in EAX, no work has to be done for the return value. The "leave" instruction tears down the stack frame and the "ret" instruction returns control back to the caller.
TL;DR summary: you can think of your space as having been allocated with the very first line of executable code in your block (paired {}).
I thought I'd clean this up a bit with explanatory comments seeing as this is the selected answer.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…