We’ve already seen how to use local variables inside a function declaration. However, there are times when we want to be able to share the same variable between several functions. In this situation local variables aren’t the best solution.
There are other cases when we want to use a local variable, but we need the variable to retain its value between calls to the function.
In this chapter we’re going to see how to declare and use variables to support these two situations.
The storage class of a variable
All variables in C have a property called storage class. The storage class defines the lifecycle of a variable. This means that depending on this property, a variable can either be created and destroyed several times during the execution of a program (whenever we call the function or block that defines the variable), or created once and exist until the program finishes.
Variables in MSX-C can belong to one of the two storage classes below:
Automatic (auto) variables
All the variables we’ve seen so far belong to this class. Automatic variables are local to the block that defines them (such as a loop or a function). The program reserves memory for these variables every single time the block that contains them runs, and frees this memory every time the block ends. This means that auto variables can be created and destroyed many times during the execution of a program.
By default the MSX-C compiler treats all variables as automatic, but we can also declare them explicitly by prepending the variable type with the auto keyword:
auto int i;
This doesn’t affect the program at all. The behaviour will be exactly the same whether we use the auto keyword or not, so usually we just omit it.
In most cases we’re fine using just automatic variables, but there will be situations where we need variables to retain their value after each execution of the function or block that contains them. In this cases we use static variables. To define a static variable we just need to prepend the static keyword to the variable definition:
static int i;
The program below illustrates how this works: the rand() function uses an static variable r to generate a pseudo-random number. The value of r persists after each execution of rand() and is reused every time we call the function in order to generate a new number:
What the static keyword does here is tell the compiler: “assign memory for the r variable and don’t reassign that memory to anybody else“. The effect is that the value of r will persist after each call to rand(), effectively creating a pseudo-random number each time we call it:
Important note: In this particular case the example program will probably behave exactly the same without the static keyword. This is because this is a very simple program where nothing changes between calls to rand(), so even if we use an auto variable the program will assign to r the same memory area again and again, effectively retaining the variable value. If this had been a more complex program with a bunch of other variables being created and destroyed then r would most certainly be corrupted at some point. Remember to always declare variables as static when you need to ensure they keep their value between runs of the block or function that contains them.
All the variables we’ve worked with so far have been local and could only be used from inside the function in which they were defined. In contrast to these, it is also possible to define variables that are available from any part of the program, similar to variables in BASIC. We call these global variables.
Based on this, when we refer to the scope of a variable we are talking about the part(s) of the program from where the variable is visible. Variables in MSX-C have the following two scopes, depending on where they are defined:
We’ve seen them already. Every single variable we’ve seen so far has been local because they were defined inside a function. Local variables are available only inside the function that defines them.
As opposed to local variables, global variables (or just globals) are defined outside of all function declarations (usually at the beginning of the source code), and are available from anywhere in the program.
The example program below illustrates how to define and use global variables:
This program uses two global variables defined at the beginning of the source code (Sum and Product) to work around the fact that C functions can only return one value. The addmul() function takes two arguments, and returns their sum and their product in the Sum and Product global variables, respectively. In this way it becomes possible to return more than one value from a single call to a function.
As a general rule it’s best to use globals only when strictly needed. The main reason is that modifying variables at several points in the program increases its complexity, in a way similar to how BASIC programs become more and more complex as the number of variables increases.
In order to distinguish globals from local variables we’ll follow the convention of capitalizing them to avoid confusion.
In this post we’ve learnt about the two storage classes supported by MSX-C: automatic variables are created and destroyed as needed, and static variables are created once and retain their value for the whole duration of the program. We’ve also learnt the concept of variable scope, the difference between local and global variables, and how to define each.
In the next post
The next post starts a short series (maybe 3-4 parts) in which we’ll learn about pointers, which is probably the most interesting feature of the C programming language, though it’s also the most confusing for beginners. The posts after these will deal with text strings and data structures.
This series of articles is supported by your donations. If you’re willing and able to donate, please visit the link below to register a small pledge. Every little amount helps.