参考书:《C Primer Plus》第六版
–
1. 二进制数、位和字节,按位运算符
按位运算符
二进制反码或按位取反:~
按位与:&
按位或:|
按位异或:^
掩码
按位与运算通常用于掩码。
用掩码如:
flags = flags & mask;
常见用法是
ch &=0xff;
0xff
的二进制形式为11111111
,八进制形式为0377
。这个掩码保持ch
中的后8为不变,其他位设为0。
按位或运算用于打开位。
flags|=MASK;
关闭位如:
flags&=~MASK;
切换位用按位异或操作:
flags^=MASK;
检查某个位的值:
if((flags&MASK)==MASK){
..;
}
移位运算符
左移:<<
,number << n
:number乘以2的n次幂
右移:>>
,number >> n
:number除以2的n次幂
移位运算符对于2的幂提供了快速有效的乘除法。
程序清单1:
#include"stdio.h"
#include"limits.h"
char * itobs(int ,char *);
void show_bstr(const char *);
int main(void){
char bit_str[CHAR_BIT*sizeof(int)+1];
int number;
puts("Enter integers and see them in binary.");
puts("Non-numeric input terminates program.");
while(scanf("%d",&number)==1){
itobs(number,bit_str);//将一个整数转换位一个二进制字符串
printf("%d is ",number);
show_bstr(bit_str);
putchar('\n');
}
puts("Bye!");
return 0;
}
char *itobs(int n,char *ps){
int i;
const static int size =CHAR_BIT*sizeof(int);
for(i=size-1;i>=0;i--,n>>=1)
ps[i]=(01 & n)+'0';
ps[size]='\0';
return ps;
}
void show_bstr(const char *str){
int i=0;
while(str[i]){
putchar(str[i]);
if(++i%4==0 &&str[i])
putchar(' ');
}
}
root@DESKTOP-624LRQ5:/mnt/d/Program Files/code/c15# ./list1
Enter integers and see them in binary.
Non-numeric input terminates program.
123
123 is 0000 0000 0000 0000 0000 0000 0111 1011
231
231 is 0000 0000 0000 0000 0000 0000 1110 0111
221
221 is 0000 0000 0000 0000 0000 0000 1101 1101
321331
321331 is 0000 0000 0000 0100 1110 0111 0011 0011
123321
123321 is 0000 0000 0000 0001 1110 0001 1011 1001
12312
12312 is 0000 0000 0000 0000 0011 0000 0001 1000
q
Bye!
root@DESKTOP-624LRQ5:/mnt/d/Program Files/code/c15#
程序清单2
#include"stdio.h"
#include"limits.h"
char * itobs(int ,char *);
void show_bstr(const char *);
int invert_end(int num,int bits);
int main(void){
char bit_str[CHAR_BIT*sizeof(int)+1];
int number;
puts("Enter integers and see them in binary.");
puts("Non-numeric input terminates program.");
while(scanf("%d",&number)==1){
itobs(number,bit_str);//将一个整数转换位一个二进制字符串
printf("%d is ",number);
show_bstr(bit_str);
putchar('\n');
number=invert_end(number,4);
printf("Iverting the last 4 bits gives\n");
show_bstr(itobs(number,bit_str));
putchar('\n');
}
puts("Bye!");
return 0;
}
char *itobs(int n,char *ps){
int i;
const static int size =CHAR_BIT*sizeof(int);
for(i=size-1;i>=0;i--,n>>=1)
ps[i]=(01 & n)+'0';
ps[size]='\0';
return ps;
}
void show_bstr(const char *str){
int i=0;
while(str[i]){
putchar(str[i]);
if(++i%4==0 &&str[i])
putchar(' ');
}
}
int invert_end(int number,int bits){
int mask=0;
int bitval=1;
while(bits-- >0){
mask |=bitval;
bitval <<= 1;
}
return number^mask;
}
Enter integers and see them in binary.
Non-numeric input terminates program.
7
7 is 0000 0000 0000 0000 0000 0000 0000 0111
Iverting the last 4 bits gives
0000 0000 0000 0000 0000 0000 0000 1000
23
23 is 0000 0000 0000 0000 0000 0000 0001 0111
Iverting the last 4 bits gives
0000 0000 0000 0000 0000 0000 0001 1000
123
123 is 0000 0000 0000 0000 0000 0000 0111 1011
Iverting the last 4 bits gives
0000 0000 0000 0000 0000 0000 0111 0100
Bye!
2. 位字段
位字段是一个signed int或unsigned int 类型的变量中的一组相邻的位。为字段通过一个结构声明来建立,声明时为每个字段提供标签,并确定该字段的宽度。如下:
struct
{
unsigned int a:1;
unsigned int b:2;
unsigned int c:1;
unsigned int d:3;
} s;
3. 编程练习
- 编写一个函数把二进制字符转换为一个数字
#include<stdio.h>
#include<stdlib.h>
int toDigit(char *ch);
int main(void){
char ch;
char str[20];
puts("Enter a binary number:");
while(scanf("%s",str)==1){
printf("-->%d\n",toDigit(str));
puts("Next:");
}
puts("Bye.");
return 0;
}
int toDigit(char *ch){
int i=0,value=0;
while(ch[i]!='\0'){
if(ch[i]=='1'){
value<<=1;
value++;
}else if(ch[i]=='0')
value<<=1;
else
return 0;
i++;
}
return value;
}
Enter a binary number:
000111
-->7
Next:
11001
-->25
Next:
111111
-->63
Next:
1111111
-->127
Next:
1000000
-->64
Next:
s
-->0
Next:
Bye.
- 编写一个程序,通过命令行参数读取两个二进制字符串,然后对这两个二进制字符串做一些位操作并输出。
#include"stdio.h"
#include"stdlib.h"
#include"limits.h"
char* toString(int i);
int todigit(char*);
int main(int argc,char **argv){
if(argc<3){
puts("arguments not enough");
exit(EXIT_FAILURE);
}
int v1=todigit(argv[1]);
int v2=todigit(argv[2]);
printf("v1=%d ,v2=%d, ~v1=%d,~v2=%d\n",v1,v2,~v1,~v2);
printf("~%s-->%s,~%s-->%s\n",argv[1],toString(~v1),argv[2],toString(~v2));
printf("%s & %s = %s\n",argv[1],argv[2],toString(v1&v2));
printf("%s | %s = %s\n",argv[1],argv[2],toString(v1|v2));
printf("%s ^ %s = %s\n",argv[1],argv[2],toString(v1^v2));
return 0;
}
int todigit(char *ch){
int i=0,sum=0;
while(ch[i]!='\0'){
if(ch[i]=='1'){
sum<<=1;
sum++;
}else if(ch[i]=='0')
sum<<=1;
else
return 0;
i++;
}
return sum;
}
char * toString(int val){
int i;
const static int size=CHAR_BIT*sizeof(int);
char static str[CHAR_BIT*sizeof(int)+1];
for(i=size-1;i>=0;i--,val>>=1)
str[i]=(01&val)+'0';
str[size]='\0';
return str;
}
```bash
root@DESKTOP-624LRQ5:/mnt/d/Program Files/code/c15# ./prac2 11001 100001111
v1=25 ,v2=271, ~v1=-26,~v2=-272
~11001-->11111111111111111111111111100110,~100001111-->11111111111111111111111111100110
11001 & 100001111 = 00000000000000000000000000001001
11001 | 100001111 = 00000000000000000000000100011111
11001 ^ 100001111 = 00000000000000000000000100010110
root@DESKTOP-624LRQ5:/mnt/d/Program Files/code/c15#
- 编写一个函数,接受一个int,返回参数中打开位的数量。
#include<stdio.h>
int num(int val);
int main(void){
int v;
puts("Enter an integer:");
while(scanf("%d",&v)==1){
printf("number:%d\n",num(v));
printf("Next:\n");
}
puts("Bye.");
return 0;
}
int num(int val){
int i,sum=0;
while(val!=0){
sum+=(val%2?1:0);
val>>=1;
}
return sum;
}
Enter an integer:
7
number:3
Next:
5
number:2
Next:
15
number:4
Next:
99
number:4
Next:
6
number:2
Next:
- 编写一个函数接受两个int参数,一个为值,一个为位的位置,返回0或1
#include"stdio.h"
#include"stdlib.h"
int bit(int val,int ind);
int main(void){
int val,ind;
puts("Enter two integer:");
while(scanf("%d %d",&val,&ind)==2){
printf("The value is :%d\n",bit(val,ind));
puts("Next");
}
puts("Bye.");
return 0;
}
int bit(int val,int ind){
return (val>>ind)%2;
}
root@DESKTOP-624LRQ5:/mnt/d/Program Files/code/c15# ./prac4
Enter two integer:
8 2
The value is :0
Next
127 4
The value is :1
Next
44 3
The value is :1
Next
55 4
The value is :1
Next
Bye.
- 编写一个函数把一个unsigned int中的位向左旋转指定数量的位。
#include"stdio.h"
#include"stdlib.h"
#include"limits.h"
int rotate(int x,int ind);
int main(void){
puts("Enter two integer:");
int x,i;
while(scanf("%d %d",&x,&i)==2){
printf("%d rotate -- %d -->%d \n",x,i,rotate(x,i));
puts("Next:");
}
puts("Bye.");
return 0;
}
int rotate(int x,int ind){
int m=0;
int i,xc=x,bits=0;;
while(xc!=0){
xc>>=1;
bits++;
}
for(i=0;i<ind;i++){
m=(x>>(bits-1))%2;
x<<=1;
x=x-(m<<bits)+m;
}
return x;
}
Enter two integer:
7
2
7 rotate -- 2 -->7
Next:
8 2
8 rotate -- 2 -->2
Next:
255 4
255 rotate -- 4 -->255
Next:
256 4
256 rotate -- 4 -->8
Next:
Bye.
- 设计一个字段程序存储文本一些属性信息。
#include"stdio.h"
#include"stdlib.h"
struct textStyle{
unsigned int fontId:8;
unsigned int fontSize:7;
unsigned int align:2;
unsigned int bold:1;
unsigned int italic:1;
unsigned int underline:1;
};
void show(struct textStyle);
int main(void){
struct textStyle ts={1,12,0,0,0,0};
show(ts);
char ch='f';
int val;
while((ch=getchar())!='q'){
switch (ch)
{
case 'f':
printf("Enter font id (0-255): ");
scanf("%d",&val);
ts.fontId=val;
show(ts);
break;
case 's':
printf("Enter font size (0-127): ");
scanf("%d",&val);
ts.fontSize=val;
show(ts);
break;
case 'a':
printf("Select alignment:\n");
printf("l)left c)center r)right\n");
char chh='l';
getchar();
if((chh=getchar())=='l')
ts.align=0;
else if(chh=='c')
ts.align=1;
else if(chh=='r')
ts.align=2;
show(ts);
break;
case 'b':
ts.bold=ts.bold==0?1:0;
show(ts);
break;
case 'i':
ts.italic=ts.italic==0?1:0;
show(ts);
break;
case 'u':
ts.underline=ts.underline==0?1:0;
show(ts);
break;
default:
break;
}
}
puts("Bye.");
return 0;
}
void show(struct textStyle ts){
printf("ID SIZE ALIGNMENT B I U\n");
printf(" %d %d %s %s %s %s\n",ts.fontId,ts.fontSize,ts.align==0?"left":ts.align==1?"center":"right",
ts.bold==0?"off":"on",ts.italic==0?"off":"on",ts.underline==0?"off":"on");
puts("f)change font s)change size a)change alignment");
puts("b)toggle bold i)touggle italic u)toggle underline");
puts("q)quit");
}
root@DESKTOP-624LRQ5:/mnt/d/Program Files/code/c15# ./prac6
ID SIZE ALIGNMENT B I U
1 12 left off off off
f)change font s)change size a)change alignment
b)toggle bold i)touggle italic u)toggle underline
q)quit
a
Select alignment:
l)left c)center r)right
l
ID SIZE ALIGNMENT B I U
1 12 left off off off
f)change font s)change size a)change alignment
b)toggle bold i)touggle italic u)toggle underline
q)quit
a
Select alignment:
l)left c)center r)right
c
ID SIZE ALIGNMENT B I U
1 12 center off off off
f)change font s)change size a)change alignment
b)toggle bold i)touggle italic u)toggle underline
q)quit
b
ID SIZE ALIGNMENT B I U
1 12 center on off off
f)change font s)change size a)change alignment
b)toggle bold i)touggle italic u)toggle underline
q)quit
i
ID SIZE ALIGNMENT B I U
1 12 center on on off
f)change font s)change size a)change alignment
b)toggle bold i)touggle italic u)toggle underline
q)quit
u
ID SIZE ALIGNMENT B I U
1 12 center on on on
f)change font s)change size a)change alignment
b)toggle bold i)touggle italic u)toggle underline
q)quit
q
Bye.