- storage-class-specifier:
- auto
register
static
extern
typedef
Items declared with the
auto or
register specifier have local lifetimes. Items declared with the
static or
extern specifier have global lifetimes.
Since
typedef and
__declspec are semantically different from the other four
storage-class-specifier terminals, they are discussed separately. For specific information on
typedef, see
Typedef Declarations. For specific information on
__declspec, see
Extended Storage-Class Attributes.
The
placement of variable and function declarations within source files
also affects storage class and visibility. Declarations outside all
function definitions are said to appear at the "external level."
Declarations within function definitions appear at the "internal level."
The exact meaning of each storage-class specifier depends on two factors:
- Whether the declaration appears at the external or internal level
- Whether the item being declared is a variable or a function
Storage-Class Specifiers for External-Level Declarations and
Storage-Class Specifiers for Internal-Level Declarations describe the
storage-class-specifier terminals in each kind of declaration and explain the default behavior when the
storage-class-specifier is omitted from a variable.
Storage-Class Specifiers with Function Declarations discusses storage-class specifiers used with functions.
Storage-Class Specifiers for External-Level Declarations
External
variables are variables at file scope. They are defined outside any
function, and they are potentially available to many functions.
Functions can only be defined at the external level and, therefore,
cannot be nested. By default, all references to external variables and
functions of the same name are references to the same object, which
means they have "external linkage." (You can use the
static keyword to override this. See information later in this section for more details on
static.)
Variable
declarations at the external level are either definitions of variables
("defining declarations"), or references to variables defined elsewhere
("referencing declarations").
An external variable declaration
that also initializes the variable (implicitly or explicitly) is a
defining declaration of the variable. A definition at the external level
can take several forms:
- A variable that you declare with the static storage-class specifier. You can explicitly initialize the static variable with a constant expression, as described in Initialization.
If you omit the initializer, the variable is initialized to 0 by
default. For example, these two statements are both considered
definitions of the variable k.
static int k = 16;
static int k;
- A variable that you explicitly initialize at the external level. For example, int j = 3; is a definition of the variable j.
In variable declarations at the external level (that is, outside all functions), you can use the
static or
extern storage-class specifier or omit the storage-class specifier entirely. You cannot use the
auto and
register storage-class-specifier terminals at the external level.
Once
a variable is defined at the external level, it is visible throughout
the rest of the translation unit. The variable is not visible prior to
its declaration in the same source file. Also, it is not visible in
other source files of the program, unless a referencing declaration
makes it visible, as described below.
The rules relating to
static include:
- Variables declared outside all blocks without the static
keyword always retain their values throughout the program. To restrict
their access to a particular translation unit, you must use the static
keyword. This gives them "internal linkage." To make them global to an
entire program, omit the explicit storage class or use the keyword extern (see the rules in the next list). This gives them "external linkage." Internal and external linkage are also discussed in Linkage.
- You
can define a variable at the external level only once within a program.
You can define another variable with the same name and the static storage-class specifier in a different translation unit. Since each static
definition is visible only within its own translation unit, no conflict
occurs. This provides a useful way to hide identifier names that must
be shared among functions of a single translation unit, but not visible
to other translation units.
- The static storage-class specifier can apply to functions as well. If you declare a function static, its name is invisible outside of the file in which it is declared.
The rules for using
extern are:
- The extern storage-class specifier declares a reference to a variable defined elsewhere. You can use an extern
declaration to make a definition in another source file visible, or to
make a variable visible prior to its definition in the same source file.
Once you have declared a reference to the variable at the external
level, the variable is visible throughout the remainder of the
translation unit in which the declared reference occurs.
- For an extern
reference to be valid, the variable it refers to must be defined once,
and only once, at the external level. This definition (without the extern storage class) can be in any of the translation units that make up the program.
Example
The example below illustrates external declarations:
/******************************************************************
SOURCE FILE ONE
*******************************************************************/
#include <stdio.h>
extern int i; // Reference to i, defined below
void next( void ); // Function prototype
int main()
{
i++;
printf_s( "%d\n", i ); // i equals 4
next();
}
int i = 3; // Definition of i
void next( void )
{
i++;
printf_s( "%d\n", i ); // i equals 5
other();
}
/******************************************************************
SOURCE FILE TWO
*******************************************************************/
#include <stdio.h>
extern int i; // Reference to i in
// first source file
void other( void )
{
i++;
printf_s( "%d\n", i ); // i equals 6
}
The two source files in this example contain a total of three external declarations of
i. Only one declaration is a "defining declaration." That declaration,
defines the global variable
i and initializes it with initial value 3. The "referencing" declaration of
i at the top of the first source file using
extern makes the global variable visible prior to its defining declaration in the file. The referencing declaration of
i
in the second source file also makes the variable visible in that
source file. If a defining instance for a variable is not provided in
the translation unit, the compiler assumes there is an
referencing declaration and that a defining reference
appears in another translation unit of the program.
All three functions,
main,
next, and
other, perform the same task: they increase
i and print it. The values 4, 5, and 6 are printed.
If the variable
i
had not been initialized, it would have been set to 0 automatically. In
this case, the values 1, 2, and 3 would have been printed. See
Initialization for information about variable initialization.
Storage-Class Specifiers for Internal-Level Declarations
You can use any of four
storage-class-specifier terminals for variable declarations at the internal level. When you omit the
storage-class-specifier from such a declaration, the default storage class is
auto. Therefore, the keyword
auto is rarely seen in a C program.
1)auto Storage-Class Specifier
The
auto storage-class specifier declares an automatic variable, a variable with a local lifetime. An
auto variable is visible only in the block in which it is declared. Declarations of
auto variables can include initializers, as discussed in
Initialization. Since variables with
auto
storage class are not initialized automatically, you should either
explicitly initialize them when you declare them, or assign them initial
values in statements within the block. The values of uninitialized
auto variables are undefined. (A local variable of
auto or
register storage class is initialized each time it comes in scope if an initializer is given.)
An internal
static variable (a static variable with local or block scope) can be initialized with the address of any external or
static item, but not with the address of another
auto item, because the address of an
auto item is not a constant.
2)The register Storage-Class Specifier
register is used to define local variables that should be stored
in a register instead of RAM. This means that the variable has a maximum size
equal to the register size (usually one word) and cant have the unary '&'
operator applied to it (as it does not have a memory location).
{
register int Miles;
}
Register should only be used for variables that require quick access - such
as counters. It should also be noted that defining 'register' goes not mean
that the variable will be stored in a register. It means that it MIGHT be stored
in a register - depending on hardware and implimentation restrictions.
3)Static - Storage Class
static is the default storage class for
global variables. The two
variables below (
count and
road) both have a static storage class.
static int Count;
int Road;
main()
{
printf("%d\n", Count);
printf("%d\n", Road);
}
|
'static' can also be defined within a function. If this is done, the variable
is initalised at compilation time and retains its value between calls.
Because it is initialsed at compilation time, the initalistation value
must be a constant.
This is serious stuff - tread with care.
void Func(void)
{
static Count=1;
}
|
Here is an
example
There is one very important use for 'static'. Consider this bit of code.
char *Func(void);
main()
{
char *Text1;
Text1 = Func();
}
char *Func(void)
{
char Text2[10]="martin";
return(Text2);
}
|
'Func' returns a pointer to the memory location where 'Text2' starts
BUT Text2 has a storage class of auto and will disappear
when we exit the function and could be overwritten by something else. The
answer is to specify:
static char Text[10]="martin";
|
The storage assigned to 'Text2' will remain reserved for the duration if the
program.
4)Extern - storage Class
extern defines a global variable that is visable to ALL object
modules. When you use 'extern' the variable cannot be initalized as
all it does is point the variable name at a storage location that has
been previously defined.
Source 1 Source 2
-------- --------
extern int count; int count=5;
write() main()
{ {
printf("count is %d\n", count); write();
} }
Count in 'source 1' will have a value of 5. If source 1 changes the
value of count - source 2 will see the new value. Here are some example
source files.
Source 1
Source 2
Storage-Class Specifiers with Function Declarations
You can use either the
static or the
extern storage-class specifier in function declarations. Functions always have global lifetimes.
Microsoft Specific
Function
declarations at the internal level have the same meaning as function
declarations at the external level. This means that a function is
visible from its point of declaration throughout the rest of the
translation unit even if it is declared at local scope.
The visibility rules for functions vary slightly from the rules for variables, as follows:
- A function declared to be static is visible only within the source file in which it is defined. Functions in the same source file can call the static function, but functions in other source files cannot access it directly by name. You can declare another static function with the same name in a different source file without conflict.
- Functions declared as extern are visible throughout all source files in the program (unless you later redeclare such a function as static). Any function can call an extern function.
- Function declarations that omit the storage-class specifier are extern by default.