crafter
crafter

Reputation: 6296

Question about test_bit macro in C

I've used the following macro in C:

#define   test_bit(_n,_p)     !! ( _n & ( 1u << _p))

I've studied the macro but I need to determine the use of the double negative in the macro, and how it behaves differently from the macro definition :

#define   test_bit(_n,_p)     ( _n & ( 1u << _p))

Upvotes: 4

Views: 4149

Answers (3)

paxdiablo
paxdiablo

Reputation: 881253

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 :-)

Upvotes: 13

jpalecek
jpalecek

Reputation: 47762

Basically, the purpose of double negation is to constrain values returned by the macro to 0 and 1. In

if(test_bit(x, 5)) x=0; // (1)
array[test_bit(x, 5)] = 0; // (2)

In (1), both of the definitions work equivalently. In (2), the first definition always sets array[0] or array[1], whereas the second doesn't.

Upvotes: 2

sharptooth
sharptooth

Reputation: 170489

It will behave differently if you chain the macro with some arithmetic or bitwise operators. For example if you have

#define   test_bit(_n,_p)     ( _n & ( 1u << _p))

and

test_bit( whatever, 1 ) | test_bit( whatever, 4 )

the result will differ to the one which you have with

#define   test_bit(_n,_p)     !! ( _n & ( 1u << _p))

And double negation is just another way of writing != 0.

Upvotes: 2

Related Questions