(十八)位操作

1、为什么要进行位操作?
在单片机开发领域也是将C语言作为主要开发语言的,那里的内存空间可是寸土寸金,如何更好的利用好这寸金寸土的内存空间就显得更加重要。

单片机microcontrollers,是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储期ROM、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,就是单片机。单片机在工业控制领域广泛应用,小到比如热水壶遥控器大到控器航天器的芯片等,都是单片机的应用。

单片就是把一个电脑的各个部件的功能缩小放到一个芯片上,单片机虽小,但五脏俱全,有cpu有内存有ROM,还有其他乱七八糟的东西都打包到一块放到一个小芯片上。

上图就是51单片机,大小就像你一个食指的长度。一般情况下单片机的内存是256B,就是256个字节。1k=1024B,1B=8bit。
如果你的程序需要设置一个标志位变量(标志位变量就是用来存放0或1,用来表示真或假的变量),那如果你用一个字节来存放,都显得非常奢侈,你得用一个二进制位即可,就是用一个bit即可。就是一个字节可以让你存8个这样的变量。
所以,对于这种情况,C语言提供了一种叫"位域"的数据结构。
其实,不仅仅限于单片机开发,比如我们图像处理,很多地方就需要位操作。

2、位域
位域又叫位段、位字段。
意思就是位域这种数据结构,允许你把一个字节拆开使用,把一个字节中的二进制位划分成不同的区域,并指定不同区域的位数,并且可以给不同区域命名,就可以对每个区域进行单独使用。

  • 如何使用位域?
    使用位域的做法是:在结构体定义时,在结构体成员后面使用冒号和数字来表示该成员所占的位数。
    注意:一是,你冒号后面的数字代表的是你给这个成员分配的内存位数,这个位数一定要能放得下这个成员,否则报错。二是,你规定的成员的内存位数不能超过它所依附的数据类型的长度。

  • 无名位域
    位域成员可以没有名称,只要给出数据类型和位宽即可。比如下图:

    无名位域一般都是用来填充或调整成员之间的位置的,比如上图中的无名位域成员你可以把它放到成员xy之间,那xy之间就被424个二进制隔开了。由于无名位域没有名称所以不能使用。没名称没法赋值啊。

3、你需要知道的

  • 在C语言标准中,只有signed int和unsigned int支持位域,c99后又增加了bool类型也支持位域。其他数据类型理论上是不支持位域的。但是编译器一般都进行了扩展,一般char也可以支持。

  • 由于内存的基本单位是字节,我们很多函数都是在字节的基础上写的,而位域是对字节的细分,所以很多函数不能对位域进行运算。比如不能对位域进行取址,比如不能sizeof位域的大小。

  • 其实C语言是没有规定一个字节是8位的!实际上C语言并没有规定一个字节的尺寸!C语言对字节的定义是:可寻址的数据存储单位,其尺寸必须可以容纳运行环境的基本字符集的任何成员。其中这里的“基本字符集”指的肯定就是ASCII里面的字符呗。那到底一个字节是多少位呢,这个规定是由编译器来决定的。现在我们的编译器规定是8位,并且将这个规定写在了limits.h这个头文件里面。 

4、位运算符

C语言不仅支持前面讲的“通过位域的形式,按位存取”,C语言还支持“精确到位的运算”。那要会位运算就要学逻辑位运算符以及移位运算符

(1)逻辑位运算符
逻辑位运算符只有4个。逻辑位运算符只作用于整型数据的,并且对数据中的单独每个二进制位进行运算的。

这4个运算符,除了按位取反只有一个操作数之外,其他三个都可以跟赋值号(=)结合到一块,使得代码更加简洁。下面展示一个案例:

(2)移位运算符
移位运算符就是将某个变量中所有的二进制位进行左移或右移的运算符。

同理,移位运算符也是可以跟赋值号(=)结合到一块,使得代码更加简洁。下面代码示例:

如果左移、右移运算符右边的操作数为负数,或者右边的操作数大于左边操作数支持的最大宽度,那么表达式的结果均是属于"未定义行为"。这种情况就由编译器自行决定。所以尽量避免程序中出现这种情况,不然就各种奇怪的报错。

左边的操作数是有符号数还是无符号数,其实对移位运算符也有着不同的影响。无符号数肯定没问题,因为这时候变量里面所有的位都用于表示该数值的大小。但如果是有符号数,那左边第一位是符号位,那移动是否要覆盖符号位,这就又是编译器说了算,所以如果这个数恰好是个负数,而且负数又是以补码形式存在的,所以如果覆盖了,数值都将会发生极大的变化。所以移位操作要慎重。

5、位操作应用————掩码、打开位、关闭位、转置位
掩码指的就是一串二进制数字,通过与目标数据进行按位操作,来达到屏蔽目标数据特定区域的数据的功能。

更多推荐