[The question is tagged with both Java and C. This answer addresses C. The information here is taken from draft N1570 of the C 2011 standard.]
A variable consists of both an identifier (the name by which it is known) and an object (the storage in memory that holds its value).
The identifier always has some scope, and the object always has some lifetime. (When memory is allocated with malloc
, the storage has lifetime, but there is no identifier, so there is no scope for a name.)
For a variable, the scope of its identifier is determined by where its declaration is in the source code?
- If the declaration is outside any block (a sequence of statements and declarations inside '{' and '}'), it has file scope, and the identifier is visible from the declaration to the end of the translation unit (the source code after preprocessing is done).
- If the declaration is inside a block or inside the parameter declarations of a function definition (not just a declaration), it has block scope, and the identifier is visible from its declaration to the end of the block.
- If the declaration is inside the parameter declarations of a function declaration that is not a definition, it has function prototype scope, and is visible from its declaration to the end of the function declarator.
There are other identifiers besides variable identifiers. The rules for identifiers of functions; tags for structures, unions, and enumerations; and typedef names are the same as for variable identifiers. For labels (used in goto
statements, written as label:
), the identifier has function scope, and it is visible everywhere in the function in which it appears.
There are four storage durations, also called lifetimes: static, thread, automatic, and allocated. The storage duration of an object is affected by the linkage of its identifier, so we need to discuss linkage first. Linkage is a way of making the same identifier in different scopes refer to the same object.
If an identifier for an object or a function at file scope is declared with static
, it has internal linkage. Internal linkage means that any other declarations in the same translation unit will refer to the same object or function.
If an identifier is declared with extern
, the linkage depends on whether there is already a prior declaration visible:
If no prior declaration is visible, the identifier has external linkage. This means any other declarations in the program will refer to the same object or function.
If there is a prior declaration, and it specifies internal or external linkage, the linkage for the current declaration is the same as the prior declaration.
If there is a prior declaration but it does not specify any linkage, the linkage for the current declaration is external.
If a function is declared with no storage-class specifier (typedef
, extern
, static
, _Thread_local
, auto
, or register
), its linkage is as if it were declared with extern
(so it follows the rule above about depending on a prior declaration).
If an object is declared at file scope with no storage-class specifier, its linkage is external.
Otherwise, the identifier has no linkage, so each declaration of it refers to a different entity. This includes an identifier of anything that is not an object or a function (such as a structure tag or a typedef name), a function parameter, and variables declared inside functions without extern
.
Now we can state the rules for storage durations:
If an object is declared with static
and without _Thread_local
, it has static storage duration, and its lifetime is the entire execution of the program.
If an object is declared without _Thread_local
and has external or internal linkage, it has static storage duration.
If an object is declared with _Thread_local
, it has thread storage duration, and its lifetime is the entire execution of the thread for which is is created.
If an object is declared without static
and with no linkage, it has automatic storage duration. If it is not a variable length array, its lifetime is from when execution enters the block it is in until execution of that block ends. (Note that calling a function suspends execution of a block but does not end it.) If it is a variable length array, its lifetime is from when execution reaches the declaration until execution leaves the scope of the declaration.
There is also an allocated storage duration for objects created by routines in the malloc
family, and there is a temporary lifetime that applies to objects created within expressions, but I omit discussion of those since they are not relevant to declarations of named objects.
As you can see, the rules are somewhat complicated. However, you will come to recognize the scopes and lifetimes with practice.