
WebAppendix-2 BITMSK Bitmasks
A netmask is a type of bitmask. Bitmasks are used extensively in programming, usually to extract or set a particular part of a variable or other value. We’ll illustrate this is with an example.
Let’s say we have a simple database-style application, to maintain a catalog of our books. We have three pieces of information we want to record: where the book is stored, whether it’s checked in or out, and how many other copies we have of this title. (Forget about other details like title and author, because they’re not relevant to our discussion of bitmasks.)
We could store each of our three pieces of information in a separate byte. However, that uses more space that we really need. In particular, the checked-out status is a simple YES/NO value, which can be accommodated in a single bit (1 = YES, 0 = NO) so using a whole byte for that would be very wasteful. In fact, we can store all the information we need in a single byte, by assigning a particular meaning to specific bits, as shown in the Table-1. (We even have some spare bits that we can use for system enhancements later on.)
|
Bit no. |
Field description |
Field value |
|
0 – 1 |
book location |
library = 0 technical-dept = 1 sales-dept = 2 admin-dept = 3 |
|
2–4 |
number of other copies |
max. no. of copies = 7 |
|
5 |
checked status |
checked-in = 0 |
|
6-7 |
spare |
|
|
Table-1 Book status fields. |
||
The same information is shown diagrammatically in Figure-1.
Note: the purpose of this example is to show how bitmasks and binary operators can be used in manipulate values. In real-life if you were writing a database application like this in a programming language such as C, the language would let you define data structures so that you could access the fields directly without having to jump through the bitmask hoops that we show below.
Figure-1 Bit-positions of fields.
Now, if we have a book, located in the sales-dept, that’s checked-out-on-loan and we have five other copies, its record will look like this (Figure-2). The value of this status byte us 00110110 binary = 54 decimal.
Figure-2 Values stored in bit-fields.
That’s what the data looks like when its stored in the variable (or record, or byte in the database) but how do you manipulate it? The answer is we use the bitwise binary operators AND, OR and COMP (ones’ complement) in conjunction with bitmasks to get the results we want. The operators are called bitwise because they operate on each bit position in the operands without any carry from one position to the next (such as you get in addition or subtraction).
To extract the "no. of copies" field from the byte containing the book’s details, we define a bitmask that has all 1’s in the bit positions for that field, and all 0’s everywhere else (Figure-3). In this case our bitmask is 00011100 binary, or 28 decimal.
Figure 3 Bitmask for the "no. of copies" field..
Having defined the bitmask, we use it in conjunction with the AND operator to operate on the data, as follows:
In other words, for each bit position, if you have:
Assume our one-byte record has been read from our database files into the variable bookstatus. Here’s how we manipulate the values:
temp = bookstatus AND 28;
This extracts the num-of-copies field by masking. The result, temp, is set to 10100 binary, 20 decimal (Figure-4).
Figure 4 extracting the num-of-copies field.
However, the value we’ve extracted still has two zero bits on the right, so we have to bitshift the whole number to the right by two bit positions to convert the extracted value to the correct numeric value for cnt.
cnt = temp RIGHTSHIFT 2;
This moves the extracted value two bit positions to the right. cnt is now 101 binary, 5 decimal, which is what we expected (Figure-5).
Figure 5 the variable cnt.
To set values in the record, e.g. to decrease the value of the count by one, or to change the checked-out status, we use the OR and AND operators in conjunction with the appropriate masks. Here’s where introduce our third operator to make it easy to create the masks we want.. The ones-complement operator, COMP, reverses the bit pattern of its operand. Let’s say we want to zero the num-of-copies field. The easiest way to do this is to set all the bits in the field to 0, and as we’ve seen, the AND operator is what we use for clearing fields. But we need the correct mask to use with AND. Here’s how we create it, given that we already know that 28 decimal is the mask that selects the bits of interest:
By ANDing this mask with the variable bookstatus, the num-of-copies field is zeroed out.
Now that we have COMP, we can carry out just about any manipulation on our record:
/* this switches on bit no. 5, or leaves it on if was already set */
bookstatus = bookstatus OR 32;
mask = COMP 32; /*
mask is now 11011111 *//*
switch off bit no. 5 */bookstatus = bookstatus AND mask;
/*
extract num-of-copies into the variable cnt as above */temp = bookstatus AND 28;
cnt = temp RIGHTSHIFT 2;
/*
cnt = cnt - 1;
/*
cnt = cnt LEFTSHIFT 2;
/*
clear the num-of-copies field */bookstatus = bookstatus XOR 28;
/*
insert the new value into the cleared field */bookstatus = bookstatus OR cnt;
The last line illustrates the fact that ORing any bit with 0 leaves the original bit unchanged.
Here’s how the AND operator works on a single bit position. If the bit is 1 in both operands, the result is 1, otherwise it’s 0. I.e.
1 AND 1 = 1
1 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0
Here’s how the OR operator works on a single bit position. If the bit is 1 in either operand, the result is 1; it’s only 0 if the bit is 0 in both operands:
1 OR 1 = 1
1 OR 0 = 1
0 OR 1 = 1
0 OR 0 = 0