声明:本篇文章只是个人知识盲区、知识弱点、重点部分的归纳总结,望各位大佬不喜勿喷。梳理顺序是按照书籍的实际顺序梳理,转载请注明出处。
作者:sumjess
适用:这本书我已经看过4遍了,但是该书的知识点我并不是都常用,所以总会有忘记的,所以来写这本书的随手笔记,记录重点、易忘点。该博客可以当做字典,也可以当做你的笔记。
目前内容:第十五章总结
第十五章:位操作
1、二进制数、八进制数、十六进制数、位和字节:
(1)二进制数
(2)有符号整数
(3)二进制浮点数
(4)八进制
(5)十六进制
详见我之前的博客https://blog.csdn.net/qq_38351824/article/details/79633493
2、C按位运算符:
(1)按位逻辑运算符:
① 二进制反码或按位取反:~
一元运算符~把1变为0,把0变为1.如下面例子所示:
~(10011010)//表达式
(01100101) //结果值
口诀:一零颠倒
② 按位与:&
二元运算符&通过逐位比较两个运算对象,生成一个新值。只有两个位都为真时,结果才为真。
(10010011)&(00111101)//表达式
(00010001) //结果值
C有一个按位与和赋值结合的运算符:&=。
口诀:全真与真
③ 按位或:|
二元运算符|通过逐位比较两个运算对象,生成一个新值。如果两个对象中相应的一个位都为真,那么结果为真。
(10010011)|(00111101)//表达式
(10111111) //结果值
C有一个按位或和赋值结合的运算符:|=。
口诀:一真或真
④ 按位异或:^
二元运算符^通过逐位比较两个运算对象,生成一个新值。如果两个运算对象中相应的一个位为真,那么结果为真。
(10010011)^(00111101)//表达式
(10101110) //结果值
C有一个按位与和赋值结合的运算符:^=。
口诀:相同为一,不同为零
(2)用法:掩码
按位与运算符常用于掩码。所谓掩码指的是一些设置为开(1)或关(0)的位组合。
flags=flags&mask;
把flag中除1号位以外的所有位都设置为0,因为使用按位与运算符&任何位与0组合都得0.1号位的值不变。这个过程叫作“使用掩码”,因为掩码中的0隐藏了flags中相应的位。
用&=运算符可以简化前面的代码,如下所示:
flags&=mask;
口诀:全真与真
(3)用法:打开位(设置位)
按位与运算符常用于掩码。所谓掩码指的是一些设置为开(1)或关(0)的位组合。
flags=flags|mask;
把flag的1号位设置为1,且其他位不变。因为使用|运算符,任何位与0组合结果都为本身;任何位与1组合,结果都为1
用|=运算符可以简化前面的代码,如下所示:
flags|=mask;
同样,这种方法根据mask中为1的位,把flags中对应的位设置为1,其他位不变。
口诀:一真或真
(4)用法:关闭位(清空位)
和打开特定的位类似,有时也需要在不影响其他位的情况下关闭指定的位。
flags=flags&~mask;
任何位与0组合,结果都为0;
用|=运算符可以简化前面的代码,如下所示:
flags&=~mask;
mask中为1的位在结果中都被设置(清空)为0。flags中与mask为0的位在结果中都未改变。
口诀:一零为真(顺序不能变)
(5)用法:切换位
切换位指的是打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符(^)切换位。
flags=flags^mask;
即是:
(00001111)^(10110110)//表达式
(10111001)//结果
用^运算符可以简化前面的代码,如下所示:
flags^=mask;
flags中与mask为1的位相对应的位都被切换了,mask为0的位相对应的位不变。
口诀:相同为一,不同为零
(6)用法:检查位的值
如何检查某位的值。例如,flags中1号位是否被设置为1?
使用方法,如下所示:
if((flags&mask)==mask)
由于按位运算符的优先级比==低,所以必须在flags&mask周围加上圆括号。
(7)用法:移位运算符
左移运算符(<<)将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数。左侧运算对象移出左末段位的值丢失,用0填充空出的位置。
右移运算符(>>)将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。左侧运算对象移出右末段位的值丢失,用0填充空出的位置。
移位运算符针对2的幂提供快速有效的乘法和除法:
number <
number>>n 如果number为非负,则用number除以2的n次幂
操控位的第二种方法是位字段。位字段是一个signed int或unsigned int类型变量中的一组相邻的位。位字段通过一个结构体来建立,该结构体声明为每个字段提供标签,并确定该字段的宽度。
作用:
有时,某些设置也有多个选择,因此需要多位来表示。这没问题,字段不限制1位大小。可以使用如下代码:
struct{
unsigned int code1 : 2;
unsigned int code2 : 2;
unsigned int code3 : 8;
}prcode;
以上代码创建了两个2位的字段和一个8位的字段。可以这样赋值:
prcode.code1=0;
prcode.code2=3;
prcode.code3=102;
但是要确保所赋的值不超过字段可容纳范围。如果声明总数超过了unsigned int类型的大小,会用到下了一个unsigned int类型的存储位置。
(1)位字段示例
通常,把位字段作为一种更紧凑储存数据的方式。例如,假设要在屏幕上表示一个方框的属性。为简化问题,我们假设如下属性:
■方框是否为透明的;
■方框的填充色选自以下调色板:黑色、红色、绿色、蓝色、紫色、白色;
■边框可见或隐藏;
■边框颜色与填充色使用相同的调色板;
■边框可以使用实线、点线或虚线样式。
可以使用单独的变量或全长结构成员来表示每个属性,但是这样做有些浪费位。例如,只需1位就可以表示边框是否透明。
#include
#include //C99定义了bool、true、false
/*线样式*/
#define SOLID 0
#define DOTTED 1
#define DASHED 2
/*混合色*/
#define BLUE 4
#define GREEN 2
#define RED 1
/*混合色*/
#define BLACK 0
#define YELLOW (RED|GREEN)
#define MAGENTA (RED|BLUE)
#define CYAN (GREEN|BLUE)
#define WHITE (RED|GREEN|BLUE)
const char *colors[8]={"black","red","green","yellow","blue","magenta","cyan","white"};
struct box_props
{
bool opaque : 1; //或者unsigned int(C99以前)
unsigned int fill_color : 3;
unsigned int : 4;
bool show_border : 1;//或者unsigned int(C99以前)
unsigned int border_color : 3;
unsigned int border_style : 2;
unsigned int : 2;
};
void show_settings(const struct box_props*pb);
int main(void)
{
/*创建并初始化box_props结构*/
struct box_props box={true,YELLOW,true,GREEN,DASHED}; //初始化字段结构和初始化普通结构的语法相同
printf("Original box settings:\n");
show_settings(&box);//显示初始化字段后的结果
//给位字段成员赋值
box.opaque=false;
box.fill_color=WHITE;
box.border_color=MAGENTA;
box.border_style=SOLID;
//给位字段成员赋值
printf("\nModified box settings:\n");
show_settings(&box);//显示修改后的结果
return 0;
}
void show_settings(const struct box_props*pb)
{
printf("Box is %s.\n",pb->opaque==true?"opaque":"transparent");
printf("The fill color is %s.\n",colors[pb->fill_color]);
printf("Border %s.\n",pb->show_border==true?"shown":"not shown");
printf("The border color is %s.\n",colors[pb->border_color]);
printf("The border style is ");
switch(pb->border_style)
{
case SOLID: printf("solid.\n");break;
case DOTTED: printf("dotted.\n");break;
case DASHED: printf("dashed.\n");break;
default: printf("unkown type.\n");
}
}
#include
#include //C99定义了bool、true、false
#include
/*位字段符号常量*/
/*边框线样式*/
#define SOLID 0
#define DOTTED 1
#define DASHED 2
/*三原色*/
#define BLUE 4
#define GREEN 2
#define RED 1
/*混合颜色*/
#define BLACK 0
#define YELLOW (RED|GREEN)
#define MAGENTA (RED|BLUE)
#define CYAN (GREEN|BLUE)
#define WHITE (RED|GREEN|BLUE)
/*按位方法中用到的符号*/
#define OPAQUE 0x1
#define FILL_BLUE 0x8
#define FILL_GREEN 0x4
#define FILL_RED 0x2
#define FILL_MASK 0xE
#define BORDER 0x100
#define BORDER_BLUE 0x800
#define BORDER_GREEN 0x400
#define BORDER_RED 200
#define BORDER_MASK 0xE00
#define B_SOLID 0
#define B_DOTTED 0x1000
#define B_DASHED 0x2000
#define STYLE_MASK 3000
const char *colors[8]={"black","red","green","yellow","blue","magenta","cyan","white"};
struct box_props
{
bool opaque : 1; //或者unsigned int(C99以前)
unsigned int fill_color : 3;
unsigned int : 4;
bool show_border : 1;//或者unsigned int(C99以前)
unsigned int border_color : 3;
unsigned int border_style : 2;
unsigned int : 2;
};
union Views/*把数据看作结构或unsigned short类型的变量*/
{
struct box_props st_view;
unsigned short us_view;
} ;
void show_settings(const struct box_props*pb);
void show_settings1(unsigned short);
char*itobs(int n,char*ps);
int main(void)
{
/*创建并views结构,并初始化initialize struct box view*/
union Views box={
true,YELLOW,true,GREEN,DASHED
};
char bin_str[8*sizeof(unsigned int)+1];
printf("Original box settings:\n");
show_settings(&box.st_view);//显示初始化字段后的结果
printf("\n Box settings using unsigned int view:\n");
show_settings1 (box.us_view);//显示初始化字段后的结果
printf("bits are %s\n",itobs(box.us_view,bin_str));
//给位字段成员赋值
box.us_view&=~FILL_MASK;
box.us_view|=(FILL_BLUE|FILL_GREEN);
box.us_view^=OPAQUE;
box.us_view|=BORDER_RED;
box.us_view&=~STYLE_MASK;
box.us_view|=B_DOTTED;
//给位字段成员赋值
printf("\nModified box settings:\n");
show_settings(&box.st_view);//显示初始化字段后的结果
printf("\n Box settings using unsigned int view:\n");
show_settings1(box.us_view);//显示初始化字段后的结果
printf("bits are %s\n",itobs(box.us_view,bin_str));
return 0;
}
void show_settings(const struct box_props*pb)
{
printf("Box is %s.\n",pb->opaque==true?"opaque":"transparent");
printf("The fill color is %s.\n",colors[pb->fill_color]);
printf("Border %s.\n",pb->show_border==true?"shown":"not shown");
printf("The border color is %s.\n",colors[pb->border_color]);
printf("The border style is ");
switch(pb->border_style)
{
case SOLID: printf("solid.\n");break;
case DOTTED: printf("dotted.\n");break;
case DASHED: printf("dashed.\n");break;
default: printf("unknown type.\n");
}
}
void show_settings1(unsigned short us)
{
printf("box is %s.\n",(us&OPAQUE)==OPAQUE?"opaque":"transparent");
printf("The fill color is %s.\n",colors[(us>>9)&07]);
printf("Border %s.\n",(us&STYLE_MASK)==STYLE_MASK?"shown":"not shown");
printf("The border style is ");
switch(us&STYLE_MASK)
{
case SOLID: printf("solid.\n");break;
case DOTTED: printf("dotted.\n");break;
case DASHED: printf("dashed.\n");break;
default: printf("unknown type.\n");
}
printf("The border color is %s.\n",colors[(us>>9)&07]);
}
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;
}