Tuesday, 7 October 2014

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, unions and bit fields are comparatively less used but that does not undermine their importance.
In this tutorial we will explain the concept of Structures, Unions and Bit fields in C language using examples.


1. Structures in C

Structure provides 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 definitions 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 a 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;
NOTEThe keyword ‘struct’ is mandatory while defining structure objects in C
The variable ‘emp_obj’ now becomes object of ‘employee’ structure. Individual structure members can be accessed in the following way :
     emp_obj.name
     emp_obj.age
     ...
     ...
     ...
So we see that ‘.’ is used to access individual variables
Unlike the one above, a structure object can also be of a 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 ‘->’ is used to access individual variables.
Here is a 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? No worries, lets understand it in more detail.
Here is how Unions 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)
ie 1 + 4 = 5 bytes.
But, in case of a union, the size is equivalent to that of the largest member type in 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 a wise 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]
On a different note, to get more deeper understanding of C language, you should also know howC Macros / Inline Functions and C Binary Tree works.

3. Bit fields in C

There are times when the member 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 8 bytes.
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.
Bit fields allow efficient packaging of data in the memory. Here is how bit fields are defined :
struct info
{
    int isMemoryFreed : 1;
    int isObjectAllocated : 1;
}
The above declaration tells the compiler that only 1 bit each from the two variables would be used. After seeing this, the compiler reduces the memory size of the structure.
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 bits. 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.

No comments:

Post a Comment