You can use any of the four storage-class-specifier nonterminals 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.
The 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 auto-matically, 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.)
A 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.
The register Storage-Class Specifier
The register storage-class-specifier tells the compiler to give an automatic variable storage in a register, if possible. Register storage usually speeds access time and reduces code size. Variables declared with register storage class have the same visibility as auto variables. You cannot apply the unary address-of operator (&) to a register object (see topic for information about operators).
The number of registers that can be used for variable storage is machine-dependent. If no registers are available when the compiler encounters a register declaration, the variable is given auto storage class and stored in memory. Register storage, if available, is only guaranteed for int and pointer types that are the same size as an int. (An initialized local variable of automatic or register storage class is initialized each time it comes in scope if an initializer is given.)
Microsoft Specific
The Microsoft C/C++ version 7.0 16-bit compiler uses the SI and DI registers for registervariables.The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za command-line option to disable these extensions.¨
The 32-bit compiler uses the ESI, EDI, and EBX registers.¨
The static Storage-Class Specifier
A variable declared at the internal level with the static storage-class specifier has a global lifetime but is visible only within the block in which it is declared. For constant strings, using static is useful because it alleviates the overhead of frequent initialization in often-called functions.
If you do not explicitly initialize a static variable, it is initialized to 0 by default. Inside a function, static causes storage to be allocated and serves as a definition. Internal static variables provide private, permanent storage visible to only a single function.
The extern Storage-Class Specifier
A variable declared with the extern storage-class specifier is a reference to a variable with the same name defined at the external level in any of the source files of the program. The internal extern declaration is used to make the external-level variable definition visible within the block. Unless otherwise declared at the external level, a variable declared with the extern keyword is visible only in the block in which it is declared. This example illustrates internal- and external-level declarations:
#include <stdio.h>
int i = 1;
void other( void );
main()
{ /* Reference to i, defined above: */
extern int i;
/* Initial value is zero; a is visible only within main: */
static int a;
/* b is stored in a register, if possible: */
register int b = 0;
/* Default storage class is auto: */
int c = 0;
/* Values printed are 1, 0, 0, 0: */
printf( "%d\n%d\n%d\n%d\n", i, a, b, c );
other();
return;
}
void other( void )
{
/* Address of global i assigned to pointer variable */
static int *external_i = &i;
/* i is redefined; global i no longer visible: */
int i = 16;
/* This a is visible only within the other function: */
static int a = 2;
a += 2;
/* Values printed are 16, 4, and 1: */
printf( "%d\n%d\n%d\n", i, a, *external_i );
}
In this example, the variable i is defined at the external level with initial value 1. An extern declaration in the main function is used to declare a reference to the external-level i. The static variable a is initialized to 0 by default, since the initializer is omitted. The call to printf prints the values 1, 0, 0, and 0.
In the other function, the address of the global variable i is used to initialize the static pointer variable external_i. This works because the global variable has static lifetime, meaning its address does not change during program execution. Next, the variable i is redefined as a local variable with initial value 16. This redefinition does not affect the value of the external-level i, which is hidden by the use of its name for the local variable. The value of the global i is now accessible only indirectly within this block, through the pointer external_i. Attempting to assign the address of the auto variable i to a pointer does not work, since it may be different each time the block is entered. The variable a is declared as a static variable and initialized to 2. This a does not conflict with the a in main, since static variables at the internal level are visible only within the block in which they are declared.
The variable a is increased by 2, giving 4 as the result. If the other function were called again in the same program, the initial value of a would be 4, since internal static variables keep their values when the program exits and then reenters the block in which they are declared.