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