More on Using the Stack

Now it's time to get back to our analysis of the use of the stack in storing information needed during execution of a function. The next statement in our example program (Figure 5.5 on page 235) is Result = (First + Second) / 2;. Since we've assumed that First is 2, and Second is 4, the value of Result will be (4+2)/2, or 3. After this statement is executed, the stack looks like Figure 5.22.

Figure 5.22. The stack after the initialization of Result


Finally, at the end of the function, the stack pointer will be incremented to point to the stored return address. Then the return instruction will reload the program counter with the stored return address, which in this case is 10001005. Then the value of Result will be made available to the calling function and the stack pointer will be adjusted so the stack looks as it did before we called Average.

After the return, the stack will be empty as we no longer need the arguments, the auto variable Result, or the return address from the Average function. Figure 5.23 shows what the stack looks like now.

Figure 5.23. The stack after exiting from Average


Do not be fooled by the casual statement "the stack is empty". That means only that the stack pointer (esp) is pointing to the same place it was when we started our excursion into the Average function; namely, 20001ffe. The values that were stored in the memory locations used by Average for its auto variables haven't been erased by changing the stack pointer. This illustrates one very good reason why we can't rely on the values of auto variables until they've been initialized; we don't know how the memory locations they occupy might have been used previously.

The previous discussion of how arguments are copied into local variables when a function is called applies directly to our Average function. If we try to change the input arguments, we will change only the copies of those arguments on the stack and the corresponding variables in the calling function won't be altered.[32] That's perfectly acceptable here, since we don't want to change the values in the calling function; we just want to calculate their average and provide the result to the calling function. An argument that is handled this way is called a value argument, as its value is copied into a newly created variable in the called function, rather than allowing the called function access to the "real" argument in the calling function.[33]

[32] Actually, it's generally a good idea not to change the values of arguments, even value arguments. Although this is legal, it tends to confuse programmers who read your code later as they often make the implicit assumption that arguments have the same value throughout a function.

[33] It's also possible to define a function that has access to an actual variable in the calling function; we'll see how and when to do that at the appropriate time.

One thing we haven't really discussed here is how the return value gets back to the caller. One way is to store it in a register, which is then available to the calling routine after we get back. This is a very easy and fast way to pass a return value back to the caller. However, it has a drawback: a register can hold only one value of 32 bits. Sometimes this is not enough, in which case another mechanism will be used. However, the compiler takes care of these details for us, so we don't have to worry about them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset