Previous | Contents | Index |
Declarations are used to introduce the identifiers used in a program and to specify their important attributes, such as type, storage class, and identifier name. A declaration that also causes storage to be reserved for an object or that includes the body of a function, is called a definition.
Section 4.1 covers general declaration syntax rules, Section 4.2 discusses initialization, and Section 4.3 describes external declarations.
The following kinds of identifiers can be declared. See the associated section for information on specific declaration and initialization syntax. Functions are discussed in Chapter 5.
Preprocessor macros created with the #define directive are not declarations. Chapter 8 has information on creating macros with preprocessor directives. |
The general syntax of a declaration is as follows:
declaration:
|
declaration-specifiers:
|
init-declarator-list:
|
init-declarator:
|
Note the following items about the general syntax of a declaration:
Consider the following example:
volatile static int data = 10; |
This declaration shows a qualified type (a data type with a type qualifier---in this case, int qualified by volatile), a storage class (static), a declarator (data), and an initializer (10). This declaration is also a definition, because storage is reserved for the data object data.
The previous example is simple to interpret, but complex declarations are more difficult. See your platform-specific DEC C documentation for more information about interpreting C declarations.
The following semantic rules apply to declarations:
Storage Allocation
Storage is allocated to a data object in the following circumstances:
Initializers provide an initial value for objects, and follow this syntax:
initializer:
|
initializer-list:
|
Initialization of objects of each type is discussed in the following sections, but a few universal constraints apply to all initializations in C:
struct t1 { int i; double d; }; union t2 { int i; double d; }; struct t3 { struct t1 s; union t2 u; }; struct t3 st[] = { /* complete initializer */ 1, 2, 0, 4, 0, 0, 7, 0, 0 }; |
s u ------ - st[0]: 1, 2.0, 0 st[1]: 4, 0.0, 0 st[2]: 7, 0.0, 0 |
struct t3 st[] = { /* partial initializer */ 1, 2, 0, 4, 0, 0, 7 }; struct t3 st[] = { /* nested and complete initializers */ {1, 2, 0}, {4, 0, 0}, {7, 0, 0} }; struct t3 st[] = { /* nested and partial initializers */ {1, 2}, {4}, {7} }; |
C has historically allowed initializers to be optionally surrounded by extra braces (to improve formatting clarity, for instance). These initializers are parsed differently depending on the type of parser used. DEC C uses the parsing technique specified by the ANSI standard, known as the top-down parse. Programs depending on a bottom-up parse of partially braced initializers can yield unexpected results. The compiler generates a warning message when it encounters unnecessary braces in common C compatibility mode or when the error-checking compiler option is specified on the command line.
See Section 4.9 for a description of initializers with designations
for arrays and structures.
4.3 External Declarations
An object declaration outside of a function is called an external declaration. Contrast this with an internal declaration, which is a declaration made inside a function or block; the declaration is internal to that function or block, and is visible only to that function or block. The compiler recognizes an internally declared identifier from the point of the declaration to the end of the block.
If an object's declaration has file scope and an initializer, the declaration is also an external definition for the object. A C program consists of a sequence of external definitions of objects and functions.
Any definition reserves storage for the entity being declared. For example:
float fvalue = 15.0; /* external definition */ main () { int ivalue = 15; /* internal definition */ } |
External data declarations and external function definitions take the same form as any data or function declaration (see Chapter 5 for standard function declaration syntax), and must follow these rules:
An external function can be called without previously declaring it in C, but this construction is not recommended because of the loss of type checking and subsequent susceptibility to bugs. If such a function call is made, the compiler will treat the function as if an external declaration of type int appeared in the block containing the call. For example:
Here, the compiler will behave as if the declaration extern int x(); appeared within the function1 definition block. |
The first declaration of an identifier in a compilation unit must specify, explicitly or by the omission of the static keyword, whether the identifier is internal or external. For each object, there can be only one definition. Multiple declarations of the same object may be made, as long as there are no conflicting or duplicate definitions for the same object.
An external object may be defined with either an explicit initialization or a tentative definition. A declaration of an object with file scope, without an initializer, and with a storage-class specifier other than static is a tentative definition. The compiler will treat a tentative definition as the object's only definition unless a complete definition for the object is found. As with all declarations, storage is not actually allocated until the object is defined.
If a compilation unit contains more than one tentative definition for an object, and no external definition for the object, the compiler treats the definition as if there were a file scope declaration of the object with an initializer of zero, with composite type as of the end of the compilation unit. See Section 2.7 for a definition of composite type.
If the declaration of an object is a tentative definition and has
internal linkage, the declared type must not be an incomplete type. See
Section 2.9 for examples of tentative definitions.
4.4 Declaring Simple Objects
Simple objects are objects with one of the basic data types. Therefore, a simple object can have an integral or floating-point type. Like all objects, simple objects are named storage locations whose values can change throughout the execution of the program. All simple objects used in a program must be declared.
A simple object declaration can be composed of the following items:
const int *p; /* const qualifies the integer p points to */ int *const p; /* const qualifies the pointer p */ |
An initializer for a simple object consists of an equal sign (=) followed by a single constant expression. For example:
int x = 10; float y = ((12 - 2) + 25); |
Here, the declaration both declares and defines the object x as an integer value initially equal to 10, and declares and defines the floating-point value y with an initial value of 35.
Without an initializer, the initial value of an auto object is undefined. A static object without explicit initialization is automatically initialized to 0. (If the object is a static array or structure, all members are initialized to 0.)
A block scope identifier with external or internal linkage (that is,
declared using the extern or static keywords) cannot include an initializer
in the declaration, because it is initialized elsewhere.
4.4.2 Declaring Integer Objects
Integer objects can be declared with the int, long, short, signed, and unsigned keywords. char can also be used, but only for small values. The following statements are examples of integer declarations:
int x; /* Declares an integer variable x */ int y = 10; /* Declares an integer variable y */ /* and sets y's initial value to 10 */ |
Some of the keywords can be used together to explicitly state the allowed value range. For example:
unsigned long int a; signed long; /* Synonymous with "signed long int" */ unsigned int; |
Consider the range of values an integer object must be capable of
representing when selecting the integral data type for the object. See
Chapter 3 for more information on the size and range of integral
data types.
4.4.3 Declaring Character Variables
Character objects are declared with the char keyword. The following example shows a character declaration with the initialization of a character object:
char ch = 'a'; /* Declares an object ch with an initial value 'a' */ |
In C, character string literals are stored in arrays of type char. See Section 4.7 for more information on
arrays.
4.4.4 Declaring Floating-Point Variables
When declaring floating-point objects, determine the amount of precision needed for the stored object. Single-precision or double-precision objects can be used. For single precision, use the float keyword. For double precision, use the double or long double keywords. For example:
float x = 7.5; double y = 3.141596; |
See your platform-specific DEC C documentation for specific information on the range and precision of floating-point types.
Previous | Next | Contents | Index |