evaluating segments of a byte in C - c

I am trying to do disassembly of Intel 8080 without using disassembly tables. I read in bytes of memory and split them into sections of bits: (7, 6), (5, 4, 3), (2, 1, 0). I want to know what are the numerical values of these sections, here is an example:
given this byte:
0b00110000
bits 7 and 6 evaluate to:
0b00 -> 0
bits 5 through 3:
0b110 -> 6
bits 2 through 0:
0b000 -> 0
Now, I am very inexperienced with C and I'm having a hard time coming up with an elegant and simple solution to this problem. So far my idea was the following:
Create 3 copies of the byte (1 per section)
Clear all bits apart from the ones I'm interested in (bitwise AND mask)
Shift the byte an appropriate number of bits
Read the value
would this do the job or is there a better way?

If you think about what needs to be done, you only need be concerned about unary >> shift operator and the & operator. It also helps to come up with a bit mask to isolate only those wanted bits out of whatever intermediate calculation as may be required. (a bit mask is simply a variable holding a number whose 1 bits and 0 bits can by used in a bitwise operation to give you your desired result).
Here, in all your separating of bits, you will only be concerned with the 2 or 3 lower bits after you shift to get your final result. In the case you are looking at (7,6), there are no further bits to mask leaving only the case where you are looking at the lower 3 bits that will require a mask.
From a bit-mask (or what's the magic number) standpoint, you want a mask that will preserve the last 3-bits and discard all remaining higher bits. So for an 8-bit value you want 00000111, or simply the number 7.
To begin, if you want to examine the highest 2 bits in an 8-bit number, then you simply need to shift your number by 6 to the right, e.g. given a byte b holding the total value 0x00110000 in your case, you need.
b >> 6;
There is no need to mask anything here since no higher bits remain.
For bits (5,4,3) in your example, you need to shift to the right by 3, then you will need to & the intermediate result with your mask (7 or b00000111) to get rid of the two bits that remain (6,7), e.g.
uint8_t mask = 7;
...
(b >> 3) & mask;
In the last part, your (2,1,0) bits, no shifting is required, you just need to wipe out all bits over bit 2, e.g. get rid of (7,6,5,4,3) using your mask,
b & mask
Putting that altogether, using exact width types, you can do something similar to the following. The program takes your byte value as its first argument (using 48, e.g. 0x0011000 by default if no argument is given) and outputs the results of the shifts and masks:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main (int argc, char *argv[]) {
uint64_t tmp = argc > 1 ? strtoul (argv[1], NULL, 0) : 48;
uint8_t b = 0,
mask = 7;
if (tmp > UINT8_MAX) {
fprintf (stderr, "input exceeds UINT8_MAX.\n");
return 1;
}
b = (uint8_t)tmp;
printf ("(7,6) 0x%02" PRIx8 "\n", b >> 6);
printf ("(5,4,3) 0x%02" PRIx8 "\n", (b >> 3) & mask);
printf ("(2,1,0) 0x%02" PRIx8 "\n", b & mask);
return 0;
}
Example Use/Output
$ /bin/bytes_233
(7,6) 0x00
(5,4,3) 0x06
(2,1,0) 0x00
Look things over and let me know if you have further questions.

To parse out specific bits of a binary value, we use bit shifts and bit masks. Any segment of bits can be obtained in this manner, using the concept of:
(data >> n) & mask
Where data is the raw data, n is the bit position where this data starts and mask is a bit mask of "all ones", corresponding to the length of the segment.
The mask of "all ones" can be obtained from knowing the segment size: (1u << size) - 1. If a segment's size is for example 3 bits, then 1<<3 gives 1000b. 1000b - 1 = 111b, which is a "all ones" mask of 3 bits.
So if we know the size in bits and the bit position (offset), we can get the data. Example:
#include <stdio.h>
#include <inttypes.h>
#define SEG1_BITS 2
#define SEG1_OFFSET 6
#define SEG2_BITS 3
#define SEG2_OFFSET 3
#define SEG3_BITS 2
#define SEG3_OFFSET 0
#define SEG1(d) ( ((uint32_t)d >> SEG1_OFFSET) & ((1u<<SEG1_BITS)-1) )
#define SEG2(d) ( ((uint32_t)d >> SEG2_OFFSET) & ((1u<<SEG2_BITS)-1) )
#define SEG3(d) ( ((uint32_t)d >> SEG3_OFFSET) & ((1u<<SEG3_BITS)-1) )
int main (void)
{
uint8_t data = 0x30;
printf("%"PRIu32"\n", SEG1(data));
printf("%"PRIu32"\n", SEG2(data));
printf("%"PRIu32"\n", SEG3(data));
return 0;
}
Advanced version with "X macro" to avoid code repetition:
#include <stdio.h>
#include <inttypes.h>
#define SEG_LIST \
/*bits, offset */ \
X(2, 6) \
X(3, 3) \
X(2, 0)
#define SEG(data, bits, n) ( ((uint32_t)data >> n) & ((1u<<bits)-1) )
int main (void)
{
uint8_t data = 0x30;
#define X(bits, n) printf("%"PRIu32"\n", SEG(data, bits, n));
SEG_LIST
#undef X
return 0;
}

Since the problem turned out to be of expansive nature, I had to generalise it and wrote this method:
uint8_t bitsAsValue(uint8_t* byte, int start, int end) {
uint8_t mask = 0b00000000;
uint8_t mask_setter = 0b00000001;
for (int i = start; i <= end; i++) {
mask |= (mask_setter << i);
}
uint8_t value = *byte & mask;
value = value >> start;
return value;
}
It will extract the value from a continuous segment of a byte.

Related

Bitwise operations and masks: return bit values of the original variable that are set in the mask

It's my first time wondering here when the same question wasn't asked previously, therefore I have to ask it myself:)
There is a device (won't go in depth with that, since it's irrelevant for now) that I am working with where I have two inputs, which have length of 16 bits each. The 1st one of the inputs has the later needed values, and the 2nd one has the "locations" from where we want to find the values of 1st one's inputs. Let me show an example:
EDIT: clarification: the mask can be anything that's 16-bits in length and 8 bits set. Not just having the lowest two nibbles set (1), it's only so simple to just illustrate the scenario.
input: 0101 1011 0000 0111
mask: 0011 0011 0011 0011
output: 0001 0011 0000 0011
When mask is set at 1, the machine needs to return the input's value whether its 1 or 0, doesn't matter. The device uses the value regardless of that later on.
I can find solutions for this with simple &, as above, but it ain't enough since my hardware has its limitations and there are resources to be saved. As the example shows, the mask may have only contain at max 8 bits set since some things on the circuit board are mutually exclusive and I want to and can have my output to be only 8 bits in length:
output: xx01 xx11 xx00 xx11
saved to a variable as: 0111 0011
...I just don't know how, yet.
So how should I proceed, should I build on array where I save the locations of mask's set bits and then check value form the input, or is there a more efficient way to to this. Regarding scanning values etc. doesn't matter since I can handle that, at the moment we can treat the input and the mask just as any 16-bit long integers for example. In the short bit of code I used the same mock decimal values as I used in the binary examples earlier.
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t input=23303; //1st input, gives the 1s and 0s to be extracted
uint16_t mask=13107; //2nd input, defines the locations of needed 1s and 0s
uint8_t fi; //Filtered inputs=input after masking, this one to be returned
/*something needs to be done here*/
return fi; //With these inputs, this should be 115
return 0;
}
the mask can be anything that's 16-bits in length and 8 bits set. ...
Iterate through the result of input & mask and in every iteration check the mask bit set or not. If its set than set the corresponding bit in 8 bit result.
You can do:
#include <stdio.h>
#include <inttypes.h>
int main (void) {
uint16_t input = 23303;
uint16_t mask = 13107;
uint8_t fi = 0;
uint16_t res = input & mask;
for (unsigned int x = 0, c = 0; res; res >>= 1, ++x) {
if ((mask >> x) & 0x1) {
if (res & 0x1) {
fi |= 0x1 << c;
}
c++;
}
}
printf ("fi : %" PRIu8 "\n", fi);
return 0;
}
Output:
% ./a.out
fi : 115
Try out above solution with other mask values which are 16 bits in length and 8 bits set.
The most easiest way:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t input=23303; //1st input, gives the 1s and 0s to be extracted
uint16_t mask=13107; //2nd input, defines the locations of needed 1s and 0s
uint8_t fi; //Filtered inputs=input after masking, this one to be returned
/*something needs to be done here*/
uint16_t temp = input & mask;
uint8_t np0, np1, np2, np3;
np0 = temp &0x03;
np1 = (temp >> 4) & 0x03;
np2 = (temp >> 8) & 0x03;
np3 = (temp >> 12) & 0x03;
fi = np0 | (np1 << 2) | (np2 << 4) | (np3 << 6);
return fi; //With these inputs, this should be 115
return 0;
}
A little bit complex but may faster:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t input=23303; //1st input, gives the 1s and 0s to be extracted
uint16_t mask=13107; //2nd input, defines the locations of needed 1s and 0s
uint8_t fi; //Filtered inputs=input after masking, this one to be returned
/*something needs to be done here*/
fi = (temp &0x03) | ((temp >> 2) & 0x0C) | ((temp >> 4) & 0x30) | ((temp >> 6) & 0xC0);
return fi; //With these inputs, this should be 115
return 0;
}

Bit operations for formatting and parsing custom protocol header in C [duplicate]

Say I have a byte like this 1010XXXX where the X values could be anything. I want to set the lower four bits to a specific pattern, say 1100, while leaving the upper four bits unaffected. How would I do this the fastest in C?
In general:
value = (value & ~mask) | (newvalue & mask);
mask is a value with all bits to be changed (and only them) set to 1 - it would be 0xf in your case. newvalue is a value that contains the new state of those bits - all other bits are essentially ignored.
This will work for all types for which bitwise operators are supported.
You can set all those bits to 0 by bitwise-anding with the 4 bits set to 0 and all other set to 1 (This is the complement of the 4 bits set to 1). You can then bitwise-or in the bits as you would normally.
ie
val &= ~0xf; // Clear lower 4 bits. Note: ~0xf == 0xfffffff0
val |= lower4Bits & 0xf; // Worth anding with the 4 bits set to 1 to make sure no
// other bits are set.
Use bitwise operator or | when you want to change the bit of a byte from 0 to 1.
Use bitwise operator and & when you want to change the bit of a byte from 1 to 0
Example
#include <stdio.h>
int byte;
int chb;
int main() {
// Change bit 2 of byte from 0 to 1
byte = 0b10101010;
chb = 0b00000100; //0 to 1 changer byte
printf("%d\n",byte); // display current status of byte
byte = byte | chb; // perform 0 to 1 single bit changing operation
printf("%d\n",byte);
// Change bit 2 of byte back from 1 to 0
chb = 0b11111011; //1 to 0 changer byte
byte = byte & chb; // perform 1 to 0 single bit changing operation
printf("%d\n",byte);
}
Maybe there are better ways, I dont know. This will help you for now.
To further generalise the answers given, here are a couple of macros (for 32-bit values; adjust for different bitfield lengths).
#include <stdio.h>
#include <stdint.h>
#define MASK(L,P) (~(0xffffffff << (L)) << (P))
#define GET_VAL(BF,L,P) (((BF) & MASK(L,P)) >> P)
#define SET_VAL(BF,L,P,V) ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) )
int main(int argc, char ** argv)
{
uint32_t bf = 1024;
printf("Bitfield before : %d , 0x%08x\n", bf, bf);
printf("Mask(5,3): %d , 0x%08x\n", MASK(5,3), MASK(5,3));
SET_VAL(bf,5,3,19);
printf("Bitfield after : %d , 0x%08x\n", bf, bf);
return 0;
}
As an aside, it's ridiculous that the C bitfield is completely useless. It's the perfect syntactic sugar for this requirement but due to leaving it up to each compiler to implement as it sees fit, it's useless for any real-world usage.

Why does compound bit shifting not set leading nibble to 0? [duplicate]

This question already has answers here:
Bit shifting a byte by more than 8 bit
(2 answers)
Closed 3 years ago.
I am trying to clear the first nibble in a 16-bit unsigned integer (set it to 0).
One of the approaches I attempted was to use left bit shifting and then right bit shifting to clear the first four bits.
Here is my program.
#include <stdio.h>
#include <stdint.h>
int main() {
uint16_t x = 0xabcd; // I want to print out "bcd"
uint16_t a = (x << 4) >> 4;
printf("After clearing first four bits: %x\n", a);
return 0;
}
I am expecting the first bit shift (x << 4) to evaluate to 0xbcd0 and then the right bit shift to push a leading 0 in front - 0x0bcd. However, the actual output is 0xabcd.
What confuses me more is if I try to use the same approach to clear the last four bits,
uint16_t a = (x >> 4) << 4;
it works fine and I get expected output: abc0.
Why, in the program above, does the right bit shifting not push a leading 0?
Happens due to integer promotion. On systems where int is larger than 16 bits, your expression is converted to
uint16_t a = (int)((int)x << 4) >> 4;
and the upper bits are not stripped therefore.
if you want to print out "bcd", maybe you can do like this:
#include <stdio.h>
#include <stdint.h>
int main() {
uint16_t x = 0xabcd; // I want to print out "bcd" // step 1
uint16_t c = x << 4 ; // step 2
uint16_t a = c >> 4; // step 3
printf("After clearing first four bits: %x\n", a);
return 0;
}
above output is :
After clearing first four bits: bcd
explanation:
when run step 1:
x is 1010101111001101 (binary) // 1010(a) 1011(b) 1100(c) 1101(d)
go to step 2:
c is 1011110011010000 (binary) // 1011(b) 1100(c) 1101(d) 0000(0)
finally go to step 3:
a is 101111001101 (binary) // 1011(b) 1100(c) 1101(d)

How do you set only certain bits of a byte in C without affecting the rest?

Say I have a byte like this 1010XXXX where the X values could be anything. I want to set the lower four bits to a specific pattern, say 1100, while leaving the upper four bits unaffected. How would I do this the fastest in C?
In general:
value = (value & ~mask) | (newvalue & mask);
mask is a value with all bits to be changed (and only them) set to 1 - it would be 0xf in your case. newvalue is a value that contains the new state of those bits - all other bits are essentially ignored.
This will work for all types for which bitwise operators are supported.
You can set all those bits to 0 by bitwise-anding with the 4 bits set to 0 and all other set to 1 (This is the complement of the 4 bits set to 1). You can then bitwise-or in the bits as you would normally.
ie
val &= ~0xf; // Clear lower 4 bits. Note: ~0xf == 0xfffffff0
val |= lower4Bits & 0xf; // Worth anding with the 4 bits set to 1 to make sure no
// other bits are set.
Use bitwise operator or | when you want to change the bit of a byte from 0 to 1.
Use bitwise operator and & when you want to change the bit of a byte from 1 to 0
Example
#include <stdio.h>
int byte;
int chb;
int main() {
// Change bit 2 of byte from 0 to 1
byte = 0b10101010;
chb = 0b00000100; //0 to 1 changer byte
printf("%d\n",byte); // display current status of byte
byte = byte | chb; // perform 0 to 1 single bit changing operation
printf("%d\n",byte);
// Change bit 2 of byte back from 1 to 0
chb = 0b11111011; //1 to 0 changer byte
byte = byte & chb; // perform 1 to 0 single bit changing operation
printf("%d\n",byte);
}
Maybe there are better ways, I dont know. This will help you for now.
To further generalise the answers given, here are a couple of macros (for 32-bit values; adjust for different bitfield lengths).
#include <stdio.h>
#include <stdint.h>
#define MASK(L,P) (~(0xffffffff << (L)) << (P))
#define GET_VAL(BF,L,P) (((BF) & MASK(L,P)) >> P)
#define SET_VAL(BF,L,P,V) ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) )
int main(int argc, char ** argv)
{
uint32_t bf = 1024;
printf("Bitfield before : %d , 0x%08x\n", bf, bf);
printf("Mask(5,3): %d , 0x%08x\n", MASK(5,3), MASK(5,3));
SET_VAL(bf,5,3,19);
printf("Bitfield after : %d , 0x%08x\n", bf, bf);
return 0;
}
As an aside, it's ridiculous that the C bitfield is completely useless. It's the perfect syntactic sugar for this requirement but due to leaving it up to each compiler to implement as it sees fit, it's useless for any real-world usage.

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