Jump to 
content
HP.com Home Products and Services Support and Drivers Solutions How to Buy
»  Contact HP

 

HP C

HP C
Language Reference Manual


Previous Contents Index


int f(int (*) (char *), double (*)[3]); 

The previous composite type rules apply recursively to types derived from composite types.

2.8 Linkage

Data objects and functions can be implicitly or explicitly assigned linkage. There are three kinds of linkage:

  • Internal linkage---a declaration referring to a data object or function declared in the same compilation unit, and not known outside the compilation unit.
  • External linkage---a declaration referring to a definition of a data object or function known outside the compilation unit. The definition of the object also has external linkage.
  • No linkage---a declaration declaring a unique data object.

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:

  • An identifier explicitly specified with the auto or register storage class has no linkage.
  • An identifier with block scope and the extern storage-class specification has linkage the same as any visible declaration of the same identifier with file scope. If no such declaration of the object or function is visible, then the object or function has external linkage.
  • The declaration of functions defaults to external linkage. The only other storage class possible for a function is static, which must be specified explicitly, cannot be applied to a block scope function declaration, and results in internal linkage.
  • The file scope declaration of a data object without an explicit storage class specification, or with the extern storage class specified, has external linkage.
  • An identifier with file scope and the static storage class has internal linkage.
  • An identifier with block scope and without the extern storage-class specification has no linkage.

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

  • auto
  • register
  • static
  • extern

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, 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.

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 HP 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

HP C provides the following storage-class modifiers:

  • __inline
  • __forceinline
  • __align
  • 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.

Note

HP C for OpenVMS Systems also provides support for the storage-class modifiers noshare, readonly, and _align as VAX C keywords. For more information about these storage-class modifiers, see the HP C User's Guide for OpenVMS Systems (OPENVMS).

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; 

However, placing the storage-class specifier anywhere other than first is obsolescent.

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

2.11.1 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 HP 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); 
} 

2.11.2 The inline Modifier

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

  • If the inline keyword is used on a function declaration with external linkage, then the function must also be defined in the same translation unit.
  • If all of the file-scope declarations of the function use the inline keyword but do not use the extern keyword, then the definition in that translation unit is called an inline auxiliary definition, and no externally-callable (global) definition is produced by that compilation unit.
    Otherwise, the compilation unit does produce an externally-callable definition.
  • An inline auxiliary definition must not contain a definition of a modifiable object with static storage duration, and it must not refer to an identifier with internal linkage. These restrictions do not apply to the externally-callable definition.
  • As usual, at most one compilation unit in an entire program can supply an externally-callable definition of a given function.
  • Any call to a function with external linkage might be translated as a call to an external function, regardless of the presence of the inline qualifier. It follows from this and the previous point that any function with external linkage that is called must have exactly one externally-callable definition among all the compilation units of an entire program.
  • The address of an inline function with external linkage is always computed as the address of the unique externally-callable definition, never the address of an inline definition.
  • A call to an inline function made through a pointer to the externally-callable definition may still be inlined or translated as a call to an inline definition, if the compiler can determine the name of the function whose address was stored in the pointer.
  • Without the inline keyword, a function definition in a header file produces MULDEF errors at link time, if the header file is included by more than one translation unit. Specifying inline on such a function definition is one way to eliminate these MULDEF errors. See the example ( Section 2.11.2.1).

Note

This section describes the semantics of the C99 Standard inline keyword.

The gcc compiler implements an inline function declaration specifier for functions with external linkage that gives similar capabilites to this C99 inline feature, but the details of usage are somewhat different: essentially, the combination of extern and inline keywords makes an inline definition, instead of the exclusive use of the inline keyword without the extern keyword.

The /ACCEPT=[NO]GCCINLINE qualifier controls which variation of the feature is implemented.

2.11.2.1 Example---Using the inline Function Specifier

Consider the following C code, which results in a multiply defined function identifier (my_max):


$ type t.h 
int my_max (int x, int y) 
{ 
    if (x >= y) 
        return (x); 
    else 
        return (y); 
} 
$ 
$ type a.c 
#include "t.h" 
 
main() 
{ 
    int a =1; 
    int b=2; 
 
    func1(); 
    my_max(func1(a,b),20); 
} 
$ 
$ type b.c 
#include "t.h" 
 
void func1(int p1, int p2) 
{ 
    my_max(p1,p2); 
} 
$ 
$ link a,b 
%LINK-W-MULDEF, symbol MY_MAX multiply defined 
        in module B file DISK$:[TEST.TMP]B.OBJ;4 

One way around this problem is to define the function my_max with the keyword static:


static int my_max (int x, int y) 
{ 
    if (x >= y) 
        return (x); 
    else 
        return (y); 
} 

However, this means there is no globally visible my_max function but, rather, a copy of my_max for each module, each copy with a different address. Therefore, any function pointer comparisons would break.

The ISO C99 solution to this problem is the inline keyword. Adding inline to the header file t.h eliminates the MULDEF errors:


inline int my_max (int x, int y) 
{ 
    if (x >= y) 
        return (x); 
    else 
        return (y); 
} 

This type of function definition, like one specified with the __inline keyword, marks the function for potential inlining by the compiler. One difference, however, is that for an inline function, the compiler creates an inline auxiliary definition of the function, which is associated with the function being declared (my_max in this example). The compiler is then free to do one of the following:

  1. Call the auxiliary function.
  2. Call the global function (my_max). This implies that there must be a global definition of any non-static inline function in one of the modules of the application.
  3. Generate inlined code for the call to my_max.

There can be one and only one global definition for the inline function within an application. There can be one inline auxiliary definition per module, or many prototype declarations of the auxiliary function per module.

You can create a global inline definition by including in one of your modules (such as a.c in our example) a file-scope function declaration that:

  1. Omits the inline keyword:


    #include "t.h" 
    int my_max (int x, int y); 
    

    OR


    #include "t.h" 
    extern int my_max (int x, int y); 
    

  2. Or that specifies the extern storage class with the inline keyword:


    #include "t.h" 
    extern inline int my_max (int x, int y); 
    

Note

Taking the address of an inline function always resolves to the global function, never the auxiliary function.

2.11.3 The __forceinline Modifier

Similar to the __inline storage-class modifier, the __forceinline storage-class modifier marks a function for inline expansion. However, using __forceinline on a function definition and prototype tells the compiler that it must substitute the code within the function definition for every call to that function. (With __inline, such substitution occurs at the discretion of the compiler.)

On OpenVMS VAX systems, the __forceinline storage-class modifier does not cause any more inlining to occur than the __inline modifier does.

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

__forceinline [type]  function_definition

The compiler issues a warning if __forceinline is used in /STANDARD=PORTABLE mode, because this is an implementation-specific extension.

2.11.4 The __align Modifier

The __align and _align storage-class modifiers have the same semantic meaning. The difference is that __align is a keyword in all compiler modes while _align is a keyword only in modes that recognize VAX C keywords. For new programs, using __align is recommended.

The __align storage-class modifier aligns objects of any of the HP 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 HP C the number of bytes to pad in order to align the data. In the previous example, int __align ( 3 ) specifies an alignment of 23 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. Note that for OpenVMS VAX systems, you can specify the constants 0, 1, 2, 3, 4, or 9. For OpenVMS Alpha systems, you can specify any constant from 0 to 16.

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
  5 (ALPHA, I64) 32
  6 (ALPHA, I64) 64
  7 (ALPHA, I64) 128
  8 (ALPHA, I64) 256
  9 512
  10 (ALPHA, I64) 1024
  11 (ALPHA, I64) 2048
  12 (ALPHA, I64) 4096
  13 (ALPHA, I64) 8192
  14 (ALPHA, I64) 16384
  15 (ALPHA, I64) 32768
PAGE or
page
16 (ALPHA, I64)
9 (VAX ONLY)
65,536 (ALPHA, I64)
512 (VAX ONLY)


Previous Next Contents Index

Privacy statement Using this site means you accept its terms
© 2007 Hewlett-Packard Development Company, L.P.