# Having trouble understanding these bitwise macros

Discussion in 'C Programming' started by Krumble Bunk, Oct 12, 2005.

1. ### Krumble BunkGuest

Hello!

First things first (but not necessarily in that order), this is a
really great group, and has helped me understand more and more C
everytime I read the postings, so thanks for a great learning
environment!

I am having difficulty understanding this bitwise macro (i've recently
moved into working on these, using OpenSolaris source code -
magnificent learning resource btw!)

#define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))

where NBBY is defined as 8

I imagine that "a" is a 32bit int, and i is the position of the bit in
the word/int that wants to be set. I don't understand why they divide
by NBBY though? I sort of understand the rest, but if someone could
perhaps spare the time to explain the "setbit" macro, i can extrapolate
the rest for myself.

Many thanks!!

KB

Krumble Bunk, Oct 12, 2005

2. ### SkarmanderGuest

Krumble Bunk wrote:
> Hello!
>
> First things first (but not necessarily in that order), this is a
> really great group, and has helped me understand more and more C
> everytime I read the postings, so thanks for a great learning
> environment!
>
> I am having difficulty understanding this bitwise macro (i've recently
> moved into working on these, using OpenSolaris source code -
> magnificent learning resource btw!)
>
> #define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
> #define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
> #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
>
> where NBBY is defined as 8
>
> I imagine that "a" is a 32bit int, and i is the position of the bit in
> the word/int that wants to be set. I don't understand why they divide
> by NBBY though? I sort of understand the rest, but if someone could
> perhaps spare the time to explain the "setbit" macro, i can extrapolate
> the rest for myself.
>

No, 'a' is not an int. It can't be, because the indexing operator []
couldn't be applied.

These macros are intended to maintain a bit array, where it is assumed
that there are at least NBBY (Number of Bits per BYte, I assume) bits to
every element of a (that is, 'a' will probably be of type 'unsigned
char[]', for some size).

They say a picture's worth a thousand words. Imagine 'a' like this

a[0] a[1] a[2]
01234567 01234567 01234567
01010011 01000101 01011000 ...

Here setbit(a, 14) expands to ((a)[14/8] |= (1 << (14%8)), hence a[1] |=
1 << 6, setting bit 6 of a[1], which is the 15th bit in the collection.

S.

Skarmander, Oct 12, 2005

3. ### pemoGuest

"Krumble Bunk" <> wrote in message
news:...
> Hello!
>
> First things first (but not necessarily in that order), this is a
> really great group, and has helped me understand more and more C
> everytime I read the postings, so thanks for a great learning
> environment!
>
> I am having difficulty understanding this bitwise macro (i've recently
> moved into working on these, using OpenSolaris source code -
> magnificent learning resource btw!)
>
> #define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
> #define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
> #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
>
> where NBBY is defined as 8
>
> I imagine that "a" is a 32bit int, and i is the position of the bit in
> the word/int that wants to be set. I don't understand why they divide
> by NBBY though? I sort of understand the rest, but if someone could
> perhaps spare the time to explain the "setbit" macro, i can extrapolate
> the rest for myself.
>

Seems to set/test a variable's bits through a pointer ...

#include <stdio.h>

#define NBBY 8

#define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))

int main(void)
{
int b = 0;

int * a = &b;

puts("Before setbit");

printf("a's address = %p b's value = %d\n", a, b);

setbit(a, 2);

puts("After setbit");

printf("a's address = %p b's value = %d isset = %d\n", a, b,
!!isset(a, 2));

return 0;
}

Before setbit
a's address = 0012FF78 b's value = 0
After setbit
a's address = 0012FF78 b's value = 4 isset = 1

Code above translates to ...

int main(void)
{
int b = 0;

int * a = &b;

puts("Before setbit");

printf("a's address = %p b's value = %d\n", a, b);

((a)[(2)/8] |= 1<<((2)%8));

puts("After setbit");

printf("a's address = %p b's value = %d isset = %d\n", a, b,
!!((a)[(2)/8] & (1<<((2)%8))));

return 0;
}

pemo, Oct 12, 2005
4. ### Krumble BunkGuest

pemo wrote:
> "Krumble Bunk" <> wrote in message
> news:...
> > Hello!
> >
> > First things first (but not necessarily in that order), this is a
> > really great group, and has helped me understand more and more C
> > everytime I read the postings, so thanks for a great learning
> > environment!
> >
> > I am having difficulty understanding this bitwise macro (i've recently
> > moved into working on these, using OpenSolaris source code -
> > magnificent learning resource btw!)
> >
> > #define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
> > #define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
> > #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
> >
> > where NBBY is defined as 8
> >
> > I imagine that "a" is a 32bit int, and i is the position of the bit in
> > the word/int that wants to be set. I don't understand why they divide
> > by NBBY though? I sort of understand the rest, but if someone could
> > perhaps spare the time to explain the "setbit" macro, i can extrapolate
> > the rest for myself.
> >

>
> Seems to set/test a variable's bits through a pointer ...
>
> #include <stdio.h>
>
> #define NBBY 8
>
> #define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
> #define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
> #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
>
> int main(void)
> {
> int b = 0;
>
> int * a = &b;
>
> puts("Before setbit");
>
> printf("a's address = %p b's value = %d\n", a, b);
>
> setbit(a, 2);
>
> puts("After setbit");
>
> printf("a's address = %p b's value = %d isset = %d\n", a, b,
> !!isset(a, 2));
>
> return 0;
> }
>
> Before setbit
> a's address = 0012FF78 b's value = 0
> After setbit
> a's address = 0012FF78 b's value = 4 isset = 1
>
> Code above translates to ...
>
> int main(void)
> {
> int b = 0;
>
> int * a = &b;
>
> puts("Before setbit");
>
> printf("a's address = %p b's value = %d\n", a, b);
>
> ((a)[(2)/8] |= 1<<((2)%8));
>
> puts("After setbit");
>
> printf("a's address = %p b's value = %d isset = %d\n", a, b,
> !!((a)[(2)/8] & (1<<((2)%8))));
>
> return 0;
> }

Thanks to both of you for your superb replies - exactly what I was
after!

Thanks again -- kb

Krumble Bunk, Oct 12, 2005
5. ### Old WolfGuest

pemo wrote:
> #include <stdio.h>
>
> #define NBBY 8

There is a standard macro CHAR_BIT which tells the number of
bits per byte.

>
> #define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
> #define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
> #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
>
> int main(void)
> {
> int b = 0;
> int * a = &b;

Should be: unsigned char *a = (unsigned char *)&b;

Your example code would have failed if you use any index
greater than 7.

Old Wolf, Oct 12, 2005
6. ### SkarmanderGuest

Old Wolf wrote:
> pemo wrote:
>
>>#include <stdio.h>
>>
>>#define NBBY 8

>
>
> There is a standard macro CHAR_BIT which tells the number of
> bits per byte.
>

Depending on the problem at hand, it may or may not be correct to use
CHAR_BIT rather than 8. For a generic bit array where the goal is to
squeeze as many bits as possible in those bytes, CHAR_BIT is
appropriate, but there may be a need for bit arrays that always use
exactly 8 bits per char, even if it can store more.

>>#define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
>>#define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
>>#define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
>>
>>int main(void)
>>{
>> int b = 0;
>> int * a = &b;

>
>
> Should be: unsigned char *a = (unsigned char *)&b;
>

Not a good idea. Declaring b as an unsigned char[] of an appropriate
size in the first place would be better. The code as originally posted
isn't wrong, though.

> Your example code would have failed if you use any index
> greater than 7.
>

Obviously, and your revised version could fail for any index greater
than 15. That's assuming that writing to parts of an int through an
unsigned char* is defined in the first place, of course, which I don't know.

S.

Skarmander, Oct 12, 2005