Think about what happens when you test a specific bit:
1111 1111 (0xff)
& 0000 0100 (0x04, bit 2)
---- ----
= 0000 0100 (0x04)
If you left it like that, your result would be the bitmask itself.
Now consider the double (logical, not bitwise) negation of that, which is not the same as doing nothing:
first: !4 -> 0
then: !0 -> 1
In other words, !!4
gives you 1
rather than 4
and this guarantees that you will get a 0/1
truth value rather than a 0/whatever-the-bitmask-was
value.
The following program shows this in action:
#include <stdio.h>
#define test_bit0(_n,_p) (_n & (1u << _p))
#define test_bit1(_n,_p) !!(_n & (1u << _p))
int main (void) {
printf ("%d %d\n", test_bit0 (0xff, 2), test_bit1 (0xff,2));
return 0;
}
and it outputs:
4 1
as expected.
Aside: there are precious few places where you would write code like that nowadays since modern compilers are more than up to the task of inlining code automatically, and choosing the most efficient way to do an operation like ((_n & (1u << _p)) != 0)
.
And don't get me started on the use of obtuse variable names, the use of number
and position
delivers far more in readability that it loses in compile time :-)