Until now we have used identifiers and scopes without really caring to define precisely the details. This is unavoidable at the beginning, some things must be left unexplained at first, but it is better to fill the gaps now.
An identifier in C can denote:
an object.
a function
a tag or a member of a structure, union or enum
a typedef
a label
For each different entity that an identifier designates, the identifier can be used (is visible) only within a region of a program called its scope. There are four kinds of scopes in C.
The file scope is built from all identifiers declared outside any block or parameter declaration, it is the outermost scope, where global variables and functions are declared.
A function scope is given only to label identifiers.
The block scope is built from all identifiers that are defined within the block. A block scope can nest other blocks.
The function prototype scope is the list of parameters of a function. Identifiers declared within this scope are visible only within it.
Let's see a concrete example of this:
static int Counter = 780; // file scope
extern void fn(int Counter); // function prototype scope
void function(int newValue, int Counter) // Block scope
if (i == 4)
}
At the point indicated by the arrow, the poor "Counter" identifier has had a busy life:
It was bound to an integer object with file scope
Then it had another incarnation within the function prototype scope
Then, it was bound to the variables of the function 'setCounter' as a parameter
That definition was again "shadowed" by a new definition in an inner block, as a local variable.
The value of "Counter" at the arrow is 78. When that scope is finished its value will be the value of the parameter called Counter, within the function "function".
When the function definition finishes, the file scope is again the current scope, and "Counter" reverts to its value of 780.
The "linkage" of an identifier refers to the visibility to other modules. Basically, all identifiers that appear at a global scope (file scope) and refer to some object are visible from other modules, unless you explicitly declare otherwise by using the "static" keyword.
Problems can appear if you first declare an identifier as static, and later on, you define it as external. For instance:
static void foo(void);
and several hundred lines below you declare:
void foo(void)
Which one should the compiler use? static or not static? That is the question.
Lcc-win32 chooses always non-static, to the contrary of Microsoft's compiler that chooses always static. Note that the behavior of the compiler is explicitly left undefined in the standard, so both behaviors are correct.
|