Storage class specifiers
Storage class specifiers are keywords you can use in declarations to control storage duration and linkage. First I'll show you how they fit into the syntax. Then I'll explain their impact on semantics.
Every declaration in C and C++ has two principal parts: a sequence of zero or more declaration specifiers, and a sequence of zero or more declarators, separated by commas.
For example:
A declarator is the name being declared, possibly surrounded by operators such as *, [], (), and (in the case of C++) &. In the previous example, *x[N] is a declarator indicating that x is an "array of N pointers to ..." something, where that something is the type specified in the declaration specifiers.
A declarator may contain more than one identifier. The declarator *x[N] contains two identifiers, x and N. Only one of those identifiers is the one being declared and it's called the declarator-id. The other(s), if any, must have been declared previously. The declarator-id in *x[N] is x.
(The term declarator-id comes from the C++ standard. The C standard makes do without it, but I find it to be a useful concept.)
Some of the declaration specifiers leading up to a declarator can be type specifiers such as int, unsigned, long, const, or a user-defined type name. They can also be storage class specifiers such as extern or static, or function specifiers such as inline.
The type specifiers contribute to the type of the declarator-id; the other specifiers provide non-type information that applies directly to the declarator-id. For example:
static unsigned long int *x[N];
declares x as an object of type "array of N pointers to unsigned long int". The keyword static specifies x's storage class.
The C standard lists five storage class specifiers: auto, extern, register, static, and typedef; however, C considers typedef to be a storage class specifier for syntactic convenience only. C++ doesn't consider typedef as a storage class, so I won't either.
The C++ standard lists mutable as another storage class specifier, but this, too, is more for syntactic convenience than anything else. Unlike the other storage class specifiers, mutable has no impact on storage duration or linkage. I don't consider it a storage class specifier for the purpose of this discussion.
A declaration need not have any storage class specifier and can have no more than one.
Storage duration
The storage duration of an object determines the lifetime of the storage for that object. That is, it determines that part of program execution during which storage for the object must exist. Programmers often use the term storage allocation instead of storage duration, but both the C and C++ standards favor the latter. Only objects have storage duration. Enumeration constants, functions, labels, and types don't.
Each object in C and C++ has one of the following three storage durations: static, automatic, and dynamic. (The C standard lists the third kind of storage duration as "allocated" rather than "dynamic" but then never uses the term after that. I'll call it dynamic.)
An object declared at file scope (in C) or namespace scope (in C++), or declared with the storage class specifier extern or static, has static storage duration. The lifetime of the storage for that object is the entire time that the program is executing.
An object declared at block scope, and without the storage class specifier extern or static, has automatic storage duration. The lifetime of the storage for that object begins upon entry into the block immediately enclosing the object's declaration and ends upon exit from the block. Entering an enclosed block or calling a function suspends, but doesn't end, the execution of a block.
When a program allocates storage for an object by calling an allocation function, such as malloc in C or an operator new in C++, that object has dynamic storage duration. The lifetime of the object's storage lasts until the program passes the address of that object to a corresponding deallocation function, such as free in C or an operator delete in C++.
Table 1 shows how C and C++ determine the storage duration for an object based on the storage class specifier in the object's declaration and the scope in which the declaration appears. For example, the first row (below the column headings) says that an object declared with no storage class specifier at block scope has automatic storage duration, but if it appears at file scope in C or at namespace scope in C++, it has static storage duration. If it appears as a structure or class member, then it has the storage duration of the structure or class object of which it's a member.
None of the entries in Table 1 specify dynamic storage allocation. Unlike objects with static or automatic storage duration, a program can't declare any objects with dynamic storage duration. A program can create them by calling an allocation function; it just can't declare them.
View the full-size image