Jump to content

C++ Programming/Unions

From Wikibooks, open books for an open world

The union keyword is used to define a union type.

Syntax
    union union-name 
    {
        public-members-list;
    private:
        private-members-list;
    } object-list;

Union is similar to struct (more than class), unions differ in the aspect that the fields of a union share the same position in memory and are by default public rather than private. The size of the union is the size of its largest field (or larger if alignment so requires, for example on a SPARC machine a union contains a double and a char [17] so its size is likely to be 24 because it needs 64-bit alignment). Unions cannot have a destructor.

What is the point of this? Unions provide multiple ways of viewing the same memory location, allowing for more efficient use of memory. Most of the uses of unions are covered by object-oriented features of C++, so it is more common in C. However, sometimes it is convenient to avoid the formalities of object-oriented programming when performance is important or when one knows that the item in question will not be extended.

     union Data {
       int i;
       char c;
     };


Writing to Different Bytes

[edit | edit source]

Unions are very useful for low-level programming tasks that involve writing to the same memory area but at different portions of the allocated memory space, for instance:

union item 
{
  // The item is 16-bits
  short theItem;

  // In little-endian lo accesses the low 8-bits -
  // hi, the upper 8-bits
  struct { char lo; char hi; } portions;
};

Note:
A name for the struct declared in item can be omitted because it is not used. All that needs to be explicitly named is the parts that we intend to access, namely the instance itself, portions.

  item tItem;
  tItem.theItem = 0xBEAD;
  tItem.portions.lo = 0xEF; // The item now equals 0xBEEF

Using this union we can modify the low-order or high-order bytes of theItem without disturbing any other bytes.

Example in Practice: SDL Events

[edit | edit source]

One real-life example of unions is the event system of SDL, a graphics library in C. In graphical programming, an event is an action triggered by the user, such as a mouse move or keyboard press. One of the SDL's responsibilities is to handle events and provide a mechanism for the programmer to listen for and react to them.

Note:
The following section deals with a library in C rather than C++, so some features, such as methods of objects, are not used here. However C++ is more-or-less a superset of C, so you can understand the code with the knowledge you have gained so far.

// primary event structure in SDL

typedef union 
{
  Uint8 type;
  SDL_ActiveEvent active;
  SDL_KeyboardEvent key;
  SDL_MouseMotionEvent motion;
  SDL_MouseButtonEvent button;
  SDL_JoyAxisEvent jaxis;
  SDL_JoyBallEvent jball;
  SDL_JoyHatEvent jhat;
  SDL_JoyButtonEvent jbutton;
  SDL_ResizeEvent resize;
  SDL_ExposeEvent expose;
  SDL_QuitEvent quit;
  SDL_UserEvent user;
  SDL_SysWMEvent syswm;
} SDL_Event;

Each of the types other than Uint8 (an 8-bit unsigned integer) is a struct with details for that particular event.

// SDL_MouseButtonEvent

typedef struct
{
  Uint8 type;
  Uint8 button;
  Uint8 state;
  Uint16 x, y;
} SDL_MouseButtonEvent;

When the programmer receives an event from SDL, he first checks the type value. This tells him what kind of an event it is. Based on this value, he either ignores the event or gets more information by getting the appropriate part of the union.

For example, if the programmer received an event in SDL_Event ev, he could react to mouse clicks with the following code.

if (ev.type == SDL_MOUSEBUTTONUP && ev.button.button == SDL_BUTTON_RIGHT) 
{
  cout << "You have right-clicked at coordinates (" << ev.button.x << ", "
       << ev.button.y << ")." << endl;
}

Note:
As each of the SDL_SomethingEvent structs contain a Uint8 type entry, it is safe to access both Uint8 type and the corresponding sub-struct together.

While identical functionality can be provided with a struct rather than a union, the union is far more space efficient; the struct would use memory for each of the different event types, whereas the union only uses memory for one. As only one entry has meaning per instance, it is reasonable to use a union in this case.

This scheme could also be constructed with polymorphism and inheritance features of object-oriented C++, however the setup would be involved and less efficient than this one. Use of unions loses type safety, however it gains in performance.

The this keyword is a implicitly created pointer that is only accessible within nonstatic member functions of a union (or a struct or class ) and points to the object for which the member function is called. The this pointer is not available in static member functions. This will be restated again on when introducing unions a more in depth analysis is provided in the Section about classes.