C Crash Course, Part 3: Variable Scope
This is part three of a C programming mini crash-course.
So you’ve learned some C programming and know how to split your program up into multiple files. But how do you communicate between files, and how do you store state between method calls?
Variable scope determines when a variable is visible in the code (i.e. when it can be used). Scope can be:
- Local
- Method
- File
- Global
1. Local
Section titled “1. Local”In general, curly brackets always define a new scope. Like this:
#include <stdint.h>#include <stdio.h>
int main(int argc, char** argv){ int16_t i; int16_t varA = 0; for (i = 0; i < 10; i++) { int16_t varB = 0; varB += i; varA += i; printf("varB: %d\r\n", varB); }
printf("varA: %d\r\n", varA); return 0;}In the code above, varA is visible in all of main(), but varB is
only visible inside the for-loop. If you try to move the line which
prints varB outside of the for-loop, the code will not compile.
2. Method
Section titled “2. Method”Remember the calculator? It looked like this:
#include <stdio.h>
float add(float left, float right){ float value; value = left + right; return value;}
float sub(float left, float right){ float value; value = left - right; return value;}
int main(int argc, char** argv){ float value = 0; value = add(value, 10.5); value = sub(value, 6.3);
printf("Calculator\r\n"); printf("Result: %f\r\n", value); return 0;}The main(), add() and sub() methods all have a variable called
value. These are completely different variables. The value in the
add() method has nothing to do with the value in the sub() method
— you could be tricked into thinking so, because the variables have the
same name, but remember that curly braces define scope.
The parameters to a method also define variables which can be used in
the method. The scope of the left and right parameters to the
add() method is also limited to the method.
3. File
Section titled “3. File”Variables can be defined at file scope. This means that all methods in the file have access to the variable. As a rule of thumb, limit the number of variables at file scope — the main use of file-scope variables is to remember state.
#include <stdint.h>#include <stdio.h>
static uint16_t numberOfBullets;
void cannon_Load(){ numberOfBullets = 10;}
void cannon_Fire(){ if (numberOfBullets > 0) { printf("Bang!\r\n"); numberOfBullets--; } else { printf("Out of bullets\r\n"); }}The code above is a cannon, implemented in Cannon.c. When it is
loaded, it has 10 bullets — this is remembered in the state variable
numberOfBullets. Each call to cannon_Fire() fires a bullet and
modifies the state.
The keyword static in the numberOfBullets definition means that
numberOfBullets is limited to file scope. No other file can access
that variable.
4. Global
Section titled “4. Global”If you take the code from the cannon above, remove the static keyword
in front of numberOfBullets, and then add the same variable name to
another .c file, some compilers will assume that the variable is the
same:
#include <stdint.h>#include <stdio.h>
uint16_t numberOfBullets;
void cannon_Load(){ numberOfBullets = 10;}
void cannon_Fire(){ if (numberOfBullets > 0) { printf("Bang!\r\n"); numberOfBullets--; } else { printf("Out of bullets\r\n"); }}#include <stdint.h>#include <stdio.h>
uint16_t numberOfBullets;
int main(int argc, char** argv){ int16_t i;
cannon_Load();
for (i = 0; i < 20; i++) { cannon_Fire(); printf("NumberOfBullets: %d", numberOfBullets); }}Luckily, most compilers will give an error or a warning that
numberOfBullets has multiple definitions.
Noob programmers are sometimes tempted to use global variables to
communicate between methods implemented in different files (and someone
they thought was a friend told them about the extern keyword). Don’t
do it! It is a path which leads to anger, hate, suffering, and
ultimately the dark side.
Is there some scenario where global variables are justified? No. If
you want other .c files to know how many bullets are left, the correct
way to do it is to add a getNumberOfBullets() method to Cannon.c.