Why use unions?

Hello community,
I’m wondering why should someone use an union while developing software if it’s very dangerous to use. (I know it’s good in aspects of memory allocated but not more than that as there’s only active member…).

Thanks ahead.

Well, I don’t really know what makes it so terribly “dangerous”, but it may be quite useful in situations when you may have to give,
depending on context, different interpretation of bits. Concerning the memory saving…well, you should realise that C language got designed at the time when a machine with 1MBof RAM was considered a “computing monster”, so that this feature was quite useful at the time.

These days this saving may seem funny and insignificant, but if you consider the structures like ETHREAD and EPROCESS
(i.e HUGE structures that are allocated from non-paged pool in reasonably large numbers) you are going to realise that this language feature may still be useful in the year 2019 in some situations…

Anton Bassov

Unions are not particularly dangerous. They provide a simple way to look at a piece of memory in two different ways. It’s not accurate to say “there’s only one active member”. Let me give some examples.

The IRP structure makes heavy use of unions, but that’s primarily for saving memory saving. There are lots and lots of IRPs in the system, so reusing bytes when there is no possibility for conflict is just good sense.

Let’s say you need to crack the bits of a double-precision floating point number. There are two ways to do that. You can’t just cast the value to an __int64, because the compiler will generate a float-to-integer conversion. So, you can fake the compiler by doing:

    double d = 3.14159;
    __int64 li = *(__int64*)&d;

but that seems tacky. Instead, I can write:

    union convert_t {
        double d;
        __int64 li;
    } converter;
    converter.d = 3.14159;
    int__64 li = converter.li;

In the driver world, there are very good reason for using unions. Very often, our hardware registers consist of a number of individual bit fields, but often the registers themselves have to be addressed as a unit. Rather than error-prone shifts and masks, you can say:

    union status_register_t {
        uint32_t   ui;
        struct {
            uint32_t interrupt_mask : 1;
            uint32_t interrupt_state : 1;
            uint32_t led_state: 6;
            uint32_t fpga_version: 8;
            uint32_t memory_use: 16;
        };
    };
    ...
    register_t reg;
    reg.ul = READ_REGISTER_ULONG( base + STATUS_REGISTER );
    KdPrint(( "FPGA Version is %d\n", reg.fpga_version ));

Unions are being declared evil in context of so called “type punning”.

In the example of Mr. Roberts, the union contains float and integer type.
The danger of “type punning” is that compiler can store converter.d in a special kind of float register rather than in memory,
then it will have to do extra effort to get the bits and rearrange them into a integer register.
Especially, if union parameter is passed to function in registers - then the called function has to know in which set of registers this parameter is passed.

For temporary local manipulation on POD types like in the example, unions should be safe.
It is very widely used. No any modern C++ standard dares to break it.
– pa