c++ – Why do we need a union?

Question:

For example,

union 
{
    float fl,
    unsigned int uinteg,
    char ch,
    int integ
} foo;

All this is stored mixed in one memory area. What is the point, because once you set the values

foo.fl = 3.14f;
foo.uinteg = 666;
foo.ch = 'a';
foo.int = -25;

it will no longer be possible to get them back – will everything be mixed up? A way to save a couple of bytes or a couple of clock cycles and still be readable? Do not write 4 different functions, but write one that accepts union and decide what to do in it? In this case, isn't it easier to accept void * and then cast to the type you need? As an example of "Just cast" I will give the following code:

Classic example:

typedef enum { STR, INT } tType;
typedef struct {
    tType typ;          // typ is separate.
    union {
        int ival;       // ival and sval occupy same memory.
        char *sval;
    };
} tVal;

void printer(tVal uni)
{
    if (uni.type == INTEGER) // blah-blah
        uni.ival // Используем integer
    else
        ini.sval // В противном случае
}

The printer function can be rewritten as something like this:

void printer(void* data, tType typ)
{
    if (tType == INTEGER)
    {
        (int*)data // Чего-то делаем
    }
}

Another example:

union 
{
   int a;
   int b;
   int c;
} bar;

bar.a = 20;
bar.b = 50; // Значение a потеряли :(

Again, what's the point if I can first have a separate variable int a = 20; and then change its value a = 50; and the effect is exactly the same? Looks like a strong witchcraft.

Answer:

Union s (unions) are used in two cases:

  1. To create a "universal" data type capable of storing not only one, but one of the predefined types. To do this, an integer field is added to the union indicating the type of data currently stored:

     struct variant { union tag_value { int intValue; float floatValue } value; unsigned storedType; };

    One example of this in real life is the VARIANT structure from the Windows API.

    In other words, this is the predecessor of modern boost::variant , QVariant , etc. However, the above classes can store non-primitive types (with constructors, destructors, and copy operators), but union cannot.

  2. To convert between incompatible types. Traditionally, the conversion operator (T) or reinterpret_cast<> is used for this purpose. However, these methods are dangerous by violating the strict aliasing rule and, as a result, generating undefined (that is, unpredictable) behavior.

    The correct ways to convert are either memcpy (which is thrown out by the compiler) or using union .

    UPD: Attention! The union conversion is only valid in C , not in C++. In response to the question "Accessing inactive union member and undefined behavior?" References are made to the following paragraphs of the standards:

Scroll to Top