DEC C
Language Reference Manual


Previous Contents Index

2.8 Linkage

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:


extern int x;          /*  External linkage                        */ 
static int y;          /*  Internal linkage                        */ 
register int z;        /*  Illegal storage-class declaration       */ 
 
main ()                /*  Functions default to external linkage   */ 
{ 
    int w;             /*  No linkage                              */ 
    extern int x;      /*  External linkage                        */ 
    extern int y;      /*  Internal linkage                        */ 
    static int a;      /*  No linkage                              */ 
} 
 
void func1 (int arg1)  /*  arg1 has no linkage                     */ 
{ } 

In DEC C, a message is issued if the same object is declared with both internal and external linkage.

2.9 Tentative Definitions

A 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:


int i1 = 1;    /* Standard definition with external linkage      */ 
int i4;        /* Tentative definition with external linkage     */ 
static int i5; /* Tentative definition with internal linkage     */ 
int i1;        /* Valid tentative definition, refers to previous */ 
               /* i1 declaration                                 */ 

2.10 Storage Classes

Storage 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:


static int tree(void); 

The following sections describe these storage classes.

2.10.1 The auto Class

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:


auto int a;        /*  Illegal -- auto must be within a block  */ 
 
main () 
{ 
    auto int b;               /*  Valid auto declaration   */ 
    for (b = 0; b < 10; b++) 
      { 
        auto int a = b + a;   /*   Valid inner block declaration    */ 
      } 
} 

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.

The auto class is the default for objects with block scope. Objects with the auto class are not available to the linker.

Note

Entering an enclosed block suspends, but does not end, execution of the enclosing block. Calling a function from within a block suspends, but does not end, execution of the block containing the call. Automatic objects with reserved storage maintain their storage in these cases.

2.10.2 The register Class

The 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 DEC C compiler uses sophisticated register allocation techniques that make the use of the register keyword unnecessary.

2.10.3 The static Class

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.

2.10.4 The extern Class

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.

2.11 Storage-Class Modifiers

DEC C for OpenVMS Systems provides support for the storage-class modifiers noshare , readonly , and _align as VAX C keywords. The recognition of these three storage-class modifiers as keywords (along with the other VAX C specific keywords) is controlled by a combination of the compiler mode and the /ACCEPT command-line qualifier:

DEC C also provides the __inline and __forceinline storage-class modifiers. These 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.

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:


extern  noshare  int  x; 
 
   /*  Or, equivalently...*/ 
 
int  noshare  extern  x; 

The following sections describe each of the DEC C storage-class modifiers.

2.11.1 The noshare Modifier

The noshare storage-class modifier is applicable to OpenVMS systems only. It is not applicable to DIGITAL UNIX systems and is ignored.

The noshare storage-class modifier assigns the attribute NOSHR to the program section of the variable. Use this modifier to allow other programs, used as shareable images, to have a copy of the variable's psect without the shareable images changing the variable's value in the original psect.

When a variable is declared with the noshare modifier and a shared image that has been linked to your program refers to that variable, a copy is made of the variable's original psect to a new psect in the other image. The other program may alter the value of that variable within the local psect without changing the value still stored in the psect of the original program.

For example, if you need to establish a set of data that will be used by several programs to initialize local data sets, then declare the external variables using the noshare specifier in a DEC C program. Each program receives a copy of the original data set to manipulate, but the original data set remains for the next program to use. If you define the data as extern without the noshare modifier, a copy of the psect of that variable is not made; each program would be allowed access to the original data set, and the initial values would be lost as each program stores the values for the data in the psect. If the data is declared as const or readonly , each program is able to access the original data set, but none of the programs can then change the values.

You can use the noshare modifier with the static , extern , globaldef , and globaldef {"name"} storage-class specifiers. For more information about the possible combinations of specifiers and modifiers, and the effects of the storage-class modifiers on program-section attributes, see the DEC C User's Guide for OpenVMS Systems.

You can use noshare alone, which implies an external definition of storage class extern . Also, when declaring variables using the extern and globaldef {"name"} storage-class specifiers, you can use noshare , const , and readonly , together, in the declaration. If you declare variables using the static or the globaldef specifiers, and you use both of the modifiers in the declaration, the compiler ignores noshare and accepts const or readonly .

2.11.2 The readonly Modifier

The readonly storage-class modifier, like the const data-type qualifier, assigns the NOWRT attribute to the variable's program section; if used with the static or globaldef specifier, the variable is stored in the $CODE psect, which has the NOWRT attribute by default.

You can use both the readonly and const modifiers with the static , extern , globaldef , and globaldef {"psect"} storage-class specifiers.

In addition, both the readonly modifier and the const modifier can be used alone. When you specify these modifiers alone, an external definition of storage class extern is implied.

The const modifier restricts access to data in the same manner as the readonly modifier. However, in the declaration of a pointer, the readonly modifier cannot appear between the asterisk and the pointer variable to which it applies.

The following example shows the similarity between the const and readonly modifiers. In both instances, the point variable represents a constant pointer to a nonconstant integer.


readonly int * point; 
 
int * const point; 

Note

For new program development, Digital recommends that you use the const modifier, because const is ANSI C compliant and readonly is not.

2.11.3 The _align Modifier

The _align storage-class modifier aligns objects of any of the DEC C data types on a specified storage boundary. Use the _align modifier in a data declaration or definition.

For example, to align an integer on the next quadword boundary, you can use any of the following declarations:


int  _align( QUADWORD )  data; 
int  _align( quadword )  data; 
int  _align( 3 )  data; 

When specifying the boundary of the data alignment, you can either use a predefined constant or specify an integer value that is a power of 2. These constants, or explicit powers of 2, tell DEC C the number of bytes to pad in order to align the data. In the previous example, int _align ( 3 ) specifies an alignment of 2^3 bytes, which is 8 bytes---a quadword of memory.

Table 2-1 presents all the predefined alignment constants, their equivalent power of 2, and their equivalent number of bytes.

Table 2-1 Predefined Alignment Constants
Constant Power of
2
Number of
Bytes
BYTE or
byte
0 1
WORD or
word
1 2
LONGWORD or
longword
2 4
QUADWORD or
quadword
3 8
OCTAWORD or
octaword
4 16
PAGE or
page
16 (ALPHA ONLY)
9 (VAX ONLY)
65,536 (ALPHA ONLY)
512 (VAX ONLY)

2.11.4 The __inline Modifier

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 DEC C documentation for more information on #pragma inline ).

Use the following form to designate a function for inline expansion:

__inline [type] function_definition

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 :


/* prototype */ 
 
__inline int x (float y); 
 
 
 
/* definition */ 
 
__inline int x (float y) 
 
{ 
   return (1.0); 
} 


Previous Next Contents Index