Bitwise Operators

C provides six operators for bit manipulation; these may only be applied to integral operands, that is, char, short, int, and long, whether signed or unsigned.

OperatorMeaning
&bitwise AND
|bitwise inclusive OR
^bitwise exclusive OR
<<left shift
>>right shift
~one's complement (unary)

The bitwise AND operator (&) is often used to mask off some set of bits, for example

n = n & 0177; 

sets to zero all but the low-order 7 bits of n.

The bitwise OR operator | is used to turn bits on:

x = x | SET_ON; 

sets to one in x the bits that are set to one in SET_ON.

The bitwise exclusive OR operator ^ sets a one in each bit position where its operands have different bits, and zero where they are the same.

One must distinguish the bitwise operators & and | from the logical operators && and ||, which imply left-to-right evaluation of a truth value. For example, if x is 1 and y is 2, then x & y is zero while x && y is one.

The shift operators << and >> perform left and right shifts of their left operand by the number of bit positions given by the right operand, which must be non-negative. Thus x << 2 shifts the value of x by two positions, filling vacated bits with zero; this is equivalent to multiplication by 4. Right shifting an unsigned quantity always fits the vacated bits with zero. Right shifting a signed quantity will fill with bit signs ("arithmetic shift") on some machines and with 0-bits ("logical shift") on others.

The unary operator ~ yields the one's complement of an integer; that is, it converts each 1-bit into a 0-bit and vice versa. For example

x = x & ~077

sets the last six bits of x to zero. Note that x & ~077 is independent of word length, and is thus preferable to, for example, x & 0177700, which assumes that x is a 16-bit quantity. The portable form involves no extra cost, since ~077 is a constant expression that can be evaluated at compile time.

As an illustration of some of the bit operators, consider the function getbits(x,p,n) that returns the (right adjusted) n-bit field of x that begins at position p. We assume that bit position 0 is at the right end and that n and p are sensible positive values. For example, getbits(x,4,3) returns the three bits in positions 4, 3 and 2, right-adjusted.

/* getbits: get n bits from position p */ 
unsigned getbits(unsigned x, int p, int n) { 

    return (x >> (p+1-n)) & ~(~0 << n); 
}

The expression x >> (p+1-n) moves the desired field to the right end of the word. ~0 is all 1-bits; shifting it left n positions with ~0<<n places zeros in the rightmost n bits; complementing that with ~ makes a mask with ones in the rightmost n bits.

Note
If that confused you, it confused me too. So let's go step by step.

Imagine we have a number; say 37. in binary that would be: 100101
(most significant bit first, the lowest bit on the right)

We would like to have bits 2 and 1, so p = 2 and n = 2.
(We start counting from 0, that's why the position is 2 instead of 3, and p determines the upper bound, we count n down from there)

Original number: 100101

x >> (p+1-n)results in x >> (1)
So we shift all digits 1 position to the right, dropping the rightmost digit.

After shift: 010010

~(~0 << n)constructs a mask like this:

~0 turns 000000into 111111(however many zeros we want, deduced at compile-time) then:
<< n shifts them left by n (in our case 2) places, resulting in: 111100
the final ~ inverts it leaving: 000011

then we AND our shifted input and the mask together, which results in: 000010

I included a little example program so you can check that out too.

Exercise 2-6. Write a function setbits(x,p,n,y) that returns x with the n bits that begin at position p set to the rightmost n bits of y, leaving the other bits unchanged.

Exercise 2-7. Write a function invert(x,p,n) that returns x with the n bits that begin at position p inverted (i.e., 1 changed into 0 and vice versa), leaving the others unchanged.

Exercise 2-8. Write a function rightrot(x,n) that returns the value of the integer x rotated to the right by n positions.