UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2017 - January 2018

Chapter 3.  Variable declaration

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).

File 1 File 2
1
2
3
4
5
int number = 10;
int main(int argc, char *argv[]) 
{
    return 1;
}
1
2
3
4
5
6
extern int number;
int function() 
{
    number++;
    return number;
}

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:

  1. They cannot be accessed from any other file. Thus, prefixes extern and static cannot be used in the same declaration.

  2. 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:

  1. 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.

  2. 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 <stdio.h>
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.

File 1 File 2
/* 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 <stdio.h>
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.