3.1 Overview of Declarations

A “declaration” specifies the interpretation and attributes of a set of identifiers. A declaration that also causes storage to be reserved for the object or function named by the identifier is called a “definition.” C declarations for variables, functions, and types have this syntax.

Syntax

declaration : declaration-specifiers init-declarator-list opt ;

declaration-specifiers :
storage-class-specifier declaration-specifiers opt
type-specifier declaration-specifiers opt
type-qualifier declaration-specifiers opt

init-declarator-list :
init-declarator
init-declarator-list
, init-declarator

init-declarator :
declarator
declarator
= initializer

Note :

This syntax for declaration is not repeated in the following sections. Syntax in the following sections usually begin with the declarator nonterminal.

The declarations in the init-declarator-list contain the identifiers being named; init is an abbreviation for initializer. The init-declarator-list is a comma-separated sequence of declarators, each of which can have additional type information, or an initializer, or both. The declarator contains the identifiers, if any, being declared. The declaration-specifiers nonterminal consists of a sequence of type and storage-class specifiers that indicate the linkage, storage duration, and at least part of the type of the entities that the declarators denote. Therefore, declarations are made up of some combination of storage-class specifiers, type specifiers, type qualifiers, declarators, and initializers.

In the general form of a variable declaration, type-specifier gives the data type of the variable. The type-specifier can be a compound, as when the type is modified by const, volatile, or one of the special keywords described in “Special Keywords in Declarations”. The declarator gives the name of the variable, possibly modified to declare an array or a pointer type. For example,

int const __far *fp;

declares a variable named fp as a far pointer to a nonmodifiable (const) int value. You can define more than one variable in a declaration by using multiple declarators, separated by commas.

A declaration must have at least one declarator, or its type specifier must declare a structure tag, union tag, or members of an enumeration. Declarators provide any remaining information about an identifier. A declarator is an identifier that can be modified with brackets ([ ]), asterisks (*), or parentheses ( ( ) ) to declare an array, pointer, or function type, respectively. When you declare simple variables (such as character, integer, and floating-point items), or structures and unions of simple variables, the declarator is just an identifier. “Declarators and Variable Declarations” discusses declarators.

All definitions are implicitly declarations, but not all declarations are definitions. For example, variable declarations that begin with the extern storage-class specifier are “referencing,” rather than “defining” declarations. If an external variable is to be referred to before it is defined, or if it is defined in another source file from the one where it is used, an extern declaration is necessary. Storage is not allocated by “referencing” declarations, nor can variables be initialized in declarations.

A storage class or a type (or both) is required in variable declarations. Only one storage-class specifier is allowed in a declaration and not all storage-class specifiers are permitted in every context. The storage-class specifier of a declaration affects how the declared item is stored and initialized, and which parts of a program can reference the item. The storage-class-specifier nonterminals defined in C include: auto, extern, register, static, and typedef. All the storage-class-specifier nonterminals except typedef are discussed in “Storage Classes”. See “Typedef Declarations” for information about typedef.

The location of the declaration within the source program and the presence or absence of other declarations of the variable are important factors in determining the lifetime of variables. There can be multiple redeclarations but only one definition. However, a definition can appear in more than one translation unit. For objects with internal linkage, this rule applies separately to each translation unit, because internally linked objects are unique to a translation unit. For objects with external linkage, this rule applies to the entire program. See “Understanding Lifetime, Scope, Visibility, and Linkage” for more information about visibility.

Type specifiers provide some information about the data types of identifiers. The default type specifier is int. Type specifiers are discussed in “Type Specifiers”. Type specifiers may also define type tags, structure and union component names, and enumeration constants. Enumerations, structures, and unions are discussed later in this chapter beginning on topic .

There are two type-qualifier nonterminals: const and volatile. These qualifiers specify additional properties of types that are relevant only when accessing objects of that type through l-values. For more information on const and volatile, see “Type Qualifiers”. For a definition of l-values, see topic .