MiniUnix/usr/doc/c/c3
.ta .5i 1i 1.5i 2i 2.5i 3i
.ul
8. Declarations
.et
Declarations are used within function definitions to specify the interpretation
which C gives to each identifier; they do not necessarily
reserve storage associated with the identifier.
Declarations have the form
.dp 2
declaration:
decl-specifiers declarator-list\*(op \fG;
.ed
The declarators in the declarator-list
contain the identifiers being declared.
The decl-specifiers
consist of at most one type-specifier and at most
one storage class specifier.
.dp 5
decl-specifiers:
type-specifier
sc-specifier
type-specifier sc-specifier
sc-specifier type-specifier
.ed
8.1 Storage class specifiers
.et
The sc-specifiers are:
.dp 4
sc-specifier:
.ft G
auto
static
extern
register
.ed
The
.bd "auto, static,"
and
.bd register
declarations also serve as definitions
in that they cause an appropriate amount of storage to be reserved.
In the \fGextern\fR case
there must be an external definition (see below)
for the given identifiers
somewhere outside the function in which they are declared.
.pg
There are some severe restrictions on
.bd register
identifiers:
there can be at most 3 register identifiers in any function,
and the type of a register identifier can only be
.bd int,
.bd char,
or pointer (not
.bd float,
.bd double,
structure, function, or array).
Also the address-of
operator
.bd &
cannot be applied to such identifiers.
.a
Except for these restrictions
(in return for which one is rewarded with faster, smaller code),
register identifiers behave as if they
were automatic.
In fact implementations of C
are free to treat
.bd register
as synonymous with
.bd auto.
.pg
If the sc-specifier is missing from a declaration, it
is generally taken to be \fGauto\fR.
.ms
8.2 Type specifiers
.et
The type-specifiers are
.dp 6
type-specifier:
\fGint\fR
\fGchar\fR
\fGfloat
\fGdouble
struct \fI{ type-decl-list }\fG
struct \fIidentifier { type-decl-list }\fG
struct \fIidentifier
.ed
The \fGstruct\fR specifier is discussed in \(sc8.5.
If the type-specifier is missing from a declaration,
it is generally taken to be \fGint\fR.
.ms
8.3 Declarators
.et
The declarator-list appearing in a declaration
is a comma-separated sequence of declarators.
.dp 2
declarator-list:
declarator
declarator \fG,\fI declarator-list
.ed
The specifiers in the declaration
indicate the type and storage class of the objects to which the
declarators refer.
Declarators have the syntax:
.dp 6
declarator:
identifier
\fG\**\fI declarator
declarator \fG( )\fI
declarator \fG[ \fIconstant-expression\*(op \fG]
\fG( \fIdeclarator \fG)
.ed
The grouping in this definition is
the same as in expressions.
.ms
8.4 Meaning of declarators
.et
Each declarator is taken to be
an assertion that when a construction of
the same form as the declarator appears in an expression,
it yields an object of the indicated
type and storage class.
Each declarator contains exactly one identifier; it is this identifier that
is declared.
.pg
If an unadorned identifier appears
as a declarator, then it has the type
indicated by the specifier heading the declaration.
.pg
If a declarator has the form
.sp .7
\** D
.sp .7
for D a declarator, then the
contained identifier has the type ``pointer to .^.^.'', where
``^.^.^.^'' is the type which the identifier would have had
if the declarator had been simply D.
.pg
If a declarator has the form
.sp .7
D^(^^)
.sp .7
then the contained identifier has the type
``function returning ...'', where ``^.^.^.^'' is the
type which the identifier would have
had if the declarator had been simply D.
.pg
A declarator may have the form
.sp .7
D[constant-expression]
.sp .3
or
.sp .3
D[^^]
.sp .7
In the first case the constant
expression
is an expression
whose value is determinable at compile time,
and whose type is
.ft G
int.
.ft R
in the second the constant 1 is used.
(Constant expressions are defined precisely in \(sc15.)^^
Such a declarator makes the contained identifier have
type ``array.''
If the unadorned declarator D would
specify a non-array of type ``.^.^.'',
then the declarator
``D[^i^]''
yields a 1-dimensional array with rank \fIi\fR of objects
of type ``.^.^.''.
If the unadorned declarator D would
specify an \fIn^\fR-dimensional array
with rank
.ft I
i\s6\d1\u\s10^\(mu^i\s6\d2\u\s10^\(mu^.^.^.^\(mu^i\s6\dn\u\s10,
.ft R
then the declarator ``D[^i\s6\dn+1\u\s10^]''
yields an (\fIn^\fR+1^)\fR^-dimensional
array with rank
.ft I
i\s6\d1\u\s10^\(mu^i\s6\d2\u\s10^\(mu^.^.^.^\(mu^i\s6\dn\u\s10\
^\(mu^i\s6\dn+1\u\s10\fR.
.pg
An array may be constructed from one of the basic types, from a pointer,
from a structure,
or from another array (to generate a multi-dimensional array).
.pg
Finally, parentheses in declarators do not alter the type
of the contained identifier
except insofar as they alter the binding
of the components of the declarator.
.pg
Not all the possibilities
allowed by the syntax above are actually
permitted.
The restrictions are as follows:
functions may not return
arrays, structures or functions,
although they may return pointers to such things;
there are no arrays of functions, although
there may be arrays of pointers to functions.
Likewise a structure may not contain a function,
but it may contain a pointer to a function.
.pg
As an example, the declaration
.sp .7
.bG
int i, \**ip, f^(^^), \**fip(^^), (\**pfi)^(^^);
.eG
.sp .7
declares an integer \fIi\fR,
a pointer \fIip\fR to an integer,
a function \fIf\fR returning an integer,
a function \fIfip\fR returning a pointer to an integer,
and a pointer \fIpfi\fR to a function which
returns an integer.
Also
.sp .7
.bG
float fa[17], \**afp[17];
.eG
.sp .7
declares an array of \fGfloat\fR numbers and an array of
pointers to \fGfloat\fR numbers.
Finally,
.sp .7
.bG
static int x3d[3][5][7];
.sp .7
.eG
declares a static three-dimensional array of integers,
with rank 3\(mu5\(mu7.
In complete detail, \fIx3d\fR is an array of three items:
each item is an array of five arrays;
each of the latter arrays is an array of seven
integers.
Any of the expressions ``x3d'', ``x3d[^i^]'', ``x3d[^i^][^j^]'', ``x3d[^i^][^j^][^k^]''
may reasonably appear in an expression.
The first three have type ``array'',
the last has type \fGint\fR.
.ms
8.5 Structure declarations
.et
Recall that one of the forms for a structure specifier
is
.dp
\fGstruct \fI{ type-decl-list }
.ed
The
.ft I
type-decl-list
.ft R
is a sequence of type declarations for the members of the structure:
.dp 3
type-decl-list:
type-declaration
type-declaration type-decl-list
.ed
A type declaration is just a declaration which does not
mention a storage class (the storage class ``member of
structure'' here being understood by context).
.dp 2
type-declaration:
type-specifier declarator-list \fG;
.ed
Within the structure, the objects declared
have addresses which increase as their declarations
are read left-to-right.
Each component of a structure
begins on an addressing boundary appropriate
to its type.
On the \s8PDP\s10-11 the only requirement is that non-characters
begin on a word boundary; therefore, there may
be 1-byte, unnamed holes in a structure,
and all structures
have an even length in bytes.
.pg
Another form of structure specifier is
.dp 1
\fGstruct \fIidentifier { type-decl-list }
.ed
This form is the same as the one just discussed,
except that the identifier is remembered
as the
.ft I
structure tag
.ft R
of the structure specified by the list.
A subsequent declaration may then be given
using the structure tag but without the list,
as in the third form of structure specifier:
.dp
\fGstruct \fIidentifier
.ed
Structure tags allow definition of self-referential
structures; they also
permit the long part of the declaration to be
given once and used several times.
It is however absurd to declare a structure
which contains an instance of
itself, as distinct from a pointer to an instance of itself.
.pg
A simple example of a structure declaration, taken from
\(sc16.2 where its use is illustrated more fully, is
.dp 6
.bG
struct tnode {
char tword[20];
int count;
struct tnode \**left;
struct tnode \**right;
};
.ed
.eG
which contains an array of 20 characters, an integer, and two pointers
to similar structures.
Once this declaration has been given, the following
declaration makes sense:
.sp .7
.bG
struct tnode s, \**sp;
.br
.eG
.sp .7
which declares
\fIs\fR to be a structure of the given sort
and \fIsp\fR to be a pointer to a structure
of the given sort.
.pg
The names of structure members and structure tags may
be the same as ordinary variables, since a distinction
can be made by context.
However, names of tags and members
must be distinct.
The same member name can appear in different
structures only if the two members are of the same type
and if their origin with respect to their structure is the
same;
thus separate structures can share a common initial segment.