In C language structure and union support a very important feature that is the bit field. The bit field allows the packing of data in a structure or union and prevents the wastage of memory.

Note: The layout of the bit-fields is implementation-defined that is the reason a lot of people are avoiding the use of bit-filed.

Syntax of bit fields in C:

In C language declaration of the bit-field structure or union is similar to the declaration of the normal structure or union, the main difference is that bit-field member is declared with a specified number of bits preceded by the colon.

struct

{

type-specifier declarator opt : constant-expression

};

In the above declaration, constant-expression specifies the width of the field in bits and must be a non-negative integer value. If the value is zero, the declaration has no declarator.

The type-specifier for the declarator must be _Bool, signed int, unsigned int, or some other implementation-deﬁned type. It is implementation-deﬁned whether atomic types are permitted.

Example,

Let’s take an example to understand the structure bit field.

struct packed_data {

unsigned int data1:1;

unsigned int data2:1;

unsigned int data3:1;

unsigned int data4:1;

unsigned int data5:1;

unsigned int data6:3;

unsigned int data7:6;

} sPackData;

In below statement, structure packed_data contains 7 members. In which five-member (data1 to data5) has 1 bit and 6th and 7th member has the 3 and 6 bits.

Way to access the member:

sPackData.data6 = 3;

For learning more, you can signup for the free trial of this popular c video course by Kenny Kerr.

Use of bit field in embedded C?

Suppose a microcontroller has a port of 8 pins and each pin are connected to the led. In that scenario using the bitfield, 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->LED2 = 0;

Note: Here, I am only describing, how is the bit-field work. I am not suggesting to use 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 can be different from another compiler. So we should avoid the compiler-dependent code, In simple word, avoid using bit fields for the mapping of the hardware register.



Some important points about bit field in c

If we are compiled the same C program that uses the bit-field on a different system, the result of the program may vary (C program may not work properly).

The order of allocation of bit-ﬁelds within a unit low-order to high-order or high-order to low-order ( depend on endianness )is implementation-deﬁned.

#include <stdio.h> #define CHAR_BITS 8 // size of character #define INT_BITS ( sizeof(int) * CHAR_BITS) //bits in integer // Use to print the data in binary format void PrintInBinary(unsigned n) { short int iPos; for (iPos = (INT_BITS -1) ; iPos >= 0 ; iPos--) { (n & (1 << iPos))? printf("1"): printf("0"); } } struct sBitField { unsigned int Data00:8; unsigned int Data01:8; unsigned int Data02:8; unsigned int Data03:8; }; int main( int argc, char* argv[] ) { struct sBitField sBits ; int *pData = (int*)&sBits; *pData = 0; //Clear all bits PrintInBinary(*pData ); // Print bits putchar('

'); sBits.Data00 = 0x11; PrintInBinary(*pData); // Print bits putchar('

'); sBits.Data01 = 0x22; PrintInBinary(*pData ); // Print bits putchar('

'); sBits.Data02 = 0x33; PrintInBinary(*pData); // Print bits putchar('

'); sBits.Data03 = 0x44; PrintInBinary(*pData); // Print bits putchar('

'); }

When running on a machine (Linux):

00000000000000000000000000000000

00000000000000000000000000010001

00000000000000000010001000010001

00000000001100110010001000010001

01000100001100110010001000010001

If insufﬁcient space remains, whether a bit-ﬁeld that does not ﬁt is put into the next unit or overlaps adjacent units is implementation-deﬁned.

#include <stdio.h> struct sData { unsigned int a: 2; unsigned int b: 2; unsigned int c: 2; }; int main() { struct sData data; data.a = 5; printf("%d", data.a ); return 0; }

Output:

Implementation-Dependent

We can not create a pointer to the bit-field and also not use the address-of operator (&) to the bit-field member.

#include <stdio.h> struct sData { unsigned int a: 2; unsigned int b: 2; unsigned int c: 2; }; int main() { struct sData data; data.a = 2; printf("Address of data.a = %p", &data.a ); return 0; }

Output:

[Error] cannot take address of bit-field ‘a’

We can not create an array of a bit field in c.

#include <stdio.h> struct sData { unsigned int a: 2; unsigned int b[5]: 2; }; int main() { struct sData data; data.a = 2; return 0; }

Output:

[Error] bit-field ‘b’ has an invalid type.

The bit fields must also be long enough to contain the bit pattern. See the below example,

struct sData { unsigned int a: 2; short b: 17; /* Illegal! */ unsigned int c: 2; };

The alignment of the addressable storage unit is unspeciﬁed.

If enough space remains, a bit ﬁeld that immediately follows another bit-ﬁeld in a structure shall be packed into adjacent bits of the same unit.

A bit ﬁeld declaration with no declarator is called unnamed bit field. If the width of the unnamed bit-field is 0 (zero), it indicates that no further bit-ﬁeld is to be packed into the unit in which the previous bitﬁeld, if any, was placed.

See the below example, here I have created two structure. In the second structure, I am using the unnamed bit-field with 0 widths for the force unalignment.

#include <stdio.h> // A structure without forced alignment typedef struct { unsigned int data1: 5; unsigned int data2: 8; }sData1; // A structure with forced alignment typedef struct { unsigned int data1: 5; unsigned int: 0; unsigned int data2: 8; }sData2; int main() { printf("Size of sData1 = %d

", sizeof(sData1)); printf("Size of sData2 = %d

", sizeof(sData2)); return 0; }

Output:

Size of sData1 = 4

Size of sData2 = 8

We can not calculate the size of the bit field in c using the sizeof operator.

#include <stdio.h> struct sData { unsigned int a: 2; unsigned int b: 2; unsigned int c: 2; }; int main() { struct sData data; printf("Sizeof of data.a = %d", sizeof(data.a)); return 0; }

Output:

[Error] ‘sizeof’ applied to a bit field.





