How to Use C Structures, Unions and Bit Fields with Examples

Structures, Unions, and Bit fields are some of the important aspects of C programming language.

While structures are widely used, union and bit fields are comparatively less used but that does not undermine their importance.

In this tutorial, we’ll explain the concept of the structures, union and bit fields in C language using examples.

1. Structures in C

Structures provide a way to store multiple variables of similar or different types under one umbrella. This makes information more packaged and program more modular as different variables referring to different values can be accessed through a single structure object.

An example of a C structure can be:

struct <Name or Tag>
     {
         <member-1>;
         <member-2>;
         <member-3>;
         ...
         ...
         ...
     };

So we see that a structure can be defined through a keyword “struct” followed by structure name. The body of structure consists of different semicolon terminated variable definition within curly braces.

Going back to what structure really is, A structure usually does not package unrelated variables. All the variables are usually part of some broader level information that structure intends to hold.

For example,  a structure can hold all the information related to an employee in an organization:

struct employee
     {
        char *name;
        int age;
        char *department;
        int salary;
        char *job_title;
     };

Now, to access structure variables, you need to define an object for that structure. For example, here is how you can define an object for the “employee” structure:

struct employee emp_obj;

NOTE: The keyword “struct” is mandatory while defining structure objects in C

The variable “emp_obj” now becomes an object of “employee” structure. Individual structure members can be accessed in following way:

emp_obj.name
     emp_obj.age
     ...
     ...
     ...

So we see that “.” character is used to access individual variables.

Unlike the one above, a structure object can also be of pointer type. For example:

struct employee *emp_obj;

In this case, individual structure members can be accessed in the following way:

  emp_obj->name
     emp_obj->age
     ...
     ...
     ...

So, we see that “->” character is used to access individual variables.

Here is working example of C structure:

#include <stdio.h> 

struct employee
{
   char *name;
   int age;
   char *department;
   int salary;
   char *job_title;
};

int main(void)
{
   struct employee emp_obj;
   struct employee *emp_ptr_obj;

   emp_obj.name = "theGeekStuff";
   /* Similarly Initialize other
    * variables of employee
    * structure here */

   emp_ptr_obj = &emp_obj;

   printf("\n Employee name is [%s]\n", emp_ptr_obj->name);

   return 0;
}

Here is the output:

Employee name is [theGeekStuff]

2. Unions in C

Unions are almost like structures in C(just explained above) but with a twist. The twist is that the memory for a union is equal to the size of it’s largest member. Confused? Don’t worries, let’s understand it in more detail.

Here is how union are defined:

union char_and_ascii
{
   char ch;
   unsigned int ascii_val;
};

As you can see that it’s more or less like how we declare structures in C. Just that the keyword “union” is used instead of “struct”.

So, what is the difference between a structure and a union? Well, the difference lies in the size. If the above example would have been a structure, the size of structure would have been:

sizeof(char) + sizeof(unsigned int) = 1 + 4 = 5 bytes

But, in case of the union, the size is equivalent to that of the largest member type in the union. So, in this case, the largest type is “unsigned int” and hence the size of union becomes “4”.

Now, having understood that, one might ask, in which scenarios union can be used? Well, there are certain scenarios where you want to use only one of the members at a time. So in that case, using a union is qwise option rather than using a structure. This will save you memory.

Here is a working example of a union in C:

#include <stdio.h>

union char_and_ascii
{
    char ch;
    unsigned short ascii_val;
};

int main (void)
{
    union char_and_ascii obj;
    obj.ascii_val = 0;

    obj.ch = 'A';

    printf("\n character = [%c], ascii_value = [%u]\n", obj.ch, obj.ascii_val);

    return 0;
}

Here is the output:

character = [A], ascii_value = [65]

One a different note, to get deeper than an understanding of C language, you should also know C Macros, Inline Function, C Binary Tree works.

3. Bit fields in C

There are times when the memory variables of a structure represent some flags that store either 0 or 1. Here is an example:

struct info
{
    int isMemoryFreed;
    int isObjectAllocated;
}

If you observe, though a value of 0 or 1 would be stored in these variables but the memory used would be complete 8bytes.

To reduce memory consumption when it is known that only some bits would be used for a variable, the concept of bit fields can be used.

Here is an example that illustrates this:

#include <stdio.h>

struct example1
{
    int isMemoryAllocated;
    int isObjectAllocated;
};

struct example2
{
    int isMemoryAllocated : 1;
    int isObjectAllocated : 1;
};

int main(void)
{
    printf("\n sizeof example1 is [%u], sizeof example2 is [%u]\n", sizeof(struct example1), sizeof(struct example2));

    return 0;
}

Here is the output:

sizeof example1 is [8], sizeof example2 is [4]

Also, if after declaring the bit field width(1 in case of above example), if you try to access other bits then compiler would not allow you to do the same.

Here is an example:

#include <stdio.h>

struct example2
{
    int isMemoryAllocated : 1;
    int isObjectAllocated : 1;
};

int main(void)
{
    struct example2 obj;

    obj.isMemoryAllocated = 2;

   return 0;
}

So, by setting the value to “2”, we try to access more than 1 bit. Here is what compiler complains:

$ gcc -Wall bitf.c -o bitf
bitf.c: In function ‘main’:
bitf.c:14:5: warning: overflow in implicit constant conversion [-Woverflow]

So, we see that compiler effectively treats the variables size as 1 bit only.

(From: http://www.thegeekstuff.com/)