Bit fields in C

Bit Fields in C Language

Bit Fields in C Language

Bit fields

It seems a wastage of memory when we need few number of bits but the data types provided by the language are not appropriate according to our need. For example, to define a true/false flag, we just need a single-bit flag (when the bit is 0 it means false, and when the bit is 1 it means true).

Similarly, we may need an integer value whose range is not more than 7 ( suppose seven days of the week), in which case we need only a 3-bit integer (to store values from 000 to 111). Such data items, together, can be packed into an individual word of memory.

To do so, the word is subdivided into separate fields made up of required number of bits. These fields are therefore known as bit-fields. These bit-fields are defined as members of a structure ( or union).

C allows a structure to restrict its members to fewer number of bits. An unsigned or int member of a structure (or, union) can be declared to be made up of a specified number of bits. Such member is called a bit-field, and the number of bits associated with that field is (in bits, and not in bytes). Usually,  bit fields  are declared as consecutive members of a structure, and the compiler packs them to a minimal number of machine words.

Advantages of bit-fields

  • In packing the objects, that are made up of several bits, into an integer (i.e., machine word). This makes read/write and other operations work as if they were int.
  • In writing routines for encryption/decryption.
  • In accessing the particular system resources.
  • In handling the external file formats ( even the non-standard file formats).
  • Making those manipulations much easier which were made unnecessary and difficult if done by using

 

Disadvantages of bit-fields

  • Using bit-fields costs loss of portability, since word-size varies from machine to machine.
  • We cannot take address of a bit-field.
  • Bit-fields cannot be made arrays.
  • Size of bit-fields cannot be taken (using sizeof() operator).
  • Bit fields cannot be pointers.

Limitations of a bit-field

  • Bit-fields do not have address, so & operator cannot be applied on them. So, they cannot be read using a scanf()  function also.
  • Bit-fields cannot be accessed using pointers. So indirection operator (*) cannot be applied on them.
  • Bit-fields cannot  be arrays, i.e. subscripting [] cannot be applied on them. The reason is that when indirection operator (*) cannot be applied on bit-fields, then how can [] be (as a[i] is treated internally as * (a+i))?
  • We cannot get the sizes of bit-fields. So, sizeof operator cannot be applied on them. The reason for this is that sizeof operator returns the number of bytes (not bits). So, id size of were allowed to work on bit-fields too, it would have been confusing whether sizeof were allowed to work on bit-fields too, it would have been confusing whether sizeof is returning the number of bits, or the number of bytes the member occupies.
  • They must be declared prior to any other non bit-field member.
  • Bit-fields cannot store values beyond their limits.

Declaration of bit-fields

Bit fields are just the extension of structures.

Syntax of Bit-Fields :

struct tag

{

   type member1 : width 1;

   type member2 : width2 ;

   . . .

   type memberN : widthN;

}

  • member1, member2 , . . , memberN are bit-field members of the structure struct tag.
  • The type indicates the data type of a bit-field, which can only be an integral type (signed and unsigned char, short , int, long, or an enumerated type).
  • Width1, width2, . . ., widthN are the widths of (i.e. number of bits used y) the bit- fields to store values. These widths must be present, and should be in the range 1 and 16 because, usually a word is made up of 2 bytes (16 bits). Though, some machines implement a word of 4 bytes too!).
  • If the member name is omitted, the number of bits specified in its width is allocated, but the field is inaccessible. Sometimes, the member name is knowingly omitted for padding and alignment purpose.
  • The values assigned to bit-fields should not exceed the limit. For example, if the width of a bit –field is 8, it can store values between -128 to 127 for signed int and between 0 to 255 for unsigned int.
  • The integer fields are stored in 2’s complement form, with the leftmost bit being the MSB is interpreted as a sign bit, while it is not the case with unsigned int bit-fields.
  • So, if a bit-field of width 1 is holding a binary value 1, then it will be interpreted in decimal as 1 if the type of the bit-field is unsigned, and -1 if the type of the bit-field is signed int. Similarly, if a bit-field of width 2 is holding a binary value 11, then that value is interpreted as 3 if the type of the bit-field is unsigned, and -1 if the type of the bit-field is signed int. Further, if a bit-field of width 3 is holding a binary value 1100, then it will be interpreted as 12 if bit-field is unsigned and -4 if the bit-field is signed int.

Example:

struct abc

{

    unsigned i : 1 ;            /* i takes only 1 bit out of the 16

                        bit word. This is least significant bit (lsb) */

int  j: 4;     /* j takes the next 4 bits after the bit occupied by

  1. So, it takes bits 2 to 5 */

int k:3;                         /*k takes the next 3 bits after the bits

                         occupied by j . So, it takes bits 6 to 8 */

unsigned m:8;               /* 1 takes the next 4 bits after the

                  bits occupied by 1. So, it takes bits 9 to 16 */

}x;

The position of the 16-bit word in the memory is like:

Bit fields in C
Bit fields in C

So, if the following statements are executed,

x.i= 1;                                /* 1 in decimal = 1 in binary */

x.j=12;                            /* 12 in decimal = 1100 in binary */

x.k=3;                                /* 3 in decimal = 011 in binary */

x.m =15;                         /*15 in decimal = 1111 in binary */

 Padding and Alignment :

All the bit-fields may not be named. Some of them may be unnamed ones. These unnamed bit-fields are used for padding and alignment purpose, and they cannot be accessed and used from the code. Padding means to leave some bits of the word (suppose if 16 bits is the word size) unused in order to align the word (to the next word).

Example :

struct xyz

{

    unsigned a : 3 , b:3 , c:3,

   :7,         /* pad next 7 bits to make 16 bits ( 1 word)

                 complete, to align to next word. */

    d:4, e:4, f:3;

};

Another way to cause alignment to the next word is, using an unnamed bit-field specified with) width. This is shown below:

struct xyz

{

     unsigned a:9,           /* only 9 bits of a 16-bit word are used , so */

                        :7,         /* pad next 7 bits to align to next word. */

                 B:9,          /*  Again, only 9 bits of a 16-bit word are used, so */

                  :7,                       /* once again pad next 7 bits to align to next word. */

           C:9;                /* Now, we are using the third 16-bit word. */

} ;

The above structure creates three bit-fields , each of width 9-bit, in three separate words.

Self-referential structures

Though it is not possible for a variable to be declared as a member of a structure definition if that variable has the structure type itself. That is, we cannot define a structure like

struct tag

{

    …

    struct tag member;     /* not possible to have a member of type struct tag*/

};

 But, we can have a pointer to the structure type itself, as a member of the structure definition., as shown below

struct tag

{

   . . .

    struct tag *member;    /* O.K. , we can have a member that is a pointer to struct tag  */

};

Thus, a structure of type tag can contain  a member that points to another structure of type tag. Such structures are known as self-referential structures. Self-referential structures are mainly useful to define linked data structures like linked-lists, binary trees, etc.

Linked lists

A linked list is a linear homogeneous collection of data items, called nodes. The linear order is given by  pointers. Each node is divided into two parts :

  • Information part: which contains the information of the element
  • Link part: which contains the address (i.e. link) of the next node in the list.

One more pointer variable (say, head) is used that contains the address of the first node of the list. The link part of the last element of the list will contain a value NULL to indicate the ending of the list.

How to represent a linked list?

  Suppose we want t store a list of strings, then the linear linked list would be represented in the memory as :

      

Linked List
Linked List

                                        

#define Max 50

typedef  char * itemptype; * define new type string as char *  */

typedef struct node

{

      char str [MAX] ; /* information part of the node */

      struct node * link; /* link part of the node */

 }Node;               /* now onwards, Node is same as struct node */

Node * head;        /* pointer to the first  node of the list */

 

Operations on ( linear) linked list

 

Creating an empty list

 

void createlist(Node ** head)

{

      *head = NULL;

}

(void insert_at_beg(Node **head, itemtype item);)

 

Inserting at the beginning of the list

 

 Step-1 : create a new node, and allocate memory for it :

        

             Node *newnode;

                   newnode=  (Node *)malloc(sizeof(Node));

             

Step-2 : insert the item into the info part of this new node :

              newnode->info = item;

               

Step-3  :  now, if the list is initially empty ( i.e., list has not even a single node) :

if (*head == NULL)

and, assign this new node to head (so that the head can control the whole list) :

*head=newnode;

  Step-4 : otherwise, if the list is not empty ( i.e., list consists one or more nodes) then, insert new node at the end of the list :

 

    Node *loc;

    loc  =   *head;

    while(loc ->link ! =NULL)

    loc->next = newnode;

 

void insert_at_end (Node **head, string str)

{

    Node *newnode; /* create a  new node */

    newnode=(Node *)malloc(sizeof(Node));

    newnode->info = s; 

     if(*head == NULL)    /*if list is initially empty,      then */

        newnode->link=NULL; 

      else

         newnode->link =*head;                   

*head=newnode;     /*assign new node to head*/

}

 

Inserting an element at the end of the list

(void insert_at_beg (Node  **head, itemtype item) 😉

Inserting at the end of the list

Step-1 : create a new node, and allocate memory for it :

   Node * newnode;

   newnode = (Node *)malloc(sizeof(Node));

Step -2 : insert the item ito the info part of this new node :

     newnode-> info  = item;

Then, make its link part NULL

     newnode ->Link =NULL;

      Step-3 :now, if the list is initially empty (i.e., list has not even a single node):

    If (*head == NULL)

And, assign this new node to head (so that the head can control the whole list) :

    *head=newnode;

    Step-4 :  otherwise, if the list is not empty (i.e., list consists one or more nodes) then, insert new node at the end of the list :

 Node *loc;

 loc = *head;

 while(loc->link !=NULL)

 loc= loc->link;

 loc->next = newnode;

 void insert_at_end(Node **head, string str)

{

    Node *newnode;                          /* create a new node */

    newnode=(Node*)malloc(sizeof(Node));                 

    newnode->info=s;

if(*head == NULL)   /* if list is initially empty, then */

     newnode->link =NULL;

else

newnode->link = *head;                    

*head=newnode;      /* assign new node to head. */

}

Unions

A union is a specialized version of a structure. The syntax for both is mostly the same and they are just semantically different. A union is a variable that may hold, at different times, objects of different sizes and types. A union  variable occupies a memory space equal to the size of its largest member. Then, each member can share this space at different times, when their turn to use that memory space comes. C uses the union statement  to create unions, for example:

union abcd

{

    char a;

    int b;

    long c;

    double d;

};

union abcd x;

Similar Posts:

You May Also Like: 

How to Generate Output in JavaScript               Multiple GST and Interstate Sales invoice       What is New in HTML5

Download Official TurboC Compiler from here

 

5 1 vote
Article Rating
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
trackback
11 months ago

[…] in C                        Bit Fields in C Language                          Structures in […]

trackback
10 months ago

[…] Bit Fields in C Language […]

Please Subscribe to Stay Connected

You have successfully subscribed to the newsletter

There was an error while trying to send your request. Please try again.

DigitalSanjiv will use the information you provide on this form to be in touch with you and to provide updates and marketing.
Share via
Copy link
Powered by Social Snap
%d bloggers like this: