In Java, accessing fields and methods in an object can be controlled using three scopes: public, private and protected. The C language has much simpler rules to control what is known as the “scope of validity” of a variable.
3.1. Scope of a variable
The “scope of validity” of a variable is composed of those code portions where its content can be accessed and manipulated. These portions typically correspond with different code blocks surrounded by curly braces [“{}”]. For example, when a function invokes another function, a new scope [the invoked function] is created inside another one [the calling function] and disappears upon termination. There are certain variables with intuitive scopes of validity, as for example, the variables defined at the top of a function body. But C allows these scopes to be modified by using declaration prefixes.
3.1.1. Global variables
Every variable declared outside of the functions as a global scope, that is, it can be accessed from any point in the program. The following code shows an example of this situation.
1 2 3 4 5 6 7 8 9 10 11 12 13 | int number; int function[] { number++; return number; } int main[int argc, char *argv[]] { number = 0; function[]; return 0; } |
Variable number
is declared in line 1, outside a function, therefore it is global. Next, the variable is accessed in lines 4 and 10.
But in order to access correctly a global variable, there are two requirements to fulfill derived from the way the compiler processes the files. If the variable is declared in the same file, its declaration must precede its use [the compiler reads each file in one pass]. If
the variable is declared in another file, the same exact definition must be included in the file but with the prefix “extern
” [the compiler only remembers information in the file that is processing].
|
|
Variable number
is defined as global in line 1 of file 1. To access it from file 2, the declaration [without initialization] is replicated in line 1 of file 2 adding the “extern
” prefix. The global variable is accessed in line 4 of file 2. If the first line of this file is omitted, the compiler emits an error that the variable number
has not been declared. If in file 2 the declaration is included without
the “extern
”, the compiler emits the error that a variable has been multiply defined.
Suggestion
Copy and paste the content of the two files in the example in file file1.c
and file2.c
. Compile with the command gcc -Wall -o program file1.c file2.c. Check that the executable with name program
is created and execute it with the command
./program. It should print no message. Make changes in the declaration to check the rules imposed by the compiler.
3.1.2. Static variables
Any variable declaration may have the prefix “static
”. Static variables in C have the following two properties:
They cannot be accessed from any other file. Thus, prefixes “
extern
” and “static
” cannot be used in the same declaration.They maintain their value throughout the execution of the program independently of the scope in which they are defined.
As a consequence of these two properties, the following two cases are derived:
If a static variable is defined outside of the functions it will be accessible only by the code that follows in the file it is declared.
If the static variable is declared in a function, it will only be accessible from the function, and it will keep its value between function executions.
This behavior is counter intuitive because this variables are declared with the rest of variables in a function, but while the latter acquire new values with each execution, the static variables preserve these values between executions.
The following program shows an example of the behavior of a static variable defined in a function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include int function[] { static int number = 10; /* Static variable */ number++; /* Maintains the value of the previous execution */ return number; } int main[] { /* Prints the result of two invocations to function */ printf["%d\n", function[]]; /* Prints 11 */ printf["%d\n", function[]]; /* Prints 12! */ return 0; } |
Line 4 declares the static variable number
and assigns the value 10. Thus, the first time the function is executed, the variable has this value and is increased to 11. This is the value printed when executing line 11. But the function is invoked again, number
maintains its value and therefore is increased to 12, which is the value printed when executing line 12 of the program.
Suggestion
Copy and paste the program in the previous example into a text file in your development environment. Compile it with the command gcc -o program file.c replacing file.c by the name given to the file. Execute the program with the command ./program and check that the result is as expected.
The following example shows the behavior of a static variable when defined outside a function.
/* Global variable */ int number = 10; int main[int argc, char *argv[]] { number++; return 0; } /* Available only from this point in this file */ static int coefficient = 20; void function2[] { number++; coefficient++; } | extern int number; /* Variable coefficient cannot be accessed in this file */ int function[] { number++; return number; } |
The variable number
is declared globally and may be accessed from other file when including its declaration with the “extern
” prefix. However, the variable coefficient
is only accessible from the file in which it is declared and only from that point on [it is not visible in function main
.
3.1.3. Variable shadowing
The problem of “shadowing” appears when a variable is defined in a scope with the same name of another one valid in a higher level scope. The following example shows this situation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include int number = 10; void function[] { int number; /* Colission with global variable*/ number = 20; } int main[int argc, char *argv[]] { function[]; /* Print the value of number */ printf["%d\n", number]; /* Which value is printed? */ return 0; } |
The declarations in lines 2 and 5 are identical but they are included in different scopes [global versus local to a function]. The compiler allows this declaration. But the shadowing appears when the function is executed: the global variable number
cannot be accessed because the name refers to the variable local to the function. Upon function termination, the global variable is no longer “shadowed” and is
accessible again, and its value [10] is printed in line 15.
Suggestion
Copy and paste this program in a text file in your development environment. Add more declarations, compile and execute the program to verify the shadowing policy of the compiler.