我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:双彩网 > 正逻辑转换 >

C语言简明教程(十七):位操作之二进制、字节、按位操作和位字

归档日期:07-02       文本归类:正逻辑转换      文章编辑:爱尚语录

  接上一节:结构体类型(struct)、联合类型(union)和枚举类型(enum)详解

  C语言基本上不会被淘汰,因为C是最接近硬件底层和而且同时适合高级语言开发,在嵌入式开发、单片机、系统开发等,即使在多媒体处理方面,C也是被广泛使用。本章讨论的位操作在嵌入式开发或单片机等这些底层开发中经常用到,而在上层应用开发相对用的少,下面我们先来看一下数的进制问题。

  关于数的进制问题,常常觉得多数的资料都讲得很混乱,并没有明确区分数的进制和计算机的存储方式,如果你顺着十进制、二进制、十六进制这样理解,结合补码反码什么的,恐怕会搞得特别混乱。

  所以在这里要特别指出两点:数的进制和计算机的存储方式。数的进制可以有很多种,而十进制只是其中一种,而刚好我们最觉得理所当然的一种,数的进制是独立于计算机而存在的,数最自然的表示,例如二进制1010,三进制12102,十进制123等。

  计算机的存储方式,数据保存到计算机是需要数字化的,例如对声音振幅的采样简单使用一个十进制表示,对图像色点的采样可以使用三个十进制rgb表示,而计算机只能存储两种值0和1,因此使用二进制表示,所以一个十进制数据存储到计算机中需要转为二进制,但是注意,计算机并不严格直接存储二进制数,例如-1010是二进制数,存储在计算机中变成10110,所以数的进制和计算机的存储方式是不同的。

  为什么要转为十进制呢?既然十进制是进制中的其中一种,那么为什么要侧重十进制呢?因为十进制对于我们常人来说最直观,能够直接知道数的意义,所以在这里十进制会是我们侧重的一个,主要是为了观测数字。

  对于八进制和十六进制,这两种进制仅仅是计算机表示二进制数据的一种相对友好的方式,其中一位八进制使用3位二进制表示,一位十六进制使用4位二进制表示。在这里我们重点研究二进制和十进制,因为计算机使用二进制存储数据,而我们能直观读懂十进制,十六进制的可用数是0到15,其中10-15使用a/A – f/F表示,例如F1A。

  二进制整数转为十进制的方法是上面提到的:按位乘2的N次方。二进制小数转换成十进制,首先转换整数部分再转换小数部分,小数部分是按位除以2的N次方,例如:110.11 = 1*2^2 + 1*2^1 + 0*2^0 + 1/(2^1) + 1/(2^2)。

  十进制整数转为二进制:将该整数A除以2,取余数部分,每次除以2的商重新进行下次运算,直到得到的商为0,得到的余数组合则是对应的二进制数,逆序排列,如下图,将十进制整数12转为二进制的过程:

  十进制小数转为二进制,若有整数部分先按上面的规则转换成二进制,然后再处理小数部分,小数部分的转换规则是这样:将小数乘以2,取整数部分,每次乘以2的结果都是使用小数部分进行下次运算,重新运算需要排除整数部分,直到小数部分为0,将整数部分顺序排列,得到的结果就是二进制形式的数,下面是将十进制小数5.125转为二进制小数的过程:

  计算机存储数据是使用二进制的方式,所以在这里面向的对象主要是二进制,但是并不是直接按照二进制数的方式存储的,二进制数和计算机二进制存储的不同主要体现在:符号和浮点数,存储的数包括二进制正整数、有符号整数和二进制浮点数。

  字节是存储系统字符集所需的大小,一般一字节等于8位,该单位也是数据输出速率中使用的单位大小,8位字节又叫做8位组。将一个二进制数0101010从右到左编号,最右边是0,称为低价位,最右边的位是高阶位,计算机存储二进制数一般最左边的1位称为符号位,0表示+正数,1表示-负数。

  另外涉及计算机二进制存储的概念是表示的数个数(组合数),以及表示的数范围,举例,一个八位二进制数,能表示的数个数为2^8个,有符号数的范围为-127到128,无符号的数范围为0-255。

  而二进制正整数的存储方式是:符号位+数值位,例如0110110是一个二进制正整数,1011001是一个二进制负数,如下代码:

  二进制的原码由符号位和正数码组成,符号位是0和1,正数码是一个数的绝对值的二进制数,一个二进制数在计算机中存储是以补码方式存储的,所以正整数的补码等于原码。

  表示有符号整数的方式取决于硬件本身,但是一般来说有符号整数在计算机存储也是采用补码的方式存储的,负数或有符号整数的的补码为:符号位不变,其它位按位取反+1,按位取反即0变1,1变0。

  举例,-5的二进制数是-101,使用4位存储-5时可表示为1101,符号位不变其它位取反:1010+1为1011,所以这时计算机存储-5为1011。使用int存储-5时,最左边的是符号位1,中间使用0补足,看如下代码:

  而求原码的方式为:补码数值位-1,取反即可得到原码,求原码主要是为了从计算机的存储数据中得到真正的标示值。

  二进制浮点数10101.0101,可使用科学记数法表示为1.01010101*2^100,指数100表示4,又称为阶数,. 01010101称为尾数。按照IEEE 754标准,二进制浮点数的存储由符号位+阶码+尾数组成。

  阶码等于阶数+偏移量,阶数是指数,偏移量的计算公式为:2^(e-1)-1,e为阶码的位数,常用的浮点数存储长度为32位和64位,其阶码位数为8位和11位,所以阶码的位数一般是固定的,尾数是科学记数法中的小数部分,如下图:

  二进制按位运算又可分为按位逻辑运算和移位运算,按位逻辑运算是将一个或两个二进制数的每一位相应进行逻辑运算,而移位运算是将单个二进制数的每一位进行左移动或右移动。

  所有按位运算都不会改变原来的值,需要改变原来的值可以使用如+=这样的写法。

  两个位都为真时为真,否则为假,简写方式为&=,按位与可以用于清除位或关闭位,示例代码如下:

  任意一位为真,则为真,否则为假,简写方式为:=,按位与可用于设置位,示例代码如下:

  两位有一个为1,结果为1,但不是两个位都是1,简写方式为^=,按位异或可用于切换位,示例代码如下:

  按位运算常用于操作硬件,就是对一个组位的操作,例如一个字节8位组,对一个位或多个位进行某种操作,常规的操作有:打开位、关闭位、切换位和检查位。

  按位运算的一个常用的东西就是掩码,一般来说掩码用于屏蔽或清零指定位,掩码主要还是用于设置需要操作的位,例如掩码mask=001010,表明需要操作的位为第1位和第3位,cmd & mask表示cmd除了第1位和第3位保持不变,其它位都关闭(清零),下面详细看一个使用示例:

  用于设置指定位为1,即打开指定位,同样需要用到掩码mask,使用按位或,例如mask=1001,cmd mask表示打开第0位和第3位,其它位保持不变,示例代码如下:

  将指定位清零或关闭,使用逻辑与&,直接关闭某些位需要将掩码进行取反操作,例如需要关闭第1和第3位,掩码可设置为mask=1010,进行逻辑与操作时将掩码进行取反,这样其它位保持不变,第1和第3位会被清零,示例代码如下:

  打开已关闭的位,或关闭已打开的位,使用异或^操作,例如掩码mask=100,表示打开或关闭第2位,示例代码如下:

  检查或比较指定位的值是否为0或1,那么不比较的位就需要先进行清零,然后再进行比较,例如掩码mask=100,比较第2位是否等于1,可以将掩码与原数进行逻辑与&操作,清除除了第2位的其它位,再与mask进行比较,即(cmd &mask) == mask,示例代码如下:

  移位运算同样不会改变原来的值,可使用=的方式改变原值,对于有符号数的移位处理取决于系统,无符号数空位填充0。

  所有位按顺序向左边移动,超过左边界的丢弃,右边空位填充0,左移的数学解释为:乘以2的n次幂,n为移动数,示例代码如下:

  超出右边界的值丢弃,左边补0,数学解释为:除以2的n次幂,n为移动数,示例代码如下:

  下面给出两个移位运算的应用,第一个为提取位,使用移位+位关闭操作,另一个是输出数值的二进制位,代码如下:

  位字段使用一个结构体进行声明,可以提供一种更方便的记录/状态设置,在位层面存储变量数据,存储在signed int或unsigned int中变量中的一组相邻位,,也就是说该结构体变量的成员是按照位的方式进行存储的,存储单元默认为4字节32位,一个存储单元可以存储多个值。

  使用结构体声明位字段的要求:就结构体成员分别指定宽度,不指定位宽使用数据成员的默认位宽,不同位宽的变量需要赋值适当的值,不可超过可容纳范围,超过一个int空间的时候,默认进行使用下一个int空间,与上一个int之间留下一个间隙,使用匿名字段,指定位宽为0,可以迫使下一个字段使用下一个int空间,示例代码如下:

  C11提供字节对齐的特性,字节对齐用于描述数据对象在内存中的排列位置,按照不同的字节数对齐对CPU处理数据的速度有所影响,C11提供以下对齐特性:

  _Alignof运算符,计算数据类型的对齐要求,对齐字节数大小,返回值类型为size_t。

  _Alignas对齐说明符,指定一个变量或类型的对齐值,不能小于基本对齐值,一般在变量声明前添加该说明,clang3.2要求_Alignas在类型说明符后面。

  aligned_alloc对齐内存分配,第一个参数为对齐的字节大小,第二个参数为所需字节数大小,下面是一些代码示例:

  C语言简明教程(十八):预处理指令和C函数库完整详解

  C语言简明教程(十六):结构体类型(struct)、联合类型(union)和枚举类型(enum)详解

  C语言简明教程(十五):文件输入输出工作原理和实例详解

  C语言简明教程(十四):存储类别、链接、内存管理和类型限定

  C语言简明教程(十三):字符串和字符串处理函数实例详解

本文链接:http://gilbertpromos.com/zhengluojizhuanhuan/281.html