Reputation: 35
So I need some help getting this right. I have an assignment like this:
typedef struct {
char status[1];
} Dish;
The variable status
must only have 1 byte: first 3 bits will contain the number of stars the dish has(0-5), 4th bit tells us if the dish is canceled or not and the 5th bit tells us if the dish is ongoing or not. I tried getting the number of stars like this but it doesn't work:
getBit(char data, int bitNumber) {
return (data & (1 << bitNumber-1)) != 0;
}
int number = 0;
number = getBit(dish.status,0);
number = number << 1 + getBit(dish.status,1);
number = number << 1 + getBit(dish.status,2);
Since status
must only have 1 byte I declared it as above char status[1]
is it correct?
I also tried using binary operations directly on status
but it gives me an error saying that I can't use binary operations between a char
and an int
. My final objective is getting every information in that byte into a separate variable: stars
, canceled
, ongoing
.
Upvotes: 0
Views: 119
Reputation: 3872
As warned about in comments below, kindly note that the behavior of this code is not guaranteed to be consistent across all platforms.
The suggested answers gets the work done. If you don't want to get into bit-shift operations try this:
typedef struct dist {
union {
struct {
uint8_t number_of_stars : 3 ;
uint8_t cancel_status : 1 ;
uint8_t ongoing_status :1 ;
uint8_t reserved : 3;
};
uint8_t status;
};
} DishType;
DishType Dish;
If you check the size of Dish
you'll see that it still consumes one byte of memory.
You can set the parameters in a single line such as:
Dish.status = 0x0C; // For example
Or you can set the particular parameter like:
Dish.cancel_status = 1;
Dish.ongoing_status = 0;
And yet, access or print or modify it individually:
printf("\nNo. of starts = %u", Dish.number_of_stars);
Upvotes: 1
Reputation: 363
With some tweaks your code works:
int getBit(char data, size_t bitNumber) {
return (data & (1 << (bitNumber - 1))) != 0;
}
int main(void) {
char status = 3 + (1 << 5);
for (size_t i = 1; i <= 8; ++i) {
printf("Bit %d: %d\n", (int) i, getBit(status, i));
}
return 0;
}
I used size_t for the bit number (which is unsigned) and fixed the braces around the term.
With bit fields, the code could look like this:
#include <stdio.h>
typedef struct {
union {
struct {
unsigned stars:3;
char cancelled:1;
char ongoing:1;
};
unsigned char data;
};
} Dish;
void printDish(Dish dish) {
printf("Stars = %d, Cancelled = %d, Ongoing = %d\nValue: %d\n", dish.stars, dish.cancelled, dish.ongoing, dish.data);
}
int main(void) {
Dish dish1;
dish1.stars = 3;
dish1.cancelled = 1;
dish1.ongoing = 1;
printDish(dish1);
Dish dish2;
dish2.stars = 5;
dish2.cancelled = 0;
dish2.ongoing = 0;
printDish(dish2);
return 0;
}
This will output:
clang version 7.0.0-3~ubuntu0.18.04.1 (tags/RELEASE_700/final)
clang-7 -pthread -lm -o main main.c
./main
Stars = 3, Cancelled = -1, Ongoing = -1
Value: 27
Stars = 5, Cancelled = 0, Ongoing = 0
Value: 37
You can access the 'char' value with .data and everything else with named fields. If you want to cast the file you read (via fread), you probably want to make sure alignment of the struct is correct.
See https://repl.it/repls/SimultaneousIncredibleRoot
Upvotes: 2
Reputation: 311108
There is no great sense to declare the data member status as an array with one element
char status[1];
You could declare it like
unsigned char status;
The function can look like it is shown in the demonstrative program below.
#include <stdio.h>
#include <limits.h>
unsigned int getBit( unsigned char data, unsigned int bitNumber )
{
bitNumber %= CHAR_BIT;
return ( data & (1 << bitNumber ) ) != 0;
}
int main(void)
{
for ( int i = 0; i <3; i++ )
{
printf( "%d\n", getBit( 6, i ) );
}
return 0;
}
The program output is
0
1
1
On the other hand, as the data member status
consists from bit fields then instead of extracting one bit you could use masks for each bit field to extract it.
Another approach is to use bit fields instead of an object of the type unsigned char. Something like
typedef struct {
unsigned char stars: 3;
unsigned char cancelled: 1;
//...
} Dish;
Upvotes: 2