Using call stacks for memory storage
The main reason why C++ is still the preferred language for most game developers is that you handle memory yourself and control the allocation and de-allocation of memory to a great extent. For that reason, we need to understand the different memory spaces that are provided to us. When data is "pushed" onto the stack, the stack grows. As data is "popped" off the stack, the stack shrinks. It is not possible to pop a particular piece of data off the stack without first popping off all data placed on top of it. Think of this as a series of compartments aligned top to bottom. The top of the stack is whatever compartment the stack pointer happens to point to (this is a register).
Each compartment has a sequential address. One of those addresses is kept in the stack pointer. Everything below that magic address, known as the top of the stack, is considered to be on the stack. Everything above the top of the stack is considered to be off the stack. When data is pushed onto the stack, it is placed into a compartment above the stack pointer, and then the stack pointer is moved to the new data. When data is popped off the stack, the address of the stack pointer is changed by moving it down the stack.
Getting ready
You need to have a working copy of Visual Studio installed on your Windows machine.
How to do it...
C++ is probably one of the best programming languages out there and one of the main reasons for that is that it is also a low level language, because we can manipulate memory. To understand memory handling, it is very important to understand how memory stacks work:
- Open Visual Studio.
- Create a new C++ project.
- Select Win32 Console Application.
- Add a source file called
main.cpp
or anything that you want to name the source file. - Add the following lines of code:
#include <iostream> #include <conio.h> using namespace std; int countTotalBullets(int iGun1Ammo, int iGun2Ammo) { return iGun1Ammo + iGun2Ammo; } int main() { int iGun1Ammo = 3; int iGun2Ammo = 2; int iTotalAmmo = CountTotalBullets(iGun1Ammo, iGun2Ammo); cout << "Total ammunition currently with you is"<<iTotalAmmo; _getch(); }
How it works…
When you call the function CountTotalBullets
, the code branches to the called function. The parameters are passed in and the body of the function is executed. When the function completes, a value is returned and the control returns to the calling function.
But how does it really work from a compiler's point of view? When you begin your program, the compiler creates a stack. The stack is a special area of memory allocated for your program in order to hold the data for each function in your program. A stack is a Last In First Out (LIFO) data structure. Imagine a deck of cards; the last card put on the pile will be the first card taken out.
When your program calls CountTotalBullets
, a stack frame is established. A stack frame is an area of the stack set aside to manage that function. This is very complex and different on different platforms, but these are the essential steps:
- The return address of
CountTotalBullets
is put on the stack. When the function returns, it will resume executing at this address. - Room is made on the stack for the return type you have declared.
- All arguments to the function are placed on the stack.
- The program branches to your function.
- Local variables are pushed onto the stack as they are defined.