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.

I don't understand why this expression has that effect. Wouldn't n = 0; have the same effect? Or maybe n = ~0177;?

The trick here is that it leaves the low-order 7 bits of n unchanged. If you were storing flags in n, for example, you might want to clear only a few of them and leave the others untouched.

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.

What does x look like before the operation is performed. 16 0-bits or is it in some state I don't know about? And why is word length coming into this discussion out of nowhere?

x could be anything before this operation. The idea is that the bits of x have some values (perhaps you know what they are, perhaps you don't) and that you want to set the lowest six bits to be zero without changing the other bits.

The word length discussion is because if you calculated the value ~077 for 16-bit integers, you'd get 0177700 -- but that only works if you're using 16-bit integers. Using the expression ~077 will work for 8-bit, 16-bit, 32-bit, or whatever-bit integers, so it's better to use it.

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.

Code:

/* 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.

My brain collapsed.

I'll use eight-bit variables in my examples here.

Given a number like 0011 1011, and asked for a "window" starting from 4 of width 3 (i.e., the call getbits(0x3b, 4, 3)) is supposed to do this:

Code:

bit 7654 3210
0011 1011
so starting at bit 4 is starting here
0011 1011
^
a width of 3 will be the following bits
0011 1011
^ ^^
so if we want to get these bits, here's one way (the way the function uses).
Shift the number left by (4+1-3), i.e. 2, to obtain
0011 1011
^ ^^
>> 2 becomes
0000 1110
^^^
Now if we want the leftmost three bits, we want to AND with a mask of 000 0111.
We generate this mask with the following operations:
start with ~0 (all 1's):
1111 1111
left shift by 3: (shifting in zeros)
1111 1000
now invert the bits again:
0000 0111
This is the mask we wanted. AND'ing our (right-shifted) number with this mask gives
0000 1110
& 0000 0111
-----------
0000 0110
which is what we wanted.

Anyway, not sure if that's a very good explanation, but read it carefully and see if you get it. Hopefully I understood what getbits was supposed to do.