In computer science, a mask or bitmask is data that is used for bitwise operations, particularly in a bit field. Using a mask, multiple bits in a byte, nibble, word, etc. can be set either on or off, or inverted from on to off (or vice versa) in a single bitwise operation. An additional use of masking involves predication in vector processing, where the bitmask is used to select which element operations in the vector are to be executed (mask bit is enabled) and which are not (mask bit is clear).
Common bitmask functions
Masking bits to 1 To turn certain bits on, the bitwise OR operation can be used, following the principle that for an individual bit Y, Y OR 1 = 1 and Y OR 0 = Y. Therefore, to make sure a bit is on, OR can be used with a 1. To leave a bit unchanged, OR is used with a 0. Example: Masking on the higher nibble (bits 4, 5, 6, 7) while leaving the lower nibble (bits 0, 1, 2, 3) unchanged.
10010101 10100101 OR 11110000 11110000 = 11110101 11110101
Masking bits to 0 More often in practice, bits are "masked off" (or masked to 0) than "masked on" (or masked to 1). When a bit is ANDed with a 0, the result is always 0, i.e. Y AND 0 = 0. To leave the other bits as they were originally, they can be ANDed with 1 as Y AND 1 = Y Example: Masking off the higher nibble (bits 4, 5, 6, 7) while leaving the lower nibble (bits 0, 1, 2, 3) unchanged.
10010101 10100101 AND 00001111 00001111 = 00000101 00000101
Querying the status of a bit It is possible to use bitmasks to easily check the state of individual bits regardless of the other bits. To do this, turning off all the other bits using the bitwise AND is done as discussed above and the value is compared with 0. If it is equal to 0, then the bit was off, but if the value is any other value, then the bit was on. What makes this convenient is that it is not necessary to figure out what the value actually is, just that it is not 0. Example: Querying the status of the 4th bit
10011101 10010101 AND 00001000 00001000 = 00001000 00000000
Toggling bit values So far the article has covered how to turn bits on and turn bits off, but not both at once. Sometimes it does not really matter what the value is, but it must be made the opposite of what it currently is. This can be achieved using the XOR (exclusive or) operation. XOR returns 1 if and only if an odd number of bits are 1. Therefore, if two corresponding bits are 1, the result will be a 0, but if only one of them is 1, the result will be 1. Therefore inversion of the values of bits is done by XORing them with a 1. If the original bit was 1, it returns 1 XOR 1 = 0. If the original bit was 0 it returns 0 XOR 1 = 1. Also note that XOR masking is bit-safe, meaning that it will not affect unmasked bits because Y XOR 0 = Y, just like an OR. Example: Toggling bit values
10011101 10010101 XOR 00001111 11111111 = 10010010 01101010
To write arbitrary 1s and 0s to a subset of bits, first write 0s to that subset, then set the high bits:
register = (register & ~bitmask) | value;
Merging bits Sometimes selected bits must be copied without altering other bits in a register or storage. This can be expressed for example as
d e s t i n a t i o n = ( d e s t i n a t i o n ∧ ¬ m a s k ) ∨ ( s o u r c e ∧ m a s k ) {\displaystyle destination=(destination\land \lnot mask)\lor (source\land mask)} , or
destination = (destination & ~bitmask) | (source & bitmask);
For this example, bitmask has 0 where the destination bits remain, and 1 where they are replaced by source bits. (If source only contains bits that are going to be inserted, the & bitmask part can be omitted.)
Uses of bitmasks
Arguments to functions In programming languages such as C, bit fields are a useful way to pass a set of named Boolean arguments to a function. For example, in the graphics API OpenGL, there is a command, glClear() which clears the screen or other buffers. It can clear up to four buffers (the color, depth, accumulation, and stencil buffers), so the API authors could have had it take four arguments. But then a call to it would look like
which is not very descriptive. Instead there are four defined field bits, GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_ACCUM_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT and glClear() is declared as
Then a call to the function looks like this:
Internally, a function taking a bitfield like this can use binary and to extract the individual bits. For example, an implementation of glClear() might look like:
The advantage to this approach is that function argument overhead is decreased. Since the minimum datum size is one byte, separating the options into separate arguments would be wasting seven bits per argument and would occupy more stack space. Instead, functions typically accept one or more 32-bit integers, with up to 32 option bits in each. While elegant, in the simplest implementation this solution is not type-safe. A GLbitfield is simply defined to be an unsigned int, so the compiler would allow a meaningless call to glClear(42) or even glClear(GL_POINTS). In C++ an alternative would be to create a class to encapsulate the set of arguments that glClear could accept and could be cleanly encapsulated in a library.
… excerpt ends here. Continue reading the full article.



