Exercise 2-7 of The C Programming Language:
Write a function
invert(x,p,n)
that returnsx
with then
bits that begin at positionp
inverted (i.e., 1 changed to 0 and vice versa), leaving the others unchanged.
I understood the question like this: I have 182 which is 101(101)10
in binary, the part in parentheses has to be inverted without changing the rest. The return value should be 10101010
then, which is 170 in decimal.
Here is my attempt:
#include <stdio.h>
unsigned int getbits(unsigned int bitfield, int pos, int num);
unsigned int invert(unsigned int bitfield, int pos, int num);
int main(void)
{
printf("%d\n", invert(182, 4, 3));
return 0;
}
/* getbits: get num bits from position pos */
unsigned int getbits(unsigned int bitfield, int pos, int num)
{
return (bitfield >> (pos+1-n)) & ~(~0 << num);
}
/* invert: flip pos-num bits in bitfield */
unsigned int invert(unsigned int bitfield, int pos, int num)
{
unsigned int mask;
unsigned int bits = getbits(bitfield,pos,num);
mask = (bits << (num-1)) | ((~bits << (pos+1)) >> num);
return bitfield ^ mask;
}
It seems correct (to me), but invert(182, 4, 3)
outputs 536870730
. getbits()
works fine (it's straight from the book). I wrote down what happens in the expression I've assigned to y
:
(00000101 << 2) | ((~00000101 << 5) >> 3) -- 000000101 is the part being flipped: 101(101)10
00010100 | ((11111010 << 5) >> 3)
00010100 | (01000000 >> 3)
00010100 | 00001000
= 00011100
10110110 (182)
^ 00011100
----------
= 10101010 (170)
Should be correct, but it isn't. I found out this is where it goes wrong: ((~xpn << (p+1)) >> n)
. I don't see how.
Also, I've no idea how general this code is. My first priority is to just get this case working. Help in this issue is welcome too.