Search code examples
cmemorybitwise-operatorsbitbit-fields

Implementation of bit field in c


We have been given an assignment to create a made - up version of an assembler (not with the exact assembly commends)

We have been instructed to use memory efficiently (not in a big O notation type of memory efficiency, but rather efficient to use data structures)

Since each command is translated into 24 bit machine code, I figured that the most efficient way to store the command's machine code is using bit fields, So I implemented the following bit field:

(in bit_field.c)

#include "bit_field.h"
int set_bit(bit_field *destination, int location, enum bit_values value)
{
    if(location >= BITS)
        return 0;
    if(value == ONE)
        (destination)[location / BITS_IN_BYTE] |= 1UL << location % BITS_IN_BYTE;
    else
        (destination)[location / BITS_IN_BYTE] &= ~(1UL << location % BITS_IN_BYTE);
    return 1;
}
enum bit_values get_bit(bit_field *destination, int location)
{
    return ((destination)[location / BITS_IN_BYTE] >> location % BITS_IN_BYTE) & 1U;
}
void init_bit_field(bit_field *new_bit_field)
{
    int i;
    for(i = 0; i < BITS; i++)
        set_bit(new_bit_field, i, ZERO);
}
void init_bit_field_by_str(bit_field *new_bit_field, char *string)
{
    int i;
    for(i = 0; i < BITS; i++)
        set_bit(new_bit_field, i, *string++ - '0');
}

(in bit_field.h)

#define BITS 24
#define BITS_IN_BYTE 8
#define BYTES BITS / BITS_IN_BYTE
enum bit_values {ZERO = 0, ONE = 1}bit_values;
typedef unsigned char byte;
typedef byte bit_field [BYTES];
int set_bit(bit_field *, int , enum bit_values);
enum bit_values get_bit(bit_field *, int);
void init_bit_field(bit_field *);
void init_bit_field_by_str(bit_field *, char *);;

(test at input.c)

#include "bit_field.h"
#include <stdio.h>
int main()
{
    int i;
    bit_field bits;
    init_bit_field(&bits);
    set_bit(&bits, 22, ONE);
    for(i = 0; i < BITS; i++)
        printf("%d, ", get_bit(&bits, i));
    return 0;
}

When I try to compile the following code (gcc C90) I get the following errors:

bit_field.c:14:53: error: invalid operands to binary >> (have ‘byte (*)[3] {aka unsigned char (*)[3]}’ and ‘int’)
     return ((&destination)[location / BITS_IN_BYTE] >> location % BITS_IN_BYTE) & 1U;
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~
bit_field.c:15:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
avivgood@ubuntuVM:~/CLionProjects/Maman14$ gcc -Wall -ansi -pedantic input.c bit_field.c bit_field.h -o example.out
bit_field.c: In function ‘set_bit’:
bit_field.c:7:49: error: invalid operands to binary | (have ‘byte (*)[3] {aka unsigned char (*)[3]}’ and ‘long unsigned int’)
         (&destination)[location / BITS_IN_BYTE] |= 1UL << location % BITS_IN_BYTE;
                                                 ^~
bit_field.c:9:49: error: invalid operands to binary & (have ‘byte (*)[3] {aka unsigned char (*)[3]}’ and ‘long unsigned int’)
         (&destination)[location / BITS_IN_BYTE] &= ~(1UL << location % BITS_IN_BYTE);
                                                 ^~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bit_field.c: In function ‘get_bit’:
bit_field.c:14:53: error: invalid operands to binary >> (have ‘byte (*)[3] {aka unsigned char (*)[3]}’ and ‘int’)
     return ((&destination)[location / BITS_IN_BYTE] >> location % BITS_IN_BYTE) & 1U;
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~
bit_field.c:15:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

The errors doesn't seem to make any sense. my method of setting and resting bit should work. So why does it generate so many errors?


Solution

  • Here you define

    typedef unsigned char byte;
    typedef byte bit_field [BYTES];
    

    So bit_field is an array which has BYTES elements. But, when you define the function, you use pointer to bit_field:

    int set_bit(bit_field *, int , enum bit_values);
    enum bit_values get_bit(bit_field *, int);
    void init_bit_field(bit_field *);
    void init_bit_field_by_str(bit_field *, char *);
    

    It's reason why program raises the error with bit operator. When you use:

    destination[location / BITS_IN_BYTE]
    

    This has the type unsigned char *. This is why we have the error:

     invalid operands to binary
    

    Thus, you can use just bit_field instead of bit_field * as the argument of the function. Then in the function do not use ampersand (&) as:

    destination[location / BITS_IN_BYTE]