Having trouble understanding these bitwise macros

K

Krumble Bunk

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
 
S

Skarmander

Krumble said:
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.
 
P

pemo

Krumble Bunk said:
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;
}
 
K

Krumble Bunk

pemo said:
Krumble Bunk said:
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
 
O

Old Wolf

pemo said:
#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.
 
S

Skarmander

Old said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top