binary sequence in uint8_t - c

I'm trying to create a table in "c" (for an embedded application) where each row is a sequence of 8 bits, for example:
11010011
01010011
10000000
then I need to have functions to set/clear/read any bit in any row. What is the most efficient way to do that?
For bit manipulation I thought to use:
uint8_t msk = 0x01;
row3 |= msk;
But to do this I think I need to define row3 (and every row) as uint8_t and convert it to hexadecimal as well, and that leads me to my second question:
how to store an 8-bit binary sequence in a uint8_t? I've seen different ways to do similar tasks like the one discussed here but none of them worked for me. Can you help me?
Thanks.

To represent binary bit patterns in C, it is normal to use hexadecimal notation. The utility of hex is that a single hex digit exactly coincides with 4 binary digits, so with experience you can quickly convert between the 16 hex digits and the corresponding binary value in your head, and for longer integers it is simply a matter of converting each digit in turn - 4 bits at a time. Representing long integers in binary quickly becomes impractical.
So your table might be represented as:
uint8_t row[] = { 0xd3, // 11010011
0x53, // 01010011
0x80 // 10000000
} ;
Then you set/clear bits in the following manner:
row[2] |= mask ; // Set mask bits
row[0] &= mask ; // Clear mask bits
To create a mask specifying numbered bits without hard-coding the hex value you can use an expression such as:
uint8_t mask = 1<<7 | 1<<5 | 1<<0 ; // 10100001 mask bits 0, 5 & 7
Occasionally a "visual" binary representation is desirable - for character bitmaps for example, the character A is much easier to visualise when represented in binary:
00000000
00011000
00100100
01000010
01111110
01000010
01000010
00000000
It is possible to efficiently code such a table while maintaining the "visualisation" by exhaustively defining a macro for each binary value; e.g:
#define B_00000000 0x00
#define B_00000001 0x01
#define B_00000010 0x02
#define B_00000011 0x03
#define B_00000100 0x04
...
#define B_11111110 0xfe
#define B_11111111 0xff
Note to create the above macros, it is best perhaps to write a code generator - i.e. a program to generate the code, and put the macros in a header file.
Given such macros you can then represent your table as:
uint8_t row[] = { B_11010011
B_01010011
B_10000000
} ;
or the character bitmap for A thus:
uint8_t charA[] = { B_00000000,
B_00011000,
B_00100100,
B_01000010,
B_01111110,
B_01000010,
B_01000010,
B_00000000 } ;
In the case that the bits are received at run-time serially, then the corresponding uint8_t can be built using sequential mask and shift:
uint8_t getByte()
{
uint8_t mask = 0x80 ;
uint8_y byte = 0 ;
while( mask != 0 )
{
uint8_t bit = getBit() ;
byte |= bit ? mask : 0 ;
mask >>= 1 ;
}
return byte ;
}
What the getBit() function does is for you to define; it may read a file, or a string, or keyboard entry for example, but it must return either zero or non-zero or the binary digits 0 and 1 respectively. If the data is received LSB first then the mask starts from 0x01, and a << shift used instead.

C doesn't have a syntax for entering binary literals, so you should type them as octal or hex, e.g.
uint8_t row1 = 0xd3;
uint8_t row2 = 0x53;
uint8_t row3 = 0x80;
See How do you set, clear, and toggle a single bit? for how you can manipulate specific bits.
row3 |= mask;
will set the bits that are set in mask.

If I understand correctly, you require a list of hexadecimal numbers and you would like to manipulate the bits in any of the elements of the list. I would approach it by making an array of unsigned integers with the size of the array being defined by the number of elements you need in your table.
#include <stdio.h>
#include <stdint.h>
#define LIST_SIZE 3
//accepts the array and sets bit_pos bit of the list idx
int set_bit(uint8_t* hex_list, int list_idx, int bit_pos){
hex_list[list_idx] = hex_list[list_idx] | 0x01<<bit_pos; //left shift by the bit position you want to set
}
int clear_bit(uint8_t* hex_list, int list_idx, int bit_pos){
hex_list[list_idx] = hex_list[list_idx] & ~(0x01<<bit_pos); //left shifts and does logical inversion to get the bit to clear
}
int main(void) {
uint8_t hex_list[LIST_SIZE] = {0x00, 0x01, 0x02};
set_bit(hex_list, 0, 1); // will make 0th element 0x00-> 0x02 by seting bit position 1
clear_bit(hex_list, 1,0); //will make 1st element 0x01-> 0x00 by clearing bit position 0
set_bit(hex_list, 2, 0); // will make 2nd element 0x02->0x03 by setting bit at position 1
clear_bit(hex_list, 2 , 0);// will make 2nd element 0x03 ->0x02 by clearing bit at position 0
//print the result and verify
for(int i = 0; i<LIST_SIZE; ++i){
// modified array will be {0x02, 0x00, 0x02}
printf("elem%d = %x \n", i, hex_list[i]);
}
return 0;
}
An uint8_t in represents a 8-bit unsigned integer whose value can vary between 0(binary representation = 00000000)to 255(binary representation = 11111111).

Related

Best way to move 8 bits into 8 individual bytes [duplicate]

This question already has answers here:
How to create a byte out of 8 bool values (and vice versa)?
(8 answers)
Closed 3 years ago.
I have a status register with 8 bits. I would like to move each individual bit to a byte for further processing. Seems like it should be easy but every solution I come up with is convoluted. I was thinking about iterating through the bits with a for next loop and dumping them into an array but my solution way too messy.
Here's basically what you're trying to do. It uses bitwise operators and a uint8_t array to make each bit an individual byte:
void bits_to_bytes(uint8_t status, uint8_t bits[8])
{
int ctr;
for( ctr = 0; ctr < 8; ctr++ )
{
bits[ctr] = (status >> ctr) & 1;
}
}
OK, so a little more in-depth:
This code loops through the bits in a byte and then assigns bits[bit_number] to the bit_numberth bit of status.
If you want to reverse the order the bits are stored in, simply change bits[ctr] to bits[(8-1)-ctr].
For a start, you should be using uint8_t for eight-bit bit collections since char is fundamentally non-portable unless you add a lot of extra code for checking its size and signedness.
Something like this should suffice for your needs:
void BitsToBytes(uint8_t bits, uint8_t *bytes) {
for (int i = 0; i < 8; ++i) { // The type has exactly eight bits.
*bytes++ = (bits > 127); // 1 if high bit set, else 0.
bits = (bits & 0x7f) << 1; // Shift left to get next bit.
}
}
:
// Call with:
uint8_t inputBits = 0x42;
uint8_t outputBytes[8];
BitsToBytes(inputBits, outputBytes);
This takes a type with eight bits and a buffer of eight bytes, then places the individual bits into each byte of the array:
MSB LSB
+--------+
inputBits: |abcdefgh|
+--------+
+---+---+---+---+---+---+---+---+
outputBytes: | a | b | c | d | e | f | g | h |
+---+---+---+---+---+---+---+---+
If you want it to go the other way (where the LSB of the input is in element 0 of the array), you can simply change the body of the loop to:
*bytes++ = bits & 1; // 1 if low bit set, else 0.
bits = bits >> 1; // Shift right to get next bit.
You can use a double invocation of the ! operator to squash a zero/non-zero value to zero/one. Using this, the extracted value of bit n in status is !!(status & (1 << n)).
If you only have eight flags you might just create constants for the 8 values of 1 << n (0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80). This works particularly well if your flags all have individual names rather than numbers, so that you might have in a header file somewhere:
#define FLAG_FROB 0x01
#define FLAG_FOO 0x02
#define FLAG_BAR 0x04
#define FLAG_BAZ 0x08
#define FLAG_QUUX 0x10
Then in the code you'd just extract them as
flag_frob = !!(status & FLAG_FROB);
flag_foo = !!(status & FLAG_FOO);
flag_bar = !!(status & FLAG_BAR);
flag_baz = !!(status & FLAG_BAZ);
flag_quux = !!(status & FLAG_QUUX);

Bitwise rotate right of 4-bit value

I'm currently trying to control a stepper motor using simple full steps. This means that I'm currently outputting a sequence of values like this:
1000
0100
0010
0001
I thought an easy way to do this was just take my 4-bit value and after each step, perform a rotate right operation. "Code" obviously isn't following any kind of syntax, it's simply there to illustrate my thoughts:
step = 1000;
//Looping
Motor_Out(step)
//Rotate my step variable right by 1 bit
Rotate_Right(step, 1)
My problem is that there obviously isn't any 4-bit simple data types that I can use for this, and if I use an 8-bit unsigned int I will eventually rotate the 1 off to the MSB, which means the 4-bit value I'm actually interested in, will turn into 0000 for a few steps.
I've read that you can use structs and bit-fields to solve this, but the majority of things I read from this is telling me that it's a very bad idea.
With only 4 possible values you would use a table with 9 elements:
unsigned char table_right[] = { [0x1] = 0x8 , [0x2] = 0x1 , [0x4] = 0x2 , [0x8] = 0x4 };
When you need the next value you simply use the current value as the index:
unsigned char current = 0x4; //value is: 0b0100
unsigned char next = table_right[current]; //returns: 0b0010
assert( next == 0x2 );
Doing this in a loop, will loop through all four possible values.
Conveniently, passing an invalid value, will return a zero, so you can write a get function that also asserts next != 0. You should also assert value < 9 before passing the value to the array.
Just use an int to hold the value. When you do the rotate copy the least significant bit to bit 4 and then shift it right by 1:
int rotate(int value)
{
value |= ((value & 1) << 4); // eg 1001 becomes 11001
value >>= 1; // Now value is 1100
return value;
}
The arithmetic for this is simple enough that it will always be faster than the table approach:
constexpr unsigned rotate_right_4bit ( unsigned value )
{
return ( value >> 1 ) | ( ( value << 3 ) & 15 );
}
This turns into 5 lines of branch-free x86 assembly:
lea eax, [0+rdi*8]
shr edi
and eax, 15
or eax, edi
ret
Or, alternatively, if you actually like to see the indexes {3, 2, 1, 0}, then you can split them up into 2 functions, one that "increments" the index, and the other that actually computes the value:
constexpr unsigned decrement_mod4 ( unsigned index )
{
return ( index - 1 ) & 3;
}
constexpr unsigned project ( unsigned index )
{
return 1u << index;
}
IMO the easiest way is:
const unsigned char steps[ 4 ] = { 0x08, 0x04, 0x02, 0x01 };
int stepsIdx = 0;
...
const unsigned char step = steps[ stepsIdx++ ];
stepsIdx = stepsIdx % ( sizeof( steps ) / sizeof( steps[ 0 ] ) );
you can use 10001000b and mod 10000b
and you can get 01000100b 00100010b 00010001b 10001000b repeat.
for example:
char x = 0x88;
Motor_Out(x & 0xf);
Rotate_Right(step, 1);
if I use an 8-bit unsigned int I will eventually rotate the 1 off to the MSB
So use a shift and reinitialize the bit you want when the value goes to zero. C doesn't have a rotate operation anyway, so you'll have to do at least two shifts. (And I suppose C++ doesn't have rotates either.)
x >>= 1;
if (! x) x = 0x08;
Simple, short to write, and obvious in what it does. Yes, it'll compile into a branch (unless the processor has a conditional move operation), but until you have the profiler output to tell you it's important, you just lost more time thinking about it than those processor cycles will ever amount to.
Use an 8-bit data type (like e.g. uint8_t). Initialize it to zero. Set the bit you want to set in the lower four bits of the byte (e.g. value = 0x08).
For each "rotation" take the LSB (least significant bit) and save it. Shift one step right. Overwrite the fourth bit with the bit you saved.
Something like this:
#include <stdio.h>
#include <stdint.h>
uint8_t rotate_one_right(uint8_t value)
{
unsigned saved_bit = value & 1; // Save the LSB
value >>= 1; // Shift right
value |= saved_bit << 3; // Make the saved bit the nibble MSB
return value;
}
int main(void)
{
uint8_t value = 0x08; // Set the high bit in the low nibble
printf("%02hhx\n", value); // Will print 08
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 04
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 02
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 01
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 08 again
return 0;
}
Live demonstration.
I would make an array with the values you need and load the correct value from the array. It will take you 4 bytes, it will be fast, and solve your problems even if you start using a different motor type.
for example:
const char values[4]={1,2,4,8};
int current_value = 0;
....
if(++current_value>=4)current_value=0;
motor = values[current_value];
You only need to output 1, 2, 4, and 8. So you can use a counter to mark which bit to set high.
Motor_Out(8 >> i);
i = (i + 1) & 3;
If you want to drive the motor at half steps, you can use an array to store the numbers you need.
const unsigned char out[] = {0x8, 0xc, 0x4, 0x6, 0x2, 0x3, 0x1, 0x9};
Motor_out(out[i]);
i = (i + 1) & 7;
And you can rotate a 4-bit integer like this.
((i * 0x11) >> 1) & 0xf

Setting bits in a bit stream

I have encountered the following C function while working on a legacy code and I am compeletely baffled, the way the code is organized. I can see that the function is trying to set bits at given position in bit stream but I can't get my head around with individual statements and expressions. Can somebody please explain why the developer used divison by 8 (/8) and modulus 8 (%8) expressions here and there. Is there an easy way to read these kinds of bit manipulation functions in c?
static void setBits(U8 *input, U16 *bPos, U8 len, U8 val)
{
U16 pos;
if (bPos==0)
{
pos=0;
}
else
{
pos = *bPos;
*bPos += len;
}
input[pos/8] = (input[pos/8]&(0xFF-((0xFF>>(pos%8))&(0xFF<<(pos%8+len>=8?0:8-(pos+len)%8)))))
|((((0xFF>>(8-len)) & val)<<(8-len))>>(pos%8));
if ((pos/8 == (pos+len)/8)|(!((pos+len)%8)))
return;
input[(pos+len)/8] = (input[(pos+len)/8]
&(0xFF-(0xFF<<(8-(pos+len)%8))))
|((0xFF>>(8-len)) & val)<<(8-(pos+len)%8);
}
please explain why the developer used divison by 8 (/8) and modulus 8 (%8) expressions here and there
First of all, note that the individual bits of a byte are numbered 0 to 7, where bit 0 is the least significant one. There are 8 bits in a byte, hence the "magic number" 8.
Generally speaking: if you have any raw data, it consists of n bytes and can therefore always be treated as an array of bytes uint8_t data[n]. To access bit x in that byte array, you can for example do like this:
Given x = 17, bit x is then found in byte number 17/8 = 2. Note that integer division "floors" the value, instead of 2.125 you get 2.
The remainder of the integer division gives you the bit position in that byte, 17%8 = 1.
So bit number 17 is located in byte 2, bit 1. data[2] gives the byte.
To mask out a bit from a byte in C, the bitwise AND operator & is used. And in order to use that, a bit mask is needed. Such bit masks are best obtained by shifting the value 1 by the desired amount of bits. Bit masks are perhaps most clearly expressed in hex and the possible bit masks for a byte will be (1<<0) == 0x01 , (1<<1) == 0x02, (1<<3) == 0x04, (1<<4) == 0x08 and so on.
In this case (1<<1) == 0x02.
C code:
uint8_t data[n];
...
size_t byte_index = x / 8;
size_t bit_index = x % 8;
bool is_bit_set;
is_bit_set = ( data[byte_index] & (1<<bit_index) ) != 0;

Bit masking and separation in c

I am new to c programming and i need help in bit manipulation.
I would like to separate the number from a register which have encoded numbers in BCD.
for example;
the register got '29' as value two bits will denote 2 ='10' and four bits will denote 9='1001'.
It is an 8 bit register and rest bits are zero.
So shifting out the 4 bits will give me 2 at disposal.But what about getting the unit digit?
I need some help regarding that
I'm posting the code here:
#include<stdio.h>
main()
{
int x,y;
y=0x29;
x=y;
x=x>>4;
x=x*10;
printf("%d",x);
return(0);
}
You need to mask it out with binary 00001111, which is decimal 15 or hexadecimal 0x0f.
uint8_t reg = 41; // binary 00101001
uint8_t lo_nibble = (reg >> 0) & 0x0f;
uint8_t hi_nibble = (reg >> 4) & 0x0f;
To form a mask to capture the bottom n bits of a number, you can perform these steps (pen and paper at first, eventually in your head):
start with the value 1.
(1) // == 1 or 00000001
shift the value 1 up by n bits.
(1<<4) // == 16 or 00010000
subtract 1.
(1<<4)-1 // == 15 or 00001111
ANDing this mask with another value or variable will yield the bottom n bits of the number.
int in, hi, lo;
lo = in & ((1<<4)-1);
hi = (in>>4) & ((1<<4)-1);

How to define and work with an array of bits in C?

I want to create a very large array on which I write '0's and '1's. I'm trying to simulate a physical process called random sequential adsorption, where units of length 2, dimers, are deposited onto an n-dimensional lattice at a random location, without overlapping each other. The process stops when there is no more room left on the lattice for depositing more dimers (lattice is jammed).
Initially I start with a lattice of zeroes, and the dimers are represented by a pair of '1's. As each dimer is deposited, the site on the left of the dimer is blocked, due to the fact that the dimers cannot overlap. So I simulate this process by depositing a triple of '1's on the lattice. I need to repeat the entire simulation a large number of times and then work out the average coverage %.
I've already done this using an array of chars for 1D and 2D lattices. At the moment I'm trying to make the code as efficient as possible, before working on the 3D problem and more complicated generalisations.
This is basically what the code looks like in 1D, simplified:
int main()
{
/* Define lattice */
array = (char*)malloc(N * sizeof(char));
total_c = 0;
/* Carry out RSA multiple times */
for (i = 0; i < 1000; i++)
rand_seq_ads();
/* Calculate average coverage efficiency at jamming */
printf("coverage efficiency = %lf", total_c/1000);
return 0;
}
void rand_seq_ads()
{
/* Initialise array, initial conditions */
memset(a, 0, N * sizeof(char));
available_sites = N;
count = 0;
/* While the lattice still has enough room... */
while(available_sites != 0)
{
/* Generate random site location */
x = rand();
/* Deposit dimer (if site is available) */
if(array[x] == 0)
{
array[x] = 1;
array[x+1] = 1;
count += 1;
available_sites += -2;
}
/* Mark site left of dimer as unavailable (if its empty) */
if(array[x-1] == 0)
{
array[x-1] = 1;
available_sites += -1;
}
}
/* Calculate coverage %, and add to total */
c = count/N
total_c += c;
}
For the actual project I'm doing, it involves not just dimers but trimers, quadrimers, and all sorts of shapes and sizes (for 2D and 3D).
I was hoping that I would be able to work with individual bits instead of bytes, but I've been reading around and as far as I can tell you can only change 1 byte at a time, so either I need to do some complicated indexing or there is a simpler way to do it?
Thanks for your answers
If I am not too late, this page gives awesome explanation with examples.
An array of int can be used to deal with array of bits. Assuming size of int to be 4 bytes, when we talk about an int, we are dealing with 32 bits. Say we have int A[10], means we are working on 10*4*8 = 320 bits and following figure shows it: (each element of array has 4 big blocks, each of which represent a byte and each of the smaller blocks represent a bit)
So, to set the kth bit in array A:
// NOTE: if using "uint8_t A[]" instead of "int A[]" then divide by 8, not 32
void SetBit( int A[], int k )
{
int i = k/32; //gives the corresponding index in the array A
int pos = k%32; //gives the corresponding bit position in A[i]
unsigned int flag = 1; // flag = 0000.....00001
flag = flag << pos; // flag = 0000...010...000 (shifted k positions)
A[i] = A[i] | flag; // Set the bit at the k-th position in A[i]
}
or in the shortened version
void SetBit( int A[], int k )
{
A[k/32] |= 1 << (k%32); // Set the bit at the k-th position in A[i]
}
similarly to clear kth bit:
void ClearBit( int A[], int k )
{
A[k/32] &= ~(1 << (k%32));
}
and to test if the kth bit:
int TestBit( int A[], int k )
{
return ( (A[k/32] & (1 << (k%32) )) != 0 ) ;
}
As said above, these manipulations can be written as macros too:
// Due order of operation wrap 'k' in parentheses in case it
// is passed as an equation, e.g. i + 1, otherwise the first
// part evaluates to "A[i + (1/32)]" not "A[(i + 1)/32]"
#define SetBit(A,k) ( A[(k)/32] |= (1 << ((k)%32)) )
#define ClearBit(A,k) ( A[(k)/32] &= ~(1 << ((k)%32)) )
#define TestBit(A,k) ( A[(k)/32] & (1 << ((k)%32)) )
typedef unsigned long bfield_t[ size_needed/sizeof(long) ];
// long because that's probably what your cpu is best at
// The size_needed should be evenly divisable by sizeof(long) or
// you could (sizeof(long)-1+size_needed)/sizeof(long) to force it to round up
Now, each long in a bfield_t can hold sizeof(long)*8 bits.
You can calculate the index of a needed big by:
bindex = index / (8 * sizeof(long) );
and your bit number by
b = index % (8 * sizeof(long) );
You can then look up the long you need and then mask out the bit you need from it.
result = my_field[bindex] & (1<<b);
or
result = 1 & (my_field[bindex]>>b); // if you prefer them to be in bit0
The first one may be faster on some cpus or may save you shifting back up of you need
to perform operations between the same bit in multiple bit arrays. It also mirrors
the setting and clearing of a bit in the field more closely than the second implemention.
set:
my_field[bindex] |= 1<<b;
clear:
my_field[bindex] &= ~(1<<b);
You should remember that you can use bitwise operations on the longs that hold the fields
and that's the same as the operations on the individual bits.
You'll probably also want to look into the ffs, fls, ffc, and flc functions if available. ffs should always be avaiable in strings.h. It's there just for this purpose -- a string of bits.
Anyway, it is find first set and essentially:
int ffs(int x) {
int c = 0;
while (!(x&1) ) {
c++;
x>>=1;
}
return c; // except that it handles x = 0 differently
}
This is a common operation for processors to have an instruction for and your compiler will probably generate that instruction rather than calling a function like the one I wrote. x86 has an instruction for this, by the way. Oh, and ffsl and ffsll are the same function except take long and long long, respectively.
You can use & (bitwise and) and << (left shift).
For example, (1 << 3) results in "00001000" in binary. So your code could look like:
char eightBits = 0;
//Set the 5th and 6th bits from the right to 1
eightBits &= (1 << 4);
eightBits &= (1 << 5);
//eightBits now looks like "00110000".
Then just scale it up with an array of chars and figure out the appropriate byte to modify first.
For more efficiency, you could define a list of bitfields in advance and put them in an array:
#define BIT8 0x01
#define BIT7 0x02
#define BIT6 0x04
#define BIT5 0x08
#define BIT4 0x10
#define BIT3 0x20
#define BIT2 0x40
#define BIT1 0x80
char bits[8] = {BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, BIT8};
Then you avoid the overhead of the bit shifting and you can index your bits, turning the previous code into:
eightBits &= (bits[3] & bits[4]);
Alternatively, if you can use C++, you could just use an std::vector<bool> which is internally defined as a vector of bits, complete with direct indexing.
bitarray.h:
#include <inttypes.h> // defines uint32_t
//typedef unsigned int bitarray_t; // if you know that int is 32 bits
typedef uint32_t bitarray_t;
#define RESERVE_BITS(n) (((n)+0x1f)>>5)
#define DW_INDEX(x) ((x)>>5)
#define BIT_INDEX(x) ((x)&0x1f)
#define getbit(array,index) (((array)[DW_INDEX(index)]>>BIT_INDEX(index))&1)
#define putbit(array, index, bit) \
((bit)&1 ? ((array)[DW_INDEX(index)] |= 1<<BIT_INDEX(index)) \
: ((array)[DW_INDEX(index)] &= ~(1<<BIT_INDEX(index))) \
, 0 \
)
Use:
bitarray_t arr[RESERVE_BITS(130)] = {0, 0x12345678,0xabcdef0,0xffff0000,0};
int i = getbit(arr,5);
putbit(arr,6,1);
int x=2; // the least significant bit is 0
putbit(arr,6,x); // sets bit 6 to 0 because 2&1 is 0
putbit(arr,6,!!x); // sets bit 6 to 1 because !!2 is 1
EDIT the docs:
"dword" = "double word" = 32-bit value (unsigned, but that's not really important)
RESERVE_BITS: number_of_bits --> number_of_dwords
RESERVE_BITS(n) is the number of 32-bit integers enough to store n bits
DW_INDEX: bit_index_in_array --> dword_index_in_array
DW_INDEX(i) is the index of dword where the i-th bit is stored.
Both bit and dword indexes start from 0.
BIT_INDEX: bit_index_in_array --> bit_index_in_dword
If i is the number of some bit in the array, BIT_INDEX(i) is the number
of that bit in the dword where the bit is stored.
And the dword is known via DW_INDEX().
getbit: bit_array, bit_index_in_array --> bit_value
putbit: bit_array, bit_index_in_array, bit_value --> 0
getbit(array,i) fetches the dword containing the bit i and shifts the dword right, so that the bit i becomes the least significant bit. Then, a bitwise and with 1 clears all other bits.
putbit(array, i, v) first of all checks the least significant bit of v; if it is 0, we have to clear the bit, and if it is 1, we have to set it.
To set the bit, we do a bitwise or of the dword that contains the bit and the value of 1 shifted left by bit_index_in_dword: that bit is set, and other bits do not change.
To clear the bit, we do a bitwise and of the dword that contains the bit and the bitwise complement of 1 shifted left by bit_index_in_dword: that value has all bits set to one except the only zero bit in the position that we want to clear.
The macro ends with , 0 because otherwise it would return the value of dword where the bit i is stored, and that value is not meaningful. One could also use ((void)0).
It's a trade-off:
(1) use 1 byte for each 2 bit value - simple, fast, but uses 4x memory
(2) pack bits into bytes - more complex, some performance overhead, uses minimum memory
If you have enough memory available then go for (1), otherwise consider (2).

Resources