Structures, Unions, and Bit-Fields

Một phần của tài liệu IT training c pocket reference c syntax and fundamentals prinz kirch prinz 2002 11 30 1 (Trang 36 - 39)

Different data items that make up a logical unit are generally grouped together in a record. The structure of a record—i. e., the names, types, and order of its components—is represented in C by a structure type .

The components of a record are called the members of the structure. Each member can be of any type. The type specifier begins with the keyword struct; for example:

struct article { char name[40];

int quantity;

double price;

};

This example declares a structure type with three members. The identifier article is the tag of the structure, and name, quantity, and price are the names of its members. Within the scope of a structure declaration, variables can be declared with the structure type:

struct article a1, a2, *pArticle, arrArticle[100];

a1 and a2 are variables of type structarticle, and pArticle is a pointer to an object of type struct article. The array arrArticle has 100 elements of type struct article.

Structure variables can also be declared simultaneously with the structure type definition. If no further reference is made to a structure type, then its declaration need not include a tag. For example:

struct {unsigned char character, attribute;}

xchar, xstr[100];

The structure type defined here has the members character and attribute, both of which have the type unsigned char. The variable xchar and the elements of the array xstr have the type of the new tagless structure.

The members of a structure variable are located in memory in order of their declaration within the structure. The address of the first member is identical to the address of the entire structure. The addresses of the other members and the total storage space required by the structure may vary, however, since the compiler can insert unnamed gaps between the individual members for the sake of optimization. For this reason the storage size of a structure should always be obtained using the sizeof operator.

The macro offsetof, defined in the header file stddef.h, can be used to obtain the location of a member within a structure. The expression:

offsetof( structure_type, member )

has the type size_t, and yields the distance in bytes between the beginning of the structure and member. Structure variables can be initialized by an initialization list containing a value for each member:

struct article flower = // Declare and initialize the { "rose", 7, 2.49 }; // structure variable flower

A structure variable with automatic storage duration can also be initialized with the value of an existing structure variable. The assignment operator can be used on variables of the same structure type. For example:

arrArticle[0] = flower;

This operation copies the value of each member of flower to the corresponding member of arrArticle[0].

A specific structure member can be accessed by means of the dot operator, which has a structure variable and the name of a member as its operands:

flower.name // The array 'name'

flower.price // The double variable 'price'

Efficient data handling often requires the use of pointers to structures. The arrow operator provides convenient access to a member of a structure identified by a pointer. The left operand of the arrow operator is a pointer to a structure. Some examples follow:

pArticle = &flower; // Let pArticle point to flower pArticle->quantity // Access members of flower pArticle->price // using the pointer pArticle

A structure cannot have itself as a member. Recursive structures can be defined, however, by means of members that are pointers to the structure's own type. Such recursive structures are used to implement linked lists and binary trees, for example.

1.10.2.1 Unions

A union permits references to the same location in memory to have different types. The declaration of a union differs from that of a structure only in the keyword union:

union number {long n; double x;};

This declaration creates a new union type with the tag number and the two members n and x.

Unlike the members of a structure, all the members of a union begin at the same address! Hence the size of a union is that of its largest member. According to the example above, a variable of type union number occupies 8 bytes.

Once a union type has been defined, variables of that type can be declared. Thus:

union number nx[10];

declares an array nx with ten elements of type union number. At any given time, each such element contains either a long or a double value. The members of a union can be accessed in the same ways as structure members. For example:

nx[0].x = 1.234; // Assign a double value to nx[0]

Like structures, union variables are initialized by an initializer list. For a union, however, the list contains only one initializer. If no union member is explicitly designated, the first member named in the union type declaration is initialized:

union number length = { 100L };

After this declaration, length.n has the value 100. 1.10.2.2 Bit-fields

Members of structures or unions can also be bit-fields. Bit-fields are integers which consist of a defined number of bits. The declaration of a bit-field has the form:

type [identifier] : width;

where type is either unsigned int or signed int, identifier is the optional name of the bit- field, and width is the number of bits occupied by the bit-field in memory.

A bit-field is normally stored in a machine word that is a storage unit of length sizeof(int). The width of a bit-field cannot be greater than that of a machine word. If a smaller bit-field leaves sufficient room, subsequent bit-fields may be packed into the same storage unit. A bit-field with width zero is a special case, and indicates that the subsequent bit-field is to be stored in a new storage unit regardless of whether there's room in the current storage unit. Here's an example of a structure made up of bit fields:

struct { unsigned int b0_2 : 3;

signed int b3_7 : 5;

unsigned int : 7;

unsigned int b15 : 1;

} var;

The structure variable var occupies at least two bytes, or 16 bits. It is divided into four bit-fields: var.b0_2 occupies the lowest three bits, var.b3_7 occupies the next five bits, and var.b15 occupies the highest bit.

The third member has no name, and only serves to define a gap of seven bits, as shown in Figure 1-5.

Figure 1-5. Bit assignments in the example struct

Bit-fields with the type unsigned int are interpreted as unsigned. Bit-fields of type signed int can have negative values in two's-complement encoding. In the example above, var.b0_2 can hold values in the range from 0 to 7, and var.b3_7 can take values in the range from -16 to 15.

Bit-fields also differ from ordinary integer variables in the following ways:

ã The address operator (&) cannot be applied to bit-fields (but it can be applied to a structure variable that

contains bit-fields).

ã Some uses of bit-fields may lead to portability problems, since the interpretation of the bits within a word

can differ from one machine to another.

Một phần của tài liệu IT training c pocket reference c syntax and fundamentals prinz kirch prinz 2002 11 30 1 (Trang 36 - 39)

Tải bản đầy đủ (PDF)

(98 trang)