C: Where is union practically used?

28,135

Solution 1

I usually use unions when parsing text. I use something like this:

typedef enum DataType { INTEGER, FLOAT_POINT, STRING } DataType ;

typedef union DataValue
{
    int v_int;
    float v_float;
    char* v_string;
}DataValue;

typedef struct DataNode
{
    DataType type;
    DataValue value;
}DataNode;

void myfunct()
{
    long long temp;
    DataNode inputData;

    inputData.type= read_some_input(&temp);

    switch(inputData.type)
    {
        case INTEGER: inputData.value.v_int = (int)temp; break;
        case FLOAT_POINT: inputData.value.v_float = (float)temp; break;
        case STRING: inputData.value.v_string = (char*)temp; break;
    }
}

void printDataNode(DataNode* ptr)
{
   printf("I am a ");
   switch(ptr->type){
       case INTEGER: printf("Integer with value %d", ptr->value.v_int); break;
       case FLOAT_POINT: printf("Float with value %f", ptr->value.v_float); break;
       case STRING: printf("String with value %s", ptr->value.v_string); break;
   }
}

If you want to see how unions are used HEAVILY, check any code using flex/bison. For example see splint, it contains TONS of unions.

Solution 2

I've typically used unions where you want to have different views of the data e.g. a 32-bit colour value where you want both the 32-bit val and the red,green,blue and alpha components

struct rgba
{
  unsigned char r;
  unsigned char g;
  unsigned char b;
  unsigned char a;
};

union  
{
  unsigned int val;
  rgba components;
}colorval32;

NB You could also achieve the same thing with bit-masking and shifting i.e

#define GETR(val) ((val&0xFF000000) >> 24)

but I find the union approach more elegant

Solution 3

For accessing registers or I/O ports bytewise as well as bitwise by mapping that particular port to memory, see the example below:

    typedef Union
{
  unsigned int a;
struct {
  unsigned bit0 : 1,
           bit1 : 1,
           bit2 : 1,
           bit3 : 1,
           bit4 : 1,
           bit5 : 1,
           bit6 : 1,
           bit7 : 1,
           bit8 : 1,
           bit9 : 1,
           bit10 : 1,
           bit11 : 1,
           bit12 : 1,
           bit13 : 1,
           bit14 : 1,
           bit15 : 1
} bits;
} IOREG;

# define PORTA (*(IOREG *) 0x3B)
...
unsigned int i = PORTA.a;//read bytewise
int j = PORTA.bits.bit0;//read bitwise
...
PORTA.bits.bit0 = 1;//write operation

Solution 4

In the Windows world, unions are commonly used to implement tagged variants, which are (or were, before .NET?) one standard way of passing data between COM objects.

The idea is that a union type can provide a single natural interface for passing arbitrary data between two objects. Some COM object could pass you a variant (e.g. type VARIANT or _variant_t) which could contain either a double, float, int, or whatever.

If you have to deal with COM objects in Windows C++ code, you'll see variant types all over the place.

Solution 5

SDL uses an union for representing events: http://www.libsdl.org/cgi/docwiki.cgi/SDL_Event.

Share:
28,135
yesraaj
Author by

yesraaj

Learning c++,Check out my blog

Updated on March 21, 2020

Comments

  • yesraaj
    yesraaj over 4 years

    I have a example with me where in which the alignment of a type is guaranteed, union max_align . I am looking for a even simpler example in which union is used practically, to explain my friend.

  • yesraaj
    yesraaj over 14 years
    I know how to use union, my friend does too, but I want were it is used most commonly
  • jk.
    jk. over 14 years
    using a union to cast like this is technically undefined behaviour (although i'm unaware of any implementations which don't actually do what you want here)
  • mouviciel
    mouviciel over 14 years
    Never use this if you have to handle big/little endian conversions
  • wrapperm
    wrapperm over 14 years
    @mouviciel: This is not affected by endianness... can you please support your comment, if so..?
  • Alok Singhal
    Alok Singhal over 14 years
    But struct rgba may have padding, and even without padding, sizeof(unsigned int) may or may not be equal to sizeof(struct rgba) (4 for no padding). I.e., you probably don't want to do this.
  • Alok Singhal
    Alok Singhal over 14 years
    From the C standard: "The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
  • David Thornley
    David Thornley over 14 years
    @Alok: Not to mention that the struct will have r, g, b, and a in order (with or without padding), while the unsigned int byte order will depend on endianness. In other words, this code is not portable and may fail in odd ways when compiling on another processor.
  • fbrereto
    fbrereto over 14 years
    A common term for this technique is "type punning"
  • nos
    nos over 14 years
    Do note that (standard) C does not support this - assigning to one member in a union and then reading from another member is undefined behavior. Compilers/systems implementations do commonly support this though in their own specific ways.
  • Thomas Matthews
    Thomas Matthews over 14 years
    Isn't this what polymorphism is for? A base class for the common message content, then each message is a specialization of the base class.
  • Exectron
    Exectron over 14 years
    However, in many cases registers or I/O ports are platform-specific, so platform-independent code isn't such a concern. Though I suppose you might write a driver for some hardware that is used on both big-endian and little-endian machines (e.g. a Linux driver for a graphics chip)... in that case you'd know what you're doing I'm sure.
  • wrapperm
    wrapperm over 14 years
    The alignment of the addressable storage unit can be easily determined by a simple program... actually speaking you should have an idea about the architectural endianness and stuff like that before coding for a particular platform...
  • Adriano Varoli Piazza
    Adriano Varoli Piazza over 14 years
    @Thomas: you don't have classes in C.
  • zebrabox
    zebrabox over 14 years
    Thanks for the comments all. As you say this isn't portable ( nor is it intended to be) and relies on many assumptions which I didn't make clear in the post. Typically I wouldn't be using unsigned int but something like a typedef uint32_t i.e where I knew it was 32-bits. I'll amend my post to make this clearer
  • fortran
    fortran over 14 years
    @jk The very same undefined behaviour of getting the address, casting to a int pointer and then getting the contents. The only thing undefined here should be the endianness of the float, that is not specified by any standard.
  • GManNickG
    GManNickG over 14 years
    Do note that writing to one member of a union then reading from another leads to undefined behavior.
  • josesuero
    josesuero over 14 years
    In addition to the portability issues, it's also a great way to confuse the compiler with potential aliasing, forcing it to skip a load of otherwise useful optimizations.
  • nos
    nos over 14 years
    This technique blows up when your longs are 64 bit and your floats are not. e.g. linux 64 bit.
  • fortran
    fortran over 14 years
    @nos it won't "blow up", you'll keep getting the binary value of the float in either the lower or the upper part of the int (depending on the endiannes) and in the other, maybe trash... you can use a fixed size type if you wish, but this was just an example, not production quality code.
  • nos
    nos over 14 years
    I consider my applicatons to "blow up" when it starts producing or processing garbage :-)
  • Roman A. Taycher
    Roman A. Taycher over 13 years
    ie. Tagged unions with pattern matching in c. Do lots of people use unions without ad-hoc type tagging?
  • Sebastian Mach
    Sebastian Mach almost 13 years
    This misses a disclaimer that says "Reading from inactive union members yields undefined behavior".
  • Sebastian Mach
    Sebastian Mach almost 13 years
    Though that's using undefined behaviour, even if widely supported.
  • v.oddou
    v.oddou almost 10 years
    about what nos said; I think he means this is undefined behavior because of the strict aliasing rule. this should work when you use char as your "other" union types.
  • Koray Tugay
    Koray Tugay over 9 years
    Shouldn't you add alias for DataNode in declaration?