Writing a Wide Bit Field

Writing a chunk of bits into an integer at a specific position requires major application of binary manipulation. That sounds impressive and mystical. To put it another way, writing a bit field is like using a stencil to paint a wall: You create the stencil, set it in place, then you slap down the paint.

To write a bit field, I crafted a function called bit_field_write(). It’s the companion to bit_field_read(), covered in last week’s Lesson. It uses similar arguments:

void bit_field_write(char bit, char width, char value, char *byte);

The bit and width arguments represent the position and size of the binary chunk to write. bit is the position measured from the right-most bit, position 0. width is the size of the chunk to be written.

The value argument is the chunk of binary data to be written at position bit.

Finally, *byte is a pointer to the variable that contains the bit field. It’s a pointer so that the variable is manipulated directly. That way the function need not return a value.

The function itself is divided into four parts:

1. Create the bit mask of a given width.
2. Shift the mask and the value left to the proper bit position.
3. Invert the mask, so that the existing values in the byte are preserved.
4. Write the bit field.

Figure 1 illustrates this process using a field 4 bits wide at position 3 in an 8-bit byte.

Figure 1. The steps required to write a bit field at a specific position within a byte.

Figure 1. The steps required to write a bit field at a specific position within a byte.

First, the bit field and mask are shifted to the proper bit position. Then an ^ (exclusive OR) inverts the mask. The mask is applied to the original value, then a | (bitwise OR) set the bits. The following code shows this operation in the function bit_field_write():

void bit_field_write(char bit, char width, char value, char *byte)
{
    unsigned char mask;

    mask = 0;
    while(width--)
    {
        mask = mask << 1;
        mask |= 1;
    }

    /* position the value and the mask */
    value = value << bit;
    mask = mask << bit;
    /* invert the mask */
    mask ^= 0xFF;
    /* filter the existing value, reset to zero */
    *byte &= mask;
    /* set the bit field */
    *byte |= value;
}

I’ve written a sample program that uses both bit_field_write() and bit_field_read(). The code is a bit long; you can view the entire thing here, but this is the main() function:

int main()
{
    char board,row,column;

    row = 2;
    column = 4;
    board = 0;

    bit_field_write(ROW_BIT,FIELD_WIDTH,row-1,&board);
    bit_field_write(COL_BIT,FIELD_WIDTH,column-1,&board);

    printf("The Queen is at row %d, column %d\n",
            bit_field_read(ROW_BIT,FIELD_WIDTH,board)+1,
            bit_field_read(COL_BIT,FIELD_WIDTH,board)+1
            );

    return(0);
}

Two calls are made to bit_field_write(), which set the Queen’s row and column position. Inside the printf() function, the bit_field_read() functions report those positions. The row and column variables are adjusted to account for row 0 and column 0. Here is sample output:

The Queen is at row 2, column 4

The bit_field_read() and bit_field_write() functions need modification if you plan on reading and writing to larger integer variables, yet they would still function the same. As I wrote in last week’s Lesson, I would definitely add bounds checking to the functions if I were to create and release a library. Feel free to add that code to the functions on your own.

Leave a Reply