3

Why C use stacks for storing the local variables? Is this just to have independent memory space or to have feature of automatic clearing of all the local variables and objects once it goes out of scope?

I have few more questions around the same,

Question 1) How local variables are referenced from the instruction part. Consider NewThreadFunc is the function which is called by createThread function.

DWORD WINAPI NewThreadFunc(PVOID p_pParam)
{
int l_iLocalVar1 = 10;
int l_iLocalVar2 = 20;

int l_iSumLocalVar = l_iLocalVar1 + l_iLocalVar2;
}

The stack for this thread would look like this,

| p_pParam       |
| NewThreadFunc()|
| 10             |
| 20             |
| 30             |
|                |
.
.
.

Now my question is, while executing this function how would CPU know the address of local variables (l_iSumLocalVar, l_iLocalVar1 and l_iLocalVar2)? These variables are not the pointers that they store the address from where they have to fetch the value. My question is wrt the stack above.

Question 2) If this function further calls any other function how would the stack behave to it? As I know, the stack would get divided into itself further. If this is true how the local variables of the callee function gets hidden from the called function. Basically how the local variables maintains the scope rules?

I know these could be very basic questions but some how I could not think an answer to these.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Bhupesh Pant
  • 4,053
  • 5
  • 45
  • 70

4 Answers4

6

Firstly, it is not "Windows" that uses stack for local variables. It has absolutely nothing to do with "Windows", or with any other OS for that matter. It is your compiler that does that. Nobody forces your compiler to use system stack for that purpose, but normally this is the simplest and most efficient way to implement local variables.

Secondly, compilers use stacks to store local variables (be that system-provided stacks or compiler-implemented stack) simply because stack-like storage matches the language-mandated semantics of local variables very precisely. The storage duration of local variables is defined by their declarative regions (blocks) which strictly nest into each other. This immediately means that storage durations of local variables follow the LIFO principle: last in - first out. So, using a stack - a LIFO data structure - for allocating objects with LIFO storage duration is the first and the most natural thing that comes to mind.

Local variables are typically addressed by their offset from the beginning of the currently active stack frame. The compiler knows the exact offset of each local variable at compile time. The compiler generates the code that will allocate the stack frame for the current function by: 1) memorizing the current position of the stack pointer when the function is entered (let's say it is memorized in register R1) and 2) moving the current stack pointer by the amount necessary to store all local variables of the function. Once the stack frame is allocated in this fashion, your local variables l_iLocalVar1, l_iLocalVar2 and l_iSumLocalVar will simply be accessed through addresses R1 + 6, R1 + 10 and R1 + 14 (I used arbitrary offsets). In other words, local variables are not accessed by specific address values, since these addresses are not known at compile time. Instead local variables are accessed through calculated addresses. They are calculated as some run-time base address value + some compile-time offset value.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I like your answer. one thing that is still not clear is how the scope of the variables are maintained? You said its is taken care with the help of stack and it is popped up when goes out of scope. SO, does that mean that for even a local scope ,i.e. curley brace inside the for loop, a new sub stach is created but the stack pointer is not moved to new stack base address thus making both the previous local variables available along with new variables in new scope curly brace... main() { int l_iVar1 = 2; for(;;) { int l_iVar2 = 5; } } – Bhupesh Pant Jul 08 '13 at 17:02
  • continue.. In my above example of code, I want to point out the scope area inside the for loop where both the variables are visible. Thanks for your time @AndreyT – Bhupesh Pant Jul 08 '13 at 17:07
3
  1. Normally the system calling convention reserves a register to be used as a "stack pointer". Local variable accesses are made relative to this register's value. Since every function must know how much stack space it uses, the compiler emits code to ensure the stack pointer is adjusted correctly for each function's requirements.

  2. The scope of local variables is only enforced by the compiler, since it's a language construct, not anything to do with hardware. You can pass addresses of stack variables to other functions and they'll work correctly.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • A comment on the last sentence of 2.: beware when passing the address of local variables to other functions because those addresses will become invalid when the variables run out of scope. – Kninnug Jul 07 '13 at 17:09
  • @Kninnug: Correct. The rule with pointers to stack variables: You can "pass in", but you can't "pass out." That is, you can pass it as an argument into things you call, but you can't pass it out as a return value because the variables will go out of scope. – Joe Z Jul 07 '13 at 17:24
  • 1
    @JoeZ, that depends on whether or not the function you "pass in" to is going to maintain a reference to your pointer or not. I think your rule is too simplistic. – Carl Norum Jul 07 '13 at 17:26
  • @Kninnug Nah. "passing" a variable is not the same as "returning" a variable. When you push stuff on the call stack (i. e. call a new function with some arguments), it will be preserved until popped (that happens when the last-called function returns). What Carl Norum says is perfectly correct. –  Jul 07 '13 at 17:42
  • 1
    @H2CO3 which is why I said "passing the address of a variable". Carl Norum is indeed correct but a called function could store the address somewhere else after which it might be used when the original function has returned. My point is that you should watch out when you take local addresses and take them beyond their scope. It's not incorrect, just potentially dangerous. – Kninnug Jul 07 '13 at 18:32
1

why is the stack used for local variables?

Well, the stack is an easy to use structure to reserve space for temporary variables. It has the benefit that it will be removed almost automatically when the function returns. An alternative would be to allocate memory from the OS, but then this would cause heavy memory fragmentation. The stack can be easily allocated as well as freed again, so it is a natural choice.

Devolus
  • 21,661
  • 13
  • 66
  • 113
  • "An alternative would be to allocate memory from the OS" - huh? Where do you think the memory for the stack comes from? –  Jul 07 '13 at 17:42
  • @H2CO3 I meant, that you could use malloc/free calls for allocating the auto variables internally as well, but this would introduce additional overhead. Of ocurse all memory comes from the OS. Te stack is already available without that. – Devolus Jul 07 '13 at 17:54
0

All the variable addresses are relative to the stack pointer that is incremented at each function call or return. Fast easy way to allocate and cleanup memory used by these variables.

Tarik
  • 10,810
  • 2
  • 26
  • 40