I'm a bit late with this (it took some time) but I think it demonstrates all of the bit operations in an easy to understand way:
Code:
#include <string.h>
#include <stdio.h>
typedef struct {
unsigned char b7:1;
unsigned char b6:1;
unsigned char b5:1;
unsigned char b4:1;
unsigned char b3:1;
unsigned char b2:1;
unsigned char b1:1;
unsigned char b0:1;
} _byte;
union byte {
unsigned char X;
_byte B;
};
char string[9];
char *byte2str (union byte A) {
sprintf(string, "%d-%d-%d-%d-%d-%d-%d-%d",A.B.b0,A.B.b1,A.B.b2,A.B.b3,A.B.b4,A.B.b5,A.B.b6,A.B.b7);
return string;
}
int main(int argc, char *argv[]) {
union byte input, up, down;
unsigned char I=atoi(argv[1]);
input.X=I;
up.X=I<<atoi(argv[2]);
down.X=I>>atoi(argv[2]);
printf("input=%d \t%s\n",input,byte2str(input));
input.X=~input.X;
printf(" not=%d \t%s\n",input,byte2str(input));
input.X=I; input.X&=up.X;
printf("\n up=%d \t%s\n",up,byte2str(up));
printf("and up=%d \t%s\n",input,byte2str(input));
input.X=I; input.X|=down.X;
printf("\n down=%d \t%s\n",down,byte2str(down));
printf("or down=%d \t%s\n",input,byte2str(input));
return 0;
}
You give it two numbers, the first is "input" and the second the size of a shift:
Code:
./a.out 5 2
input=5 0-0-0-0-0-1-0-1
not=250 1-1-1-1-1-0-1-0
up=20 0-0-0-1-0-1-0-0
and up=4 0-0-0-0-0-1-0-0
down=1 0-0-0-0-0-0-0-1
or down=5 0-0-0-0-0-1-0-1
"or down" is the same as input since input already has the least significant bit set.
Code:
./a.out 57 3
input=57 0-0-1-1-1-0-0-1
not=198 1-1-0-0-0-1-1-0
up=200 1-1-0-0-1-0-0-0
and up=8 0-0-0-0-1-0-0-0
down=7 0-0-0-0-0-1-1-1
or down=63 0-0-1-1-1-1-1-1
ps. this is nifty if you change I and X to signed but then you have to "legalize" some stuff in the printf statements.