In this posting I’m going to explain a bit-twiddling technique called masking. It is used to extract (and alter) specific bits in a word of bits, for example a byte. You might be familiar with IP subnet masks in network engineering, which one practical application of masking.
You may need some deeper understanding of how masking actually works, if you want to set up registers in a microcontroller system or if you want to fiddle with the guts (e.g. UART) of your PC.
Masking allows you to set or to reset specific bits in a byte (or word) without “touching” any other bits in the word. Here is an example assignment.
Assume that a is a variable of an 8-bit datatype (e.g. unsigned char in C). Further assume that you want to set the MSB (Most Significant Bit, or Bit No. 7) without changing the state of any other bits.
unsigned char a; a = ... // already coded: some codes that may set or reset the // bits 0 to 6 of a // TBD: Insert code that only sets the MSB (Bit 7) of a without // changing bit 0 ... bit 6
If you solved this problem by using something like this,
a = 0x80;
you would also set or reset other bits in the variable (which we did not want to do).
The solution is masking. You just need to remember two basic things about logic operators.
OR allows you to force a bit to HIGH (1)
AND allows you to force a bit to LOW (0)
The reason is that if you use OR on two bits the result will always be 1 whenever at least one of the bits is 1. If you use AND on two bits the result will always be 0 whenever at least one of the bits is 0.
a = a | 0x80;
The value 0x80 is called mask. It only has those bits set which shall be set in the result (only the MSB in this case, because 0x80 is 1000 0000 when written in binary).
If you want to force bits to 0 be sure to use the AND operator. Note that the mask needs to be built in a different way. All bits which you want to be 0 in the result must be 0 in the mask. Bits you want to leave unaffected need to be 1 in the mask.
For example, let’s now reset Bit No. 2 (2² … which is the third bit from the right) of variable a.
We need to use AND with the mask 1111 1011 binary (= 0xFB hexadecimal), because we only want to reset bit 2.
The code in C is
a = a & 0xFB;
Now it is time to have some exercise. What is the value of variable a after the execution of the following code?
unsigned int value = 0xCC; value = value | 0x05; value = value & 0xA0;
— Andre M. Maier
Christian Enchelmaier, who was one of my former students, sent me the following C code. It is a very nice and easy-to-read implementation of how masking could be done in a convenient way. The only disadvantage is that due to subsequent masking single bits this code will require a greater number of machine cycles than the code in the examples above.
#define BIT_1 (1 << 0) #define BIT_2 (1 << 1) #define BIT_3 (1 << 2) char val = 0; // Set bits val |= BIT_1; val |= BIT_2; val |= BIT_3; // Clear bit val &= ~BIT_2;
Thanks to Christian!