Previous Page
Next Page

10.2. Unions

Unlike structure members, which all have distinct locations in the structure, the members of a union all share the same location in memory; that is, all members of a union start at the same address. Thus you can define a union with many members, but only one member can contain a value at any given time. Unions are an easy way for programmers to use a location in memory in different ways.

10.2.1. Defining Union Types

The definition of a union is formally the same as that of a structure, except for the keyword union in place of struct:

union [tag_name] { member_declaration_list };

The following example defines a union type named Data which has the three members i, x, and str:

union Data { int i; double x; char str[16]; };

An object of this type can store an integer, a floating-point number, or a short string.

union Data var, myData[100];

This declaration defines var as an object of type union Data, and myData as an array of 100 elements of type union Data. A union is at least as big as its largest member. To obtain the size of a union, use the sizeof operator. Using our example, sizeof(var) yields the value 16, and sizeof(myData) yields 1,600.

As Figure 10-2 illustrates, all the members of a union begin at the same address in memory.

Figure 10-2. An object of the type union Data in memory

To illustrate how unions are different from structures, consider an object of the type struct Record with members i, x, and str, defined as follows:

struct Record { int i; double x; char str[16]; };

As Figure 10-3 shows, each member of a structure object has a separate location in memory.

Figure 10-3. An object of the type struct Record in memory

You can access the members of a union in the same ways as structure members. The only difference is that when you change the value of a union member, you modify all the members of the union. Here are a few examples using the union objects var and myData:

var.x = 3.21;
var.x += 0.5;
strcpy( var.str, "Jim" );         // Occupies the place of var.x.
myData[0].i = 50;
for ( int i = 0; i < 50; ++i )
  myData[i].i = 2 * i;

As for structures, the members of each union type form a name space unto themselves. Hence in the last of these statements, the index variable i and the union member i identify two distinct objects.

You the programmer are responsible for making sure that the momentary contents of a union object are interpreted correctly. The different types of the union's members allow you to interpret the same collection of byte values in different ways. For example, the following loop uses a union to illustrate the storage of a double value in memory:

var.x = 1.25;

for ( int i = sizeof(double) - 1; i >= 0; --i )
  printf( "%02X ", (unsigned char)var.str[i] );

This loop begins with the highest byte of var.x, and generates the following output:

3F F4 00 00 00 00 00 00

10.2.2. Initializing Unions

Like structures, union objects are initialized by an initialization list. For a union, though, the list can only contain one initializer. As for structures, C99 allows the use of a member designator in the initializer to indicate which member of the union is being initialized. Furthermore, if the initializer has no member designator, then it is associated with the first member of the union. A union object with automatic storage class can also be initialized with an existing object of the same type. Some examples:

union Data var1 = { 77 },
           var2 = { .str = "Mary" },
           var3 = var1,
           myData[100] = { {.x= 0.5}, { 1 }, var2 };

The array elements of myData for which no initializer is specified are implicitly initialized to the value 0.

Previous Page
Next Page