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?
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]