United States |
|
|
||
2.6 Incomplete TypeAn identifier can be initially declared as having an incomplete type. An incomplete type declaration describes the object, but lacks the information needed to determine the object's size. For example, a declaration of an array of unknown size is an incomplete type declaration:
The incomplete type may be completed in a subsequent declaration. Incomplete types are most commonly used when forward referencing arrays, structures, and unions. ( Section 2.12 discusses forward references.) An object of an aggregate type cannot contain a member of an incomplete type; therefore, an aggregate object (a structure or array member) cannot contain itself, because the aggregate type is not complete until the end of its declaration. The following example shows how an incomplete structure type is declared and later completed:
The
void
type is a special case of an incomplete type. It is an incomplete type
that cannot be completed, and is used to signify that a function
returns no value. Section 3.5 has more information on the
void
type.
Compatibility between types refers to the similarity of two types to each other. Type compatibility is important during type conversions and operations. All valid declarations in the same scope that refer to the same object or function must have compatible types. Two types are compatible if they fit any of the following categories:
The following types, which may appear to be compatible, are not:
A composite type is constructed from two compatible types and is compatible with both of the two types. Composite types satisfy the following conditions:
Consider the following file-scope declarations:
They result in the following composite type for the function:
The previous composite type rules apply recursively to types derived
from composite types.
Data objects and functions can be implicitly or explicitly assigned linkage. There are three kinds of linkage:
When more than one declaration of the same object or function is made, linkage is made. The linked declarations can be in the same scope or in different scopes. Externally linked objects are available to any function in any compilation unit used to create the executable file. Internally linked objects are available only to the compilation unit in which the declarations appear. The concept of linkage and the static and extern keywords are related, but not directly. Using the extern keyword in an object's declaration does not guarantee external linkage. The following rules determine the actual linkage of an object or function:
Identifiers other than data objects and functions have no linkage. An identifier declared as a function parameter also has no linkage. The following examples show declarations with different linkages:
In Compaq C, a message is issued if the same object is declared with both internal and external linkage. 2.9 Tentative DefinitionsA declaration of an identifier with file scope, no initializer, and either no storage-class specifier or the static storage-class specifier is a tentative definition. The tentative definition only applies if no other definition of the object appears in the compilation unit, in which case all tentative definitions for an object are treated as if there were only one file scope definition of the object, with an initializer of zero. If a definition for a tentatively defined object is used later in the compilation unit, the tentative definition is treated as a redundant declaration of the object. If the declaration of an identifier for an object is a tentative definition and has internal linkage, the declared type cannot be an incomplete type. Section 2.8 discusses linkage. The following are examples of tentative definitions:
2.10 Storage ClassesStorage classes apply only to data objects and function parameters. However, storage class keywords in C are also used to affect the visibility of functions. Every data object and parameter used in a program has exactly one storage class, either assigned explicitly or by default. There are four storage classes:
An object's storage class determines its availability to the linker and its storage duration. An object with external or internal linkage, or with the storage-class specifier static , has static storage duration, which means that storage for the object is reserved and initialized to 0 only once, before main begins execution. An object with no linkage and without the storage-class specifier static has automatic storage duration; for such an object, storage is automatically allocated on entry to the block in which it is declared, and automatically deallocated on exiting from the block. An automatic object is not initialized. When applied to functions, the storage-class specifier extern makes the function visible from other compilation units, and the storage-class specifier static makes the function visible only to other functions in the same compilation unit. For example:
The following sections describe these storage classes.
The auto class specifies that storage for an object is created upon entry to the block defining the object, and destroyed when the block is exited. This class can be declared only at the beginning of a block, such as at the beginning of a function's body. For example:
When you use an initializer with an auto object (see Section 4.2), the object is initialized each time it is created. Storage is reserved for the object whether the block containing the object is entered through normal processing of the block or through a jump statement into the block. However, if the block is entered through a jump statement, initialization of the object is not guaranteed, and if the object is a variable-length array, storage is not reserved. The auto class is the default for objects with block scope. Objects with the auto class are not available to the linker.
2.10.2 The register ClassThe register class identifies the assigned object as frequently used, suggesting to the compiler that the object should be assigned a register to minimize access time. register is never the default class; it must be explicitly specified. The register class has the same storage duration as the auto class; that is, storage is created for a register object upon entry to the block defining the object, and destroyed when the block is exited.
The
register
class is the only storage class that can be explicitly specified for
function parameters.
The Compaq C compiler uses sophisticated register allocation
techniques that make the use of the
register
keyword unnecessary.
The static class specifies that space for the identifier is maintained for the duration of the program. Static objects are not available to the linker. Therefore, another compilation unit can contain an identical declaration that refers to a different object. A static object can be declared anywhere a declaration may appear in the program; it does not have to be at the beginning of a block, as with the auto class. If a data object is declared outside a function, it has static duration by default---it is initialized only once at the beginning of the program.
Expressions used to initialize
static
objects must be constant expressions. If the object with
static
storage duration is not explicitly initialized, every arithmetic member
of that object is initialized to 0, and every pointer member is
initialized as a null pointer constant. See Section 4.2 for more
information on initializing objects of various data types.
The
extern
class is the default class for objects with file scope.
Objects outside of any function (an external definition) receive the
extern
class storage unless explicitly assigned the
static
keyword in the declaration. The
extern
class specifies the same storage duration as
static
objects, but the object or function name is not hidden from
the linker. Using the
extern
keyword in a declaration results in external linkage in most cases (see
Section 2.8), and results in static duration of the object.
Compaq C provides the following storage-class modifiers: __inline The first three modifiers listed are recognized as valid keywords in all compiler modes on all platforms. They are in the namespace reserved to the C implementation, so it is not necessary to allow them to be treated as user-declared identifiers. They have the same effects on all platforms, except that on OpenVMS VAX systems, the __forceinline modifier does not cause any more inlining than the __inline modifier does. The inline storage-class modifier is supported in relaxed ANSI C mode or if the /ACCEPT=C99_KEYWORDS (OPENVMS) or /ACCEPT=GCCINLINE (OPENVMS) qualifier is specified.
You can use a storage-class specifier and a storage-class modifier in any order. Usually, the modifier is placed after the specifier in the source code. For example:
However, placing the storage-class specifier anywhere other than first is obsolescent.
The following sections describe each of the Compaq C storage-class
modifiers.
The __inline storage-class modifier marks a function for inline expansion. Using __inline on a function definition and prototype tells the compiler that it can substitute the code within the function definition for every call to that function. Substitution occurs at the discretion of the compiler. The __inline storage-class modifier has the same effect as the #pragma inline preprocessor directive, except that #pragma inline attempts to provide inline expansion for all functions in a translation unit, rather than for selected functions (See your platform-specific Compaq C documentation for more information on #pragma inline ). Use the following form to designate a function for inline expansion:
The compiler issues a warning if __inline is used in /STANDARD=PORTABLE mode, because this is an implementation-specific extension. Here is an example of using __inline :
2.11.2 The inline ModifierSimilar to the __inline storage-class modifier, the inline storage-class modifier can be used as a declaration specifier in the declaration of a function. The inline storage-class modifier is supported in relaxed ANSI C mode or if the /ACCEPT=C99_KEYWORDS (OPENVMS) or /ACCEPT=GCCINLINE (OPENVMS) qualifier is specified. With static functions, inline has the same effect as applying __inline or #pragma inline to the function. However, when inline is applied to a function with external linkage, besides allowing calls within that translation unit to be inlined, the inline semantics provide additional rules that also allow calls to the function to be inlined in other translation units or for the function to be called as an external function, at the compiler's discretion:
| |
privacy statement and legal notices |