Working with Unions in C Programming Language

One of the more unusual constructs in the C programming language is the union. This construct is used mainly in more advanced programming applications in which it is nec- essary to store different types of data in the same storage area. For example, if you want to define a single variable called x, which could be used to store a single character, a floating-point number, or an integer, you could first define a union called, perhaps, mixed:

union mixed

{

char c; float f; int   i;

};

The declaration for a union is identical to that of a structure, except the keyword union is used where the keyword struct is otherwise specified. The real difference between structures and unions has to do with the way memory is allocated. Declaring a variable to be of type union mixed, as in

union mixed x;

does not define x to contain three distinct members called c, f, and i; rather, it defines x to contain a single member that is called  either c, f, or i. In this way, the variable x can be used to store either a char or a float or an int, but not all three (or not even two of the three).You can store a character in the variable x with the following statement:

x.c = ‘K’;

The character stored in x can subsequently be retrieved in the same manner. So, to dis- play its value at the terminal, for example, the following could be used:

printf (“Character = %c\n”, x.c);

To store a floating-point value in x, the notation x.f is used:

x.f = 786.3869;

Finally, to store the result of dividing an integer count by 2 in x, the following statement can be used:

x.i = count / 2;

Because the float, char, and int members of x all exist in the same place in memory, only one value can be stored in x at a time. Furthermore, it is your responsibility to ensure that the value retrieved from a union is consistent with the way it was last stored in the union.

A union member follows the same rules of arithmetic as the type of the member that is used in the expression. So in

x.i / 2

the expression is evaluated according to the rules of integer arithmetic because x.i and 2 are both integers.

A union can be defined to contain as many members as desired. The C compiler ensures that enough storage is allocated to accommodate the largest member of the union. Structures can be defined that contain unions, as can arrays. When defining a union, the name of the union is not required, and variables can be declared at the same time that the union is defined. Pointers to unions can also be declared, and their syntax and rules for performing operations are the same as for structures.

One of the members of a union variable can be initialized. If no member name is specified, the first member of the union is set to the specified value, as in:

union mixed x = { ‘#’ };

This sets the first member of x, which is c, to the character #.

By specifying the member name, any member of the union can be initialized like so:

union mixed x = { .f = 123.456; };

This sets the floating member f of the union mixed variable x to the value 123.456.

An automatic union variable can also be initialized to another union variable of the same type:

void foo (union mixed x)

{

union mixed y = x;

}

Here, the function foo assigns to the automatic union variable y the value of the argu- ment x.

The use of a union enables you to define arrays that can be used to store elements of different data types. For example, the statement

struct

{

char           *name;

enum symbolType type;

union

{

int    i;

float  f;

char   c;

} data;

} table [kTableEntries];

sets up an array called table, consisting of kTableEntries elements. Each element of the array contains a structure consisting of a character pointer called name, an enumera- tion member called type, and a union member called data. Each data member of the array can contain either an int,a float, or a char. The member type might be used to keep track of the type of value stored in the member data. For example, you could assign it the value INTEGER if it contained an int, FLOATING if it contained a float, and CHARACTER if it contained a char. This information would enable you to know how to reference the particular data member of a particular array element.

To store the character ‘#’ in table[5], and subsequently set the type field to indi- cate that a character is stored in that location, the following two statements could be used:

table[5].data.c = ‘#’;

table[5].type = CHARACTER;

When sequencing through the elements of table, you could determine the type of data value stored in each element by setting up an appropriate series of test statements. For example, the following loop would display each name and its associated value from table at the terminal:

enum symbolType { INTEGER, FLOATING, CHARACTER };

for ( j = 0; j < kTableEntries;  ++j ) {

printf (“%s “, table[j].name);

switch ( table[j].type ) {

case INTEGER:

printf (“%i\n”, table[j].data.i);

break;

case FLOATING:

printf (“%f\n”, table[j].data.f);

break;

case CHARACTER:

printf (“%c\n”, table[j].data.c);

break;

default:

printf (“Unknown type (%i), element %i\n”, table[j].type, j );

break;

}

}

The type of application illustrated might be practical for storage of a symbol table, for example, which might contain the name of each symbol, its type, and its value (and per- haps other information about the symbol as well).

Source: Kochan Stephen G. (2004), Programming in C: A Complete Introduction to the C Programming Language, Sams; Subsequent edition.

Leave a Reply

Your email address will not be published. Required fields are marked *