I have another method for accomplishing this. You can use a union
of an integer type that has enough bits for your application and a bit field struct
.
Example:
typedef thesebits
{
unsigned long first4 : 4;
unsigned long second4 : 4;
unsigned long third8 : 8;
unsigned long forth7 : 7;
unsigned long fifth3 : 3;
unsigned long sixth5 : 5;
unsigned long last1 : 1;
} thesebits;
you can set that struct
up to whatever bit pattern you want. If you have multiple bit patterns, you can even use that in your union as well.
typedef thesebitstwo
{
unsigned long first8 : 8;
unsigned long second8 : 8;
unsigned long third8 : 8;
unsigned long last8 : 8;
} thesebitstwo;
Now you can set up your union:
typedef union myunion
{
unsigned long mynumber;
thesebits mybits;
thesebitstwo mybitstwo;
} myunion;
Then you can access the bits you want from any number you assign to the member mynumber:
myunion getmybits;
getmybits.mynumber = 1234567890;
If you want the last 8 bits:
last16bits = getmybits.mybitstwo.last8;
If you want the second 4 bits:
second4bits = getmybits.mybits.second4;
I gave two examples kind of randomly assigned different bits to show. You can set the struct bit-fields up for whatever bits you want to get. I made all of the variables type unsigned long
but you can use any variable type as long as the number of bits doesn't exceed those that can be used in the type. So most of these could have been just unsigned int
and some even could be unsigned short
The caveat here is this works if you always want the same set of bits over and over. If there's a reason you may need to vary which bits you're looking at to anything, you could use a struct with an array that keeps a copy of the bits like so:
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct bits32
{
bool b0 : 1;
bool b1 : 1;
bool b2 : 1;
bool b3 : 1;
bool b4 : 1;
bool b5 : 1;
bool b6 : 1;
bool b7 : 1;
bool b8 : 1;
bool b9 : 1;
bool b10 : 1;
bool b11 : 1;
bool b12 : 1;
bool b13 : 1;
bool b14 : 1;
bool b15 : 1;
bool b16 : 1;
bool b17 : 1;
bool b18 : 1;
bool b19 : 1;
bool b20 : 1;
bool b21 : 1;
bool b22 : 1;
bool b23 : 1;
bool b24 : 1;
bool b25 : 1;
bool b26 : 1;
bool b27 : 1;
bool b28 : 1;
bool b29 : 1;
bool b30 : 1;
bool b31 : 1;
} bits32;
typedef struct flags32 {
union
{
uint32_t number;
struct bits32 bits;
};
bool b[32];
} flags32;
struct flags32 assignarray ( unsigned long thisnumber )
{
struct flags32 f;
f.number = thisnumber;
f.b[0] = f.bits.b0;
f.b[1] = f.bits.b1;
f.b[2] = f.bits.b2;
f.b[3] = f.bits.b3;
f.b[4] = f.bits.b4;
f.b[5] = f.bits.b5;
f.b[6] = f.bits.b6;
f.b[7] = f.bits.b7;
f.b[8] = f.bits.b8;
f.b[9] = f.bits.b9;
f.b[10] = f.bits.b10;
f.b[11] = f.bits.b11;
f.b[12] = f.bits.b12;
f.b[13] = f.bits.b13;
f.b[14] = f.bits.b14;
f.b[15] = f.bits.b15;
f.b[16] = f.bits.b16;
f.b[17] = f.bits.b17;
f.b[18] = f.bits.b18;
f.b[19] = f.bits.b19;
f.b[20] = f.bits.b20;
f.b[21] = f.bits.b21;
f.b[22] = f.bits.b22;
f.b[23] = f.bits.b23;
f.b[24] = f.bits.b24;
f.b[25] = f.bits.b25;
f.b[26] = f.bits.b26;
f.b[27] = f.bits.b27;
f.b[28] = f.bits.b28;
f.b[29] = f.bits.b29;
f.b[30] = f.bits.b30;
f.b[31] = f.bits.b31;
return f;
}
int main ()
{
struct flags32 bitmaster;
bitmaster = assignarray(1234567890);
printf("%d\n", bitmaster.number);
printf("%d\n",bitmaster.bits.b9);
printf("%d\n",bitmaster.b[9]);
printf("%lu\n", sizeof(bitmaster));
printf("%lu\n", sizeof(bitmaster.number));
printf("%lu\n", sizeof(bitmaster.bits));
printf("%lu\n", sizeof(bitmaster.b));
}
The issue with this last example is that it's not compact. The union itself is only 4 bytes, but since you can't do pointers to bit-fields (without complicated and debatably "non-standard" code), then the array makes a copy of each boolean value and uses a full byte for each one, instead of just the bit, so it takes up 9x the total memory space (if you run the printf statement examples I gave, you'll see).
But now, you can address each bit one-by-one and use a variable to index each one, which is great if you're not short on memory.
By using the typedefs above and the assignarray
function as a constructor for flags32
, you can easily expand to multiple variables. If you're OK just addressing with .b# and not being able to use a variable, you can just define the union as flags32
and omit the rest of the struct. Then you also don't need the assignarray
function, and you'll use much less memory.
x % (2 ^ n)
(x % 16
->x % 2^4
-> 4 bits, and similarlyx % 32
-> 5 bits). If you dox % n
then you'll find that your output only ranges from 0 to n-1, whereas n bits can contain numbers 0 to 2^n-1. – Lecompte