C++, like C, enables you to specify structure members that occupy a particular number of bits. This can be handy for creating a data structure that corresponds, say, to a register on some hardware device. The field type should be an integral or enumeration type (enumerations are discussed later in this chapter), and a colon followed by a number indicates the actual number of bits to be used. You can use unnamed fields to provide spacing. Each member is termed a bit field. Here’s an example:

struct torgle_register

{

    unsigned int SN : 4;   // 4 bits for SN value

    unsigned int : 4;      // 4 bits unused

    bool goodIn : 1;       // valid input (1 bit)

    bool goodTorgle : 1;   // successful torgling

};

You can initialize the fields in the usual manner, and you use standard structure notation to access bit fields:

torgle_register tr = { 14, true, false };

...

if (tr.goodIn)   // if statement covered in Chapter 6

...

Bit fields are typically used in low-level programming. Often, using an integral type and the bitwise operators listed in Appendix E, “Other Operators,” provides an alternative approach.

Unions

A union is a data format that can hold different data types but only one type at a time. That is, whereas a structure can hold, say, an int and a long and a double, a union can hold an int or a long or a double. The syntax is like that for a structure, but the meaning is different. For example, consider the following declaration:

union one4all

{

    int int_val;

    long long_val;

    double double_val;

};

You can use a one4all variable to hold an int, a long, or a double, just as long as you do so at different times:

one4all pail;

pail.int_val = 15;        // store an int

cout << pail.int_val;

pail.double_val = 1.38;   // store a double, int value is lost

cout << pail.double_val;

Thus, pail can serve as an int variable on one occasion and as a double variable at another time. The member name identifies the capacity in which the variable is acting. Because a union holds only one value at a time, it has to have space enough to hold its largest member. Hence, the size of the union is the size of its largest member.

One use for a union is to save space when a data item can use two or more formats but never simultaneously. For example, suppose you manage a mixed inventory of widgets, some of which have an integer ID, and some of which have a string ID. In that case, you could use the following:

struct widget

{

char brand[20];

int type;

union id              // format depends on widget type

{

    long id_num;      // type 1 widgets

    char id_char[20]; // other widgets

} id_val;

};

...

widget prize;

...

if (prize.type == 1)               // if-else statement (Chapter 6)

    cin >> prize.id_val.id_num;    // use member name to indicate mode

else

    cin >> prize.id_val.id_char;

An anonymous union has no name; in essence, its members become variables that share the same address. Naturally, only one member can be current at a time:

struct widget

{

    char brand[20];

    int type;

    union                 // anonymous union

{

        long id_num;      // type 1 widgets

        char id_char[20]; // other widgets

    };

};

...

widget prize;

...

if (prize.type == 1)

    cin >> prize.id_num;

else

    cin >> prize.id_char;

Because the union is anonymous, id_num and id_char are treated as two members of prize that share the same address. The need for an intermediate identifier id_val is eliminated. It is up to the programmer to keep track of which choice is active.

Unions often (but not exclusively) are used to save memory space. That may not seem that necessary in these days of gigabytes of RAM and terabytes of storage, but not all C++ programs are written for such systems. C++ also is used for embedded systems, such as the processors used to control a toaster oven, an MP3 player, or a Mars rover. In these applications space may be at a premium. Also unions often are used when working with operating systems or hardware data structures.

Enumerations

The C++ enum facility provides an alternative to const for creating symbolic constants. It also lets you define new types but in a fairly restricted fashion. The syntax for enum resembles structure syntax. For example, consider the following statement:

enum spectrum {red, orange, yellow, green, blue, violet, indigo, ultraviolet};

This statement does two things:

• It makes spectrum the name of a new type; spectrum is termed an enumeration, much as a struct variable is called a structure.

• It establishes red, orange, yellow, and so on, as symbolic constants for the integer values 0–7. These constants are called enumerators.

By default, enumerators are assigned integer values starting with 0 for the first enumerator, 1 for the second enumerator, and so forth. You can override the default by explicitly assigning integer values. You’ll see how later in this chapter.

You can use an enumeration name to declare a variable of the enumeration type:

spectrum band;  // band a variable of type spectrum

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги