Bitwise idioms

J

Johnathan Doe

Hi,

I am having problems understanding bitwise idioms that I see frequently
in source code. I understand that they work at the individual bit level
and that 0 | 1 = 1, 1 & 1 = 1 and so on (understand what all the
operators mean), but when I try bit banging code it inevitably fails to
get the result I wanted.

I am trying to put together a packet to query a DNS server. I
understand there are potentially little vs. big-endian problems, but
TCP/IP Illustrated shows where the least and most significant bits are
in the packets, so it's only the serial number I have to consider with
little vs. big endian, I think... presumably it would be in network big
endian order...

But now to the bitwise stuff. Say I had a 16-bit short int, as in the
DNS header for flags, with the most significant bit meaning query or
answer (0 = query, 1 = answer.) Would this be correct to get a mask:

#define QR_MASK (1 << 16)

I think this means "move a 1 16 bit positions to the left..." Presumably
the 1 is moving to the most significant (big end) of the 16-bit word.
The rest of the word is filled with 0 bits. Also does it fall off the
end? (Am I looking for 1 << 15 or 1 << 16? I tried both bit there was
no output...)

In a word in the program, how would a hypothetical DNS server turn that
bit on without disturbing the other bits? Like this?

struct dns_struct {
unsigned short int flags;
...
};

struct dns_struct d;
d.flags |= QR_MASK;

Is that the idiom normally used? The mask is used to set and unset
bits, or is the mask used in another context?

How can I write a routine that will print a word in binary? I have
given it a go with the short program below. I am aiming for the output:

QR_BIT is set
OPCODE_QRY is set
1000100000000000


This program is not working as expected (ignore OPCODE for the moment,
that is supposed to set 4 bits from the 12th bit):

#include<stdio.h>
#include<stdlib.h>

#define QR_BIT (1 << 16)
#define OPCODE (15 << 12)
#define OPCODE_QRY (1 << 12)

void print_bin(unsigned short int n, int newline);

int main()
{
unsigned short flags = 0;

flags |= QR_BIT;
flags |= OPCODE_QRY;

if (flags & QR_BIT)
puts("QR_BIT is set");
else
puts("QR_BIT is not set");

if (flags & OPCODE_QRY)
puts("OPCODE_QRY is set");
else
puts("OPCODE_QRY is not set");

printf("flags = ");
print_bin(flags, 1);
}

void print_bin(unsigned short int n, int newline)
{
int i;

for (i = 16; i > 0; i--)
if ( (1 << i) & n )
putchar('1');
else
putchar('0');

if (newline)
putchar('\n');
}


So:
* Context in which masks are used, and how to construct them?
* How to set and turn off bits
* Dealing with bit fields of more than one bit

Thanks for your help.

Johnathan
 
?

=?ISO-8859-1?Q?Bj=F8rn_Augestad?=

Johnathan said:
Hi,

I am having problems understanding bitwise idioms that I see frequently
in source code. I understand that they work at the individual bit level
and that 0 | 1 = 1, 1 & 1 = 1 and so on (understand what all the
operators mean), but when I try bit banging code it inevitably fails to
get the result I wanted.

I am trying to put together a packet to query a DNS server. I
understand there are potentially little vs. big-endian problems, but
TCP/IP Illustrated shows where the least and most significant bits are
in the packets, so it's only the serial number I have to consider with
little vs. big endian, I think... presumably it would be in network big
endian order...

But now to the bitwise stuff. Say I had a 16-bit short int, as in the
DNS header for flags, with the most significant bit meaning query or
answer (0 = query, 1 = answer.) Would this be correct to get a mask:

#define QR_MASK (1 << 16)

I think this means "move a 1 16 bit positions to the left..." Presumably
the 1 is moving to the most significant (big end) of the 16-bit word.
The rest of the word is filled with 0 bits. Also does it fall off the
end? (Am I looking for 1 << 15 or 1 << 16? I tried both bit there was
no output...)

In a word in the program, how would a hypothetical DNS server turn that
bit on without disturbing the other bits? Like this?

struct dns_struct {
unsigned short int flags;
...
};

struct dns_struct d;
d.flags |= QR_MASK;

Is that the idiom normally used? The mask is used to set and unset
bits, or is the mask used in another context?

How can I write a routine that will print a word in binary? I have
given it a go with the short program below. I am aiming for the output:

QR_BIT is set
OPCODE_QRY is set
1000100000000000


This program is not working as expected (ignore OPCODE for the moment,
that is supposed to set 4 bits from the 12th bit):

#include<stdio.h>
#include<stdlib.h>

#define QR_BIT (1 << 16)

1 is a 32 bit int, so it is OK to shift it 16 bits. You probably meant
to shift 15 bits, right?
#define OPCODE (15 << 12)
#define OPCODE_QRY (1 << 12)

void print_bin(unsigned short int n, int newline);

int main()
{
unsigned short flags = 0;

flags |= QR_BIT;

Here you OR the 32-bit int with a 16-bit short. Since (1<<16) doesn't
fit in the short, the value of flags still is 0.

flags |= OPCODE_QRY;

if (flags & QR_BIT)
puts("QR_BIT is set");
else
puts("QR_BIT is not set");

if (flags & OPCODE_QRY)
puts("OPCODE_QRY is set");
else
puts("OPCODE_QRY is not set");

printf("flags = ");
print_bin(flags, 1);
}

void print_bin(unsigned short int n, int newline)
{
int i;

for (i = 16; i > 0; i--)

Bits are indexed from 0, so a short int is (in most cases) indexed from
0..15. When you leftshift 16, you invoke undefined behaviour (§6.5.7#3).

So change your for loop to:
for(i = 15; i >= 0; i--)
and things will work better.


HTH
boa
 
M

Mark McIntyre

1 is a 32 bit int, so it is OK to shift it 16 bits.

AFAIR Integer constants are the smallest size they can fit into, so 1 is a
short. This might be 16 bits.
 
J

Johnathan Doe

Hi guys,

Thanks, problem solved. Of course, it's (1 << 15) and not (1 << 16),
etc. I started from 1 instead of 0.

Cheers
Johnathan
 
?

=?ISO-8859-1?Q?Bj=F8rn_Augestad?=

pete said:
How do you figure that 1 is a 32 bit int?

My mistake, sorry. The type of 1 << 16 is (in most cases) a 32 bit int,
at least it was when I compiled the OP's program using gcc 3.3.1 on x86.

Bjørn
 
A

Arthur J. O'Dwyer

AFAIR Integer constants are the smallest size they can fit into, so 1 is a
short. This might be 16 bits.

Integer constants are the smallest size they can fit into, or 'int',
whichever is bigger. Thus 1 is an 'int'. This /still/ might be
16 bits, though, so your (and pete's) conclusion is correct.

Look at 'sizeof 1' for enlightenment. ;)

-Arthur
 
M

Mark F. Haigh

Johnathan said:

* How to set and turn off bits
* Dealing with bit fields of more than one bit

All bits are ordered starting with 0. Some superfluous parenthesis have
been added, in some of the examples below.

unsigned int x = 0; /* Always use unsigned types! */
x |= (1U << 3); /* Set bit 3 */
x |= (1U << 4 | 1U << 5); /* Set bits 4 and 5 */
x &= ~(1U << 4); /* Clear bit 4 */
x &= ~(1U << 3 | 1U << 5); /* Clear bits 3 and 5 */
x ^= (1U << 6); /* Toggle bit 6 */
x ^= (1U << 7 | 1U << 8); /* Toggle bits 7 and 8 */
if(x & (1U << 6)) {...} /* Is bit 6 set? */
if(!(x & (1U << 7 | 1U << 8))) {...} /* Are bits 7 and 8 clear? */


/* Some typical usages */
#define FOO (1U << 2)
#define BAR (1U << 4)
#define BAZ (1U << 5)
#define ANY (FOO | BAR | BAZ)
#define FOOBAR (FOO | BAR)

if(x & ANY) {...} /* Is any of FOO, BAR, BAZ set? */
x |= FOOBAR; /* Set FOO and BAR bits */
x ^= BAZ; /* Toggle BAZ bit */


You get the idea. Not difficult. You should define a descriptive macro
for each meaningful bit, and should avoid sprinkling the code with
numeric literals.


Mark F. Haigh
(e-mail address removed)
 
R

Rajeev

Mark F. Haigh said:
All bits are ordered starting with 0. Some superfluous parenthesis have
been added, in some of the examples below.

unsigned int x = 0; /* Always use unsigned types! */
x |= (1U << 3); /* Set bit 3 */
x |= (1U << 4 | 1U << 5); /* Set bits 4 and 5 */
x &= ~(1U << 4); /* Clear bit 4 */
x &= ~(1U << 3 | 1U << 5); /* Clear bits 3 and 5 */
x ^= (1U << 6); /* Toggle bit 6 */
x ^= (1U << 7 | 1U << 8); /* Toggle bits 7 and 8 */
if(x & (1U << 6)) {...} /* Is bit 6 set? */
if(!(x & (1U << 7 | 1U << 8))) {...} /* Are bits 7 and 8 clear? */


/* Some typical usages */
#define FOO (1U << 2)
#define BAR (1U << 4)
#define BAZ (1U << 5)
#define ANY (FOO | BAR | BAZ)
#define FOOBAR (FOO | BAR)

if(x & ANY) {...} /* Is any of FOO, BAR, BAZ set? */
x |= FOOBAR; /* Set FOO and BAR bits */
x ^= BAZ; /* Toggle BAZ bit */

This is a very nicely presented collection.

If I may add, there are alternatives to using #defines.
One can use const int or enum, ie (building on Mike's summary)

const int FOOpos=2; /* pos shorthand for position */
/* const int FOO = (1U<<FOOpos); this is not allowed in VisualC */
enum MyRegBitPos {BARpos=4,BAZpos=5};
const int BAZ = (1U<<BAZpos); /* this is allowed */

and here are some other macros to consider

#define SetRegBitPos(iReg,BitPos) {iReg|=(1U<<(BitPos));}
#define ClrRegBitPos(iReg,BitPos) {iReg&= ~(1U<<(BitPos));}

Regards,
-rajeev-
 
C

Charlie Gordon

and here are some other macros to consider
#define SetRegBitPos(iReg,BitPos) {iReg|=(1U<<(BitPos));}
#define ClrRegBitPos(iReg,BitPos) {iReg&= ~(1U<<(BitPos));}

Not advisable : macros should not expand to a block statement, it makes them
unfit for use as follows:

if (some_condition())
SetRegBitPos(iReg,BitPos);
else
ClrRegBitPos(iReg,BitPos);

There are ways to fix this problem :

#define SetRegBitPos(iReg,BitPos) ((iReg) |= (1U<<(BitPos)))
#define ClrRegBitPos(iReg,BitPos) ((iReg) &= ~(1U<<(BitPos)))

Or

#define SetRegBitPos(iReg,BitPos) do { (iReg) |= (1U<<(BitPos));}while (0)
#define ClrRegBitPos(iReg,BitPos) do { (iReg) &= ~(1U<<(BitPos));}while (0)

Also note that iReg must be parenthesized to avoid precedence issues.

Chqrlie.
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top