C Primer Plus (第六版) 中文版 随手笔记(十二)

声明:本篇文章只是个人知识盲区、知识弱点、重点部分的归纳总结,望各位大佬不喜勿喷。梳理顺序是按照书籍的实际顺序梳理,转载请注明出处。

作者: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 <<n         number乘以2的n次幂                                              

                   number>>n          如果number为非负,则用number除以2的n次幂      

3、位字段:

操控位的第二种方法是位字段。位字段是一个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 <stdio.h>
#include <stdbool.h>//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 <stdio.h>
#include <stdbool.h>//C99定义了bool、true、false
#include <limits.h>
/*位字段符号常量*/ 
/*边框线样式*/
#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;
}


猜你喜欢

转载自blog.csdn.net/qq_38351824/article/details/80399797