HPlogo HP C/HP-UX Reference Manual: Version A.05.55.02 > Chapter 3 Data Types and Declarations

Structure and Union Specifiers

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

A structure specifier indicates an aggregate type consisting of a sequence of named members. A union specifier defines a type whose members begin at offset zero from the beginning of the union.

Syntax

struct-or-union specifier ::=
struct-or-union [identifier] { struct-declaration-list }
struct-or-union identifier

struct-or-union ::=
struct
union

struct-declaration-list ::=
struct-declaration
struct-declaration-list struct-declaration

struct-declaration ::=
specifier-qualifier-list struct-declarator-list;

specifier-qualifier-list ::=
type-specifier [specifier-qualifier-list]
type-qualifier [specifier-qualifier-list]

struct-declarator-list ::=
struct-declarator
struct-declarator-list struct-declarator

struct-declarator ::=
declarator
[declarator] : constant-expression

Description

A structure is a named collection of members. Each member belongs to a name space associated with the structure. Members in different structures can have the same names but represent different objects.

Members are placed in physical storage in the same order as they are declared in the definition of the structure. A member's offset is the distance from the start of the structure to the beginning of the member. The compiler inserts pad bytes as necessary to insure that members are properly aligned. For example, if a char member is followed by a float member, one or more pad bytes may be inserted to insure that the float member begins on an appropriate boundary.

Unions are like structures except that all members of a union have a zero offset from the beginning of the union. In other words, the members overlap. Unions are a way to store different type of objects in the same memory location.

A declarator for a member of a structure or union may occupy a specified number of bits. This is done by following the declarator with a colon and a constant non-negative integral expression. The value of the expression indicates the number of bits to be used to hold the member. This type of member is called a bit-field. Only integral type specifiers are allowed for bit-field declarators.

In structures, bit-fields are placed into storage locations from the most significant bits to the least significant bits. Bit-fields that follow one another are packed into the same storage words, if possible. If a bit-field will not fit into the current storage location, it is put into the beginning of the next location and the current location is padded with an unnamed field.

A colon followed by an integer constant expression indicates that the compiler should create an unnamed bit-field at that location. In addition, a colon followed by a zero indicates that the current location is full and that the next bit-field should begin at the start of the next storage location.

Although bit-fields are permitted in unions (ANSI mode only), they are just like any other members of the union in that they have a zero offset from the beginning of the union. That is, they are not packed into the same word, as in the case of structures. The special cases of unnamed bit-fields and unnamed bit-fields of length zero behave differently with unions; they are simply unnamed members that cannot be assigned to.

The unary address operator (&) may not be applied to bit-fields. This implies that there cannot be pointers to bit-fields nor can there be arrays of bit-fields.

Refer to Chapter 10 “HP C/HP-UX Implementation Topics ” for more information on bit-fields.

Structure and Union Tags

Structures and unions are declared with the struct or union keyword. You can follow the keywords with a tag that names the structure or union type much the same as an enum tag names the enumerated type. (Refer to “Enumeration ” for information on enumerated types.) Then you can use the tag with the struct or union keyword to declare variables of that type without re-specifying member declarations. A structure tag occupies a separate name space reserved for tags. Thus, a structure tag may have the same spelling as a structure member or an ordinary identifier. Structure tags also obey the normal block scope associated with identifiers. Another tag of the same spelling in a subordinate block may hide a structure tag in an outer block.

A struct or union declaration has two parts: the structure body, where the members of the structure are declared (and possibly a tag name associated with them); and a list of declarators (objects with the type of the structure).

Either part of the declaration can be empty. Thus, you can put the structure body declaration in one place, and use the struct type in another place to declare objects of that type.

For example, consider the following declarations:

struct s1 {
int x;
float y;
};

struct s1 obj1, *obj2;

The first example declares only the struct body and its associated tag name. The second example uses the struct tag to declare two objects — obj1 and obj2. They are, respectively, a structure object of type struct s1 and a pointer object, pointing to an object of type struct s1.

This allows you to separate all the struct body declarations into one place (for example, a header file) and use the struct types elsewhere in the program when declaring objects.

Consider the following example:

struct examp {
float f; /* floating member */
int i; /* integer member */
}; /* no declaration list */

In this example, the structure tag is examp and it is associated with the structure body that contains a single floating-point quantity and an integer quantity. Note that no objects are declared after the definition of the structure's body; only the tag is being defined.

A subsequent declaration may use the defined structure tag:

struct examp x, y[100];

This example defines two objects using type struct examp. The first is a single structure named x and the second, y, is an array of structures of type struct examp.

Another use for structure tags is to write self-referential structures. A structure of type S may contain a pointer to a structure of type S as one of its members. Note that a structure can never have itself as a member because the definition of the structure's content would be recursive. A pointer to a structure is of fixed size, so it may be a member. Structures that contain pointers to themselves are key to most interesting data structures. For example, the following is the definition of a structure that is the node of a binary tree:

struct node {
float data; /* data stored at the node */
struct node *left; /* left subtree */
struct node *right; /* right subtree */
};

This example defines the shape of a node type of structure. Note that the definition contains two members (left and right) that are themselves pointers to structures of type node.

The C programming rule that all objects must be defined before use is relaxed somewhat for structure tags. A structure can contain a member that is a pointer to an as yet undefined structure. This allows for mutually referential structures:

struct s1 { struct s2 *s2p; };
struct s2 { struct s1 *s1p; };

In this example, structure s1 references the structure tag s2. When s1 is declared, s2 is undefined. This is valid.

Example

struct tag1 {
   int m1;
   int   :16;              /* unnamed bit-field */
   int m2 :16;             /* named bit-field; packed into
                           /* same word as previous member */
   int m3, m4;
};                         /* empty declarator list */
union tag2 {
   int u1;
   int    :16;
   int u2:16;              /* bit-field, starts at offset 0 */
   int u3, u4;
} fudge1, fudge2;          /* declarators denoting objects of the union type */

struct tag1 obj1, obj2;    /* use of type "struct tag1", */
                             /* whose body has been declared above */
© Hewlett-Packard Development Company, L.P.