union in C with Examples Program and Tips (Detail Blog Post)

This blog post will teach you about the union in C programming and its applications. In C, a union is a type that consists of a sequence of members whose storage overlaps. It is the reason union can only hold the value of one of its members at a time.

The following topic we will cover in this blog post:

  • What are unions?
  • How to declare and use C union?
  • How to access members of a union?
  • Examples and applications of unions.
  • How to access members of the union using pointers?
  • How is the size of the union decided by the compiler in C?
  • Differences between structures and unions.
  • Union features include C99 and C11.

What is a union in C?

A union is a user-defined data type that allows storing different data types in the same memory region. It means all members of the union share the same memory location.

Now you are thinking about how many data types you can store in C union?

Don’t worry about the count it allows you to create many members in the union as per your requirement. But you should remember all members of the union shared the same memory storage. This means that at any given time, a union can contain no more than one object from its sequence of members. It is the reason it can only hold the value of one of its members at a time.

I assume definitely this question is come to your mind how the value of at most one of the members be stored in a union object at any time.

The answer to your question is that the size of a union is sufficient to contain the largest of its members. That is why at any time union object is capable of holding the value of any members.

If you are already familiar with C structure specifiers then you will find that the structure and union specifiers have the same form. The keywords struct and union indicate that the type being specified is, respectively, a structure type or a union type.

Syntax:

union tagopt { member-list };

Parameters:

tag: Type name given to the union.

member-list: Members that the union can contain.

 

How to Declare a Union?

Declaration of union is similar to the structure just you need to use the union keyword beside the struct keyword.

So the declaration of a union begins by using the union keyword followed by tag (union name which is optional) and enclosing the member list in curly braces.

Here’s an example:

union MyData // Declare a simple union type
{
    int age;
    float fees;
    char name[4];
} data;

The object of the MyData type can store an integer value, float value, or string at a time.

 

You can add n numbers of members to the member list as per your requirement. But remember they share the same storage. See the below example,

union Test
{
   member_1;
   member_2;
   .
   .
   .
   member_n;
};

 

In the above examples, you can see I have used the union name (tag). The union name is optional if you want you can avoid it but not using the union name results in anonymous unions.

An unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union, keeping their structure or union layout (C11).

The anonymous unions are usually nested inside a named structure and use the struct’s name to identify them. Consider the below example,

#include <stdio.h>

struct ColourCode
{
    // Anonymous union
    union
    {
        char m_char;
        unsigned int m_asciiCode;
    };
};

int main()
{
    struct ColourCode asciiCode, ch;
    asciiCode.m_asciiCode = 65;
    ch.m_char = 'A';

    /*Note that members of union are
    accessed directly with struct name*/
    printf("ch.m_char = %c\n", ch.m_char);
    printf("asciiCode.m_asciiCode = %d",asciiCode.m_asciiCode);

    return 0;
}

Output:

ch.m_char = A
asciiCode.m_asciiCode = 65

 

In the above example “struct ColourCode” has an anonymous union whose members are an unsigned int and char. You can see in the example program, using the structure variable we are able to access the members of the anonymous union and its members, they behave like members of the struct.

I know you are a curious reader you are thinking that what happens if the struct has both normal and anonymous unions.

Don’t worry I have an example for you. Consider the below code.

#include <stdio.h>

struct Test
{
    union // anonymous union
    {
        int a;
        char b;
    };

    union
    {
        long c;
        char d;
    } e;

    int value;
} var;



int main()
{
    var.a = 2;   // valid
    
    // invalid: inner union is not anonymous
    // you will get compiler error
    var.c = 3;
    
    var.e.c = 5; // valid

    return 0;
}

 

 

Different ways to define union variable (object) in C:

You can create a union object in two ways:

1.) At the time of the declaration of union, see the below example:

union MyData
{
    int age;
    float fees;
    char name[4];
    
} data, *pData; //union variables

 

2.)  Using the union keyword and its tag, see the below example:

#include <stdio.h>

union MyData
{
    int age;
    float fees;
    char name[4];

};


int main()
{
    //union variables
    union MyData data, *pData;
}

 

Accessing Union Members:

We can access union members by the union object or union pointer. Based on the union variable type, there are two ways to access union data members:

1.) Using the dot (.) operator, when union variable is an object. This means the first operand of the . operator shall be an atomic, qualified, or unqualified union type, and the second operand shall name a member of that type.

2.)Using the arrow ( -> ) operator, when union variable is a pointer. The first operand of the -> operator shall have type “pointer to atomic, qualified, or unqualified union”, and the second operand shall name a member of the type pointed to.

Let’s see an example to understand how this work:

union Laptop
{
    float price;

    int productId;

    char name[24];

} Laptop1, *Laptop2;

 

The above-mentioned union contains three members price, productId, and name. Let’s see how we can access the members of the union using the pointer object and pointer to the union that are the laptop1 and pLaptop2.

Using the laptop1 (union object):

Here we use . operator to access the member of union. See the following expression.

//access union member price
laptop1.price

//access union member productId
laptop1.productId

//access union member name
laptop1.name

 

Using the pLaptop2 ( pointer to a union):

Here we use -> operator to access the member of union. See the following expression.

//access union member price
pLaptop2->price

//access union member productId
pLaptop2->productId

//access union member name
pLaptop2->name

 

Let’s see an example code for a better understanding of how to access the members of the union.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//Declaration of C union
union Laptop
{
    float price;
    int productId;
    char name[24];
};

int main( )
{
    //creation union object
    union Laptop laptop1;

    //creation pointer to the union
    union Laptop *pLaptop2;

    //Access members using the union object
    printf("Access Members of Union using the union object\n");
    laptop1.price = 20045.56;
    printf( "Laptop price : %f\n", laptop1.price);

    laptop1.productId = 345;
    printf( "Laptop product Id : %d\n", laptop1.productId);

    strcpy( laptop1.name, "Lenovo");
    printf( "Laptop name : %s\n", laptop1.name);


    //Access members using the pointer to union
    printf("\n\nAccess Members of Union using the pointer to union\n");
    //Assign memory to the pointer to union
    pLaptop2 = malloc(sizeof(union Laptop ));
    if(pLaptop2 == NULL)
    {
        printf("Failed to allocate the memory");
        return -1;
    }

    pLaptop2->price = 10045.56;
    printf( "Laptop price : %f\n",  pLaptop2->price);

    pLaptop2->productId = 245;
    printf( "Laptop product Id : %d\n",  pLaptop2->productId);

    strcpy(  pLaptop2->name, "Dell");
    printf( "Laptop name : %s\n",  pLaptop2->name);

    //Now free the allocated memory
    free(pLaptop2);
    pLaptop2 = NULL;

    return 0;
}

Output:

union in c with example code to how to access union members

What we have done above is essentially created a union object laptop1 and pointer variable pLaptop2. Now we are accessing union members using the laptop1 with the help of the dot (.) operator. And later accessing members using the pointer variable pLaptop2 with the help of the arrow (->) operator

 

✌ Bonus Knowledge about accessing the union members:

If the first expression of the dot(.) or arrow (->) operator has qualified type, the result has the so qualified version of the type of the designated member.

Let’s understand it with an example.

//Declaration of C union
union s
{
    int i;
    const int ci;
};

Now I am going to create unqualified and some qualified objects of the above declared union.

//object unqualified
union s s;

//object qualified with const
const union s cs;


//object qualified with volatile
volatile union s vs;

 

Now the various members have the following types with respective objects:

s.i   -->   int

s.ci  -->   const int

cs.i  -->   const int

cs.ci -->   const int

vs.i  -->   volatile int

vs.ci -->   volatile const int

 

Note: If &unionObj is a valid pointer expression (where & is the “address-of” operator, which generates a pointer to its operand), the expression (&unionObj )->mou is the same as unionObj.mou.

 

How is size of union decided by compiler in C?

The size of a union is sufficient to contain the largest of its members. And there may be unnamed padding at the end of a union.

Let’s take the following code as an example to understand the concept:

#include <stdio.h>

union Test1
{
    int data;
    char ch;
} Obj1;

union Test2
{
    int data1;
    int data2;
} Obj2;


union Test3
{
    float data1;
    int data2;
} Obj3;

union Test4
{
    char ch[24];
    int data;
} Obj4;


int main()
{
    printf("sizeof(Obj1) = %lu\n", sizeof(Obj1));

    printf("sizeof(Obj2) = %lu\n", sizeof(Obj2));

    printf("sizeof(Obj3) = %lu\n", sizeof(Obj3));

    printf("sizeof(Obj4) = %lu\n", sizeof(Obj4));

    return 0;
}

Output:

sizeof(Obj1) = 4
sizeof(Obj2) = 4
sizeof(Obj3) = 4
sizeof(Obj4) = 24

We are getting the size of the union Test1 is 4 while it has one int and one char member. This is because a union always takes up as much space as the largest member. Similarly, the size of the union test2 is 4, since both are int.

Now I believe you are able to understand the logic behind the union size. The point which you need to remember is that all members share the same memory region.

 

Some questions for you, calculate the size of the union. If you are able to calculate, write your answer in the comment box.

Question1:

#include <stdio.h>

union Test
{
    char ProdName[10];
    int iAmount;
};

int main()
{
    printf("Size of Union = %ld\n", sizeof(union Test));

    return 0;
}

Output: ?

 

Question2:

#include <stdio.h>
union Test
{
    char ProdName[10];
    double  dAmount;
};

int main()
{
    printf("Size of Union = %ld\n", sizeof(union Test));
    
    return 0;
}

Output: ?

 

Initialization of union in C:

A union initializer specifies the initial value stored in a union object. When initializing union type object, the initializer must be a non-empty, (until C23) brace-enclosed, comma-separated list of initializers for the members:

= { expression , ... }(1)	


= { designator expression , ... }(2) (since C99)


= { }(3) (since C23)

Note: Where the designator is a sequence of individual member designators of the form .member and array designators of the form [ index ].

Let’s take an example for a better understanding.

#include <stdio.h>

union Test
{
    int x;
    char c[4];
};

int main()
{
    /* makes obj1.x active with value 1 */
    union Test obj1 = {1};

    printf("%d\n", obj1.x);

    /*  Designated initialize   */
    /* makes obj2.c active with value {'A','m','l','\0'} */
    union Test obj2 = { .c={"Aml"} }; //C99

    printf("%s\n", obj2.c);

    return 0;
}

Output:

1
Aml

 

✌ Bonus  Knowledge about the union initializer:

When we initialize a union with an initializer it initializes the first member of the union unless a designated initializer is used.

Now one question for you.

#include <stdio.h>

union Test
{
    unsigned char c;
    int x;
};

int main()
{
    union Test obj = {400};

    printf("%d\n", obj.x);

    return 0;
}

Output: ?

 

One important point which I have explained earlier in this blog post is that all union members share the same memory region. Let’s understand what would happen if a union have two members and assigned value to any one member and try to read the second member.

#include <stdio.h>

union Test
{
    char a;
    int b;
};

int main( )
{
    union Test testData;

    testData.a = 'A';

    printf( "testData.b = %d\n", testData.b);

    return 0;
}

Output:unspecified

The above union Test has two members char and int. If we assigned a character value to the char member, but later tried accessing the value of int members. In this situation, the output would be unspecified.

 

Note: If the member used to access the contents of a union is not the same as the member last used to store a value, the object representation of the value that was stored is reinterpreted as an object representation of the new type (this is known as type punning). If the size of the new type is larger than the size of the last-written type, the contents of the excess bytes are unspecified (and may be a trap representation). (since C99)

 

 

Application of union in C

There are many developers who does not understand to how to use union better way and take the advantage of the union. In this section I will explain how you can use union efficinety with an example code.

Basically purpose of union is to save memory by using the same memory region for storing different type of object at different times.

A union is work like a washroom, different people use it in a different time frame (non-overlapping period) but nobody uses it at the same time. So a single washroom handles the many people and there is no need to create a washroom for each person, it saves money.

Simillar to that, if in the application there are a lot of objects that hold the value at a non-overlapping time, you can create the union for these objects to save the memory. Just like a washroom has at most one “active” user at each moment, a union has at most one “active” member at each moment of program time.

So unions are used when mutually exclusive data members are used. It save a lot of memory space which is primary goal for embedded system developer.

Let’s understand it with example.

#include <stdio.h>
#include<string.h>


//define enum
typedef enum  { ROLLNUMB, AGEYEAR, AGEMONTH } eInfoTypes;


//struc contains union
typedef struct
{
    eInfoTypes e_Infotype;

    union //Anonyms union
    {
        int RollNumber;
        int AgeYear;
        int AgeMonth;
    };
} InfoData;



//function to read stored data
void readInformation (const InfoData *MyInfoData, InfoData *ReadData)
{
    switch(MyInfoData->e_Infotype)
    {
    case ROLLNUMB:

        ReadData->RollNumber = MyInfoData->RollNumber; // Read MyInfoData->RollNumber

        break;

    case AGEYEAR:

        ReadData->AgeYear = MyInfoData->AgeYear; // Read MyInfoData->AgeYear

        break;

    case AGEMONTH:

        ReadData->AgeMonth = MyInfoData->AgeMonth; // Read MyInfoData->AgeMonth

        break;
    }
}


//function to write data
void writeInformation (InfoData *MyInfoData)
{
    switch(MyInfoData->e_Infotype)
    {
    case ROLLNUMB:

        MyInfoData->RollNumber = 100; // write MyInfoData->RollNumber

        break;

    case AGEYEAR:

        MyInfoData->AgeYear = 20; // write MyInfoData->AgeYear

        break;

    case AGEMONTH:

        MyInfoData->AgeMonth = 240;  // write MyInfoData->AgeMonth

        break;
    }
}


//Driving main function

int main()
{

    //structure variable to store data
    InfoData sInfoData = {0};

    //structure variable to store read data
    InfoData sReadInfoData = {0};

    //enum variable initialize with ROLLNUMB
    sInfoData.e_Infotype = ROLLNUMB;


    //write roll number to the structure variable
    writeInformation(&sInfoData);

    //read roll number from the structure variable
    readInformation(&sInfoData,&sReadInfoData);

    //print read roll number
    printf("Roll Number %d\n", sReadInfoData.RollNumber);


    //enum variable initialize with age in year
    sInfoData.e_Infotype = AGEYEAR;

    //write age in year to the structure variable
    writeInformation(&sInfoData);

    //read age in year from the structure variable
    readInformation(&sInfoData,&sReadInfoData);

    //print read age in year
    printf("Age in year %d\n", sReadInfoData.AgeYear);


    //enum variable initialize with AGEMONTH
    sInfoData.e_Infotype = AGEMONTH;

    //write age in month to the structure variable
    writeInformation(&sInfoData);

    //read age in month to the structure variable
    readInformation(&sInfoData,&sReadInfoData);

    //print read age in month
    printf("Age in month %d\n", sReadInfoData.AgeMonth);

    return 0;

}


 

In the above example code you can see how single union object converting to different three integer object but at a time one object. It save a lot of memory if it has many members of different types.

Note: A pointer to a union object, suitably converted, points to each of its members (if a member is a bit-field, then to the unit in which it resides), and vice versa.

 

Unions are also used in memory mapping where direct accessing the memory. For example, to access the register in a more convenient way we can put a bit-field structure and integral data type in a union, which enables the way to access the entire register or individual bits.

For example, suppose a microcontroller has a port of 8 pins and each pin is connected to the led. In that scenario using the bit field, we can easily change the status of the led.

So first we need to create a bit-field structure to mapping with the micro-controller port.

typedef union
{

    struct
    {

        uint8_t LED1 : 1;
        uint8_t LED2 : 1;
        uint8_t LED3 : 1;
        uint8_t LED4 : 1;
        uint8_t LED5 : 1;
        uint8_t LED6 : 1;
        uint8_t LED7 : 1;
        uint8_t LED8 : 1;
    };

    uint8_t AllLedState;

} LED_BAR_STATE;

Create a pointer to the above describe bit-field and assign the address of the PORT to the pointer which you want to access.

volatile LED_BAR_STATE *pLedState = (volatile LED_BAR_STATE *)0xE002C000;

Now you can access the individual led using the pointer.

pLedState->LED1 = 1;

pLedState->LED1 = 0;

Disclaimer: Here, I am only describing, how the bit-field work. I am not suggesting using bit-field in the mapping of a hardware register because the allocation of bit-field depends upon the compiler.

Might be the result of one compiler that can be different from another compiler. So we should avoid the compiler-dependent code, In simple words, avoid using bit fields for the mapping of the hardware register.

 

Few Important Points of a C union:

  • A union has the declaration list define a new type within the translation unit.
  • According to the C standard,If the member declaration list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined..

Note: GCC permits a C structure to have no members.

struct empty
{
};

The structure has a size zero.

  • A union or struct with no tag is called an anonymous union or structure. An anonymous structure or union is introduced in C11 and not supported by the c99 or older compiler.
struct //anonymous struct
{
    short int b;
};

 

union //anonymous union
{
    short int b;
};

 

  • If a structure contains the anonymous structure or union(only in C11), The members of an anonymous structure or union are considered to be members of the containing structure or union.
#include <stdio.h>
#include<string.h>

struct myData
{
    union   // anonymous union
    {
        short int a;

        short int b;

    };

    short int c;
};


int main()
{
    //Variable of structure
    struct myData sMydata;

    sMydata.a =10; //valid

    sMydata.b = 20;  //valid

    sMydata.c = 40;  //valid

    return 0;
}

 

  • The above describe rule applies recursively if the containing structure or union is also anonymous.
#include <stdio.h>

struct myData
{
    union   // anonymous union
    {
        struct
        {
            short int a;

        } data; //data is struct variable

        struct //anonymous struct
        {
            short int b;
        };

    };

    short int c;
};


int main()
{
    struct myData sMydata; //structure variable

    sMydata.a = 5; //invalid

    sMydata.data.a =10; //valid

    sMydata.b = 20; //valid

    sMydata.c = 40; //valid

    return 0;
}

 

  • We can create a bit-field using the union.
#include <stdio.h>

union Data
{
    unsigned int a: 4;
    unsigned int b: 4;
    int c;
};

int main()
{
    union Data myData;

    myData.a = 5;
    myData.b = 5;
    myData.c = 4;

    printf("myData.a= %d, myData.b = %d, myData.c = %d\n\n",
           myData.a, myData.b, myData.c);

    return 0;
}
  • Each non-bit-field member of a structure or union object is aligned in an implementation-defined manner appropriate to its type.
  • The size of a union is sufficient to contain the largest of its members.
  • A pointer to a union object, suitably converted, points to each of its members (or if a member is a bitfield, then to the unit in which it resides), and vice versa.
  • Designated initialization of unions is also supported by C99 and C11.
#include <stdio.h>

union Data
{
    int a;
};

int main()
{
    //designated initialization of union
    union Data myData = { .a = 4 };

    printf("myData.a= %d\n",myData.a);

    return 0;
}

 

 

Difference between structure and union:

The key difference between structure and union is that structure allocates enough space to store all the fields but unions only allocate enough space to store the largest field. In union, all fields are stored in the same space.

In the below table, I have listed some common differences between structure and union.

difference between union and structure

 

Recommended Post