HP 3000 Manuals

Declarators [ HP C/iX Reference Manual ] MPE/iX 5.0 Documentation


HP C/iX Reference Manual

Declarators 

A declarator introduces an identifier and specifies its type, storage
class, and scope.

Syntax 

     declarator  ::=
          [pointer] direct-declarator 

     direct-declarator  ::=
          identifier 
          (declarator)
          direct-declarator [[constant-expression]]
          direct-declarator (parameter-type-list)
          direct-declarator ([identifier-list])
     pointer  ::=
          * [type-qualifier-list] 
          * [type-qualifier-list] pointer 

     type-qualifier-list  ::=
          type-qualifier 
          type-qualifier-list type-qualifier 

     parameter-type-list ::=
          parameter-list 
          parameter-list , ...

     parameter-list ::=
          parameter-declaration 
          parameter-list , parameter-declaration 

     parameter-declaration ::=
          declaration-specifiers declarator 
          declaration-specifiers [abstract-declarator] 

     identifier-list ::=
          identifier 
          identifier-list , identifier 

Description 

Various special symbols may accompany declarators.  Parentheses change
operator precedence or specify functions.  The asterisk specifies a
pointer.  Square brackets indicate an array.  The constant-expression 
specifies the size of an array.

A declarator specifies one identifier and may supply additional type
information.  When a construction with the same form as the declarator
appears in an expression, it yields an entity of the indicated scope,
storage class, and type.

If an identifier appears by itself as a declarator, it has the type
indicated by the type specifiers heading the declaration.

Declarator operators have the same precedence and associativity as
operators appearing in expressions.  Function declarators and array
declarators bind more tightly than pointer declarators.  You can change
the binding of declarator operators using parentheses.  For example,

       int *x[10];

is an array of 10 pointers to ints.  This is because the array declarator
binds more tightly than the pointer declarator.  The declaration

       int (*x)[10];

is a single pointer to an array of 10 ints.  The binding order is altered
with the use of parentheses.

Pointer Declarators 

If D is a declarator, and T is some combination of type specifiers and
storage class specifiers (such as int), then the declaration T *D
declares D to be a pointer to type T. D can be any general declarator of
arbitrary complexity.  For example, if D were declared as a pointer
already, the use of a second asterisk indicates that D is a pointer to a
pointer to T.

Some examples:

          int *pi;         /* pi:  Pointer to an int                    */
          int **ppi;       /* ppi: Pointer to a pointer to an int       */
          int *ap[10];     /* ap:  Array of 10 pointers to ints         */
          int (*pa)[10];   /* pa:  Pointer to array of 10 ints          */
          int *fp();       /* fp:  Function returning pointer to int    */
          int (*pf)();     /* pf:  Pointer to function returning an int */

The binding of * (pointer) declarators is of lower precedence than either
[ ] (array) or () (function) declarators.  For this reason, parentheses
are required in the declarations of pa and pf.

Array Declarators 

If D is a declarator, and T is some combination of type specifiers and
storage class specifiers (such as int), then the declaration

       T D[constant-expression];

declares D to be an array of type T.

You declare multidimensional arrays by specifying additional array
declarators.  For example, a 3 by 5 array of integers is declared as
follows:

       int x[3][5];

This notation (correctly) suggests that multidimensional arrays in C are
actually arrays of arrays.  Note that the [ ] operator groups from left
to right.  The declarator x[3][5] is actually the same as ((x[3])[5]).
This indicates that x is an array of three elements each of which is an
array of five elements.  This is known as row-major array storage. 

You can omit the constant-expression giving the size of an array under
certain circumstances.  You can omit the first dimension of an array (the
dimension that binds most tightly with the identifier) in the following
cases:

   *   If the array is a formal parameter in a function definition.

   *   If the array declaration contains an initializer.

   *   If the array declaration has external linkage and the definition
       (in another translation unit) that actually allocates storage
       provides the dimension.

Following are examples of array declarations:

     int x[10];           /* x:  Array of 10 integers                */
     float y[10][20];     /* y:  Matrix of 10x20 floats              */
     extern int z[ ];     /* z:  External integer array of undefined */
                          /* dimension */
     int a[ ]={2,7,5,9};  /* a:  Array of 4 integers                 */
     int m[ ][3]= {       /* m:  Matrix of 2x3 integers              */
        {1,2,7},
        {6,6,6}  };

Note that an array of type T that is the formal parameter in a function
definition has been converted to a pointer to type T. The array name in
this case is a modifiable lvalue and can appear as the left operand of an
assignment operator.  The following function will clear an array of
integers to all zeros.  Note that the array name, which is a parameter,
must be a modifiable lvalue to be the operand of the ++ operator.

     void clear(a, n)
     int a[];            /* has been converted to int * */
     int n;              /* number of array elements to clear */
     {
        while(n--)       /* for the entire array */
           *a++ = 0;     /* clear each element to zero */
     }

Function Declarators 

If D is a declarator, and T is some combination of type specifiers and
storage class specifiers (such as int), then the declaration

     T D (parameter-type-list)

or

     T D ([identifier-list])

declares D to be a function returning type T. A function can return any
type of object except an array or a function.  However, functions can
return pointers to functions or arrays.

If the function declarator uses the form with the parameter-type-list, it
is said to be in "prototype" form.  The parameter type list specifies the
types of, and may declare identifiers for, the parameters of the
function.  If the list terminates with an ellipsis (,...), no information
about the number of types of the parameters after the comma is supplied.
The special case of void as the only item in the list specifies that the
function has no parameters.

If a function declarator is not part of a function definition, the
optional identifier-list must be empty.

Function declarators using prototype form are only allowed in ANSI mode.

Functions can also return structures.  If a function returns a structure
as a result, the called function copies the resulting structure into
storage space allocated in the calling function.  The length of time
required to do the copy is directly related to the size of the structure.
If pointers to structures are returned, the execution time is greatly
reduced.  (But beware of returning a pointer to an auto struct--the
struct will disappear after returning from the function in which it is
declared.)

The function declarator is of equal precedence with the array declarator.
The declarators group from left to right.  The following are examples of
function declarators:

     int f();         /* f:   Function returning an int             */
     int *fp();       /* fp:  Function returning pointer to an int  */
     int (*pf)();     /* pf:  Pointer to function returning an int  */
     int (*apf[])();  /* apf: Array of pointers to functions        */
                      /* returning int  */

Note that the parentheses alter the binding order in the declarations of
pf and apf in the above examples.



MPE/iX 5.0 Documentation