目录

位操作


位操作

0011 1100 二进制左侧是高位,右侧是低位

1 二进制数、位和字节

以数字10为基底表示的数字称为十进制数

以数字2为基底表示的数字称为二进制数

二进制系统可以把任意整数表示为 01 的组合。

1.1 二进制整数

1字节包含8位。

C语言用字节(byte) 表示存储系统字符集所需的大小。

描述存储器芯片数据传输率中所用的字节指的是 8位 字节。

1.1.1 有符号整数

如何表示有符号整数取决于硬件,而不是C语言。

原码表示法:-127~127,缺点 +0 和 -0 容易混淆

二进制补码方法

二进制反码方法通过反码位组合中的每一位形成一个负数。

1.2 其他进制数

1.2.1 八进制

八进制是指八进制记数系统。

八进制数转换为二进制形式时,不能去掉中间的0

1.2.2 十六进制

十六进制:十六进制记数系统。

每个十六进制都对应一个4位的二进制数(即4个二进制数)。

十六进制很适合表示字节值。

1.3 C按位运算符

C提供按位逻辑运算符移位运算符

1.3.1 按位逻辑运算符

1.3.1.1 取反:~

二进制反码或按位取反:~ 一元运算符~把 1 变为0,把0变为1。

1.3.1.2 按位与:&

二元运算符&通过逐位比较两个运算对象,生成一个新值。相当于逻辑乘法

重点:任何位与1组合都得本身(保持1号位不变,改变其他各位)。任何位与0组合都得0。

对于每个位,只有两个运算对象中相应的位都为1时,结果才为1(从真/假方面来看,只有当两个位都为真时,结果才为真)。

&运算符经常用于掩码和关闭位

掩码:按位与运算符常用于 掩码(mask)。一些设置为 开(1)关(0)的位组合。

关闭位(清空位):和打开特定的位类似,使用 & ,任何位与1组合都得本身(保持1号位不变,改变其他各位)。任何位与0组合都得0。

检查位的值(检查flags 最地位的值是否是 1):mask = 0001; (flags & mask) == mask,把 flags 上最后一位保留,其余位置覆盖成 0,然后再跟 mask 比较

1.3.1.3 按位或:|

二元运算符 | ,通过逐位比较两个运算对象,生成一个新值。

重点:任何位与0组合,结果都为本身;任何位与1组合,结果都为1。

对于每个位,如果两个运算对象中相应的位只有一个1(非两个为1),结果为1(从真/假考虑,有一个位为真且不是为同为1,那结果为真)。

|经常用于打开位,或者说设置某个位变成 1

打开位(设置位):使用按位或(|) 运算符,任何位与0组合,结果都为本身;任何位与1组合,结果都为1。

1.3.1.4 按位异或:^

二元运算符

重点:任何位与0异或,结果都为本身;任何位与1异或,结果为相反。

逐位比较两个运算对象。 > 对于每个位,如果一个运算对象中相应的位一个为1(但不是两个都为1),结果为1(真假来看,如果两个运算对象中相应的一个位真且不是两个同为1,结果为真)。

切换位:打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符完成。使用异或(^) 运算符,任何位与0异或,结果都为本身;任何位与1异或,结果为相反。

1.3.2 移位运算符

  • 左移<< 将其左侧运算对象每一位的值向左移动右侧运算对象指定的位数

左侧运算对象移出左末端位的值丢失,用0填充空出的位置。

(10001010)<<2 // 表达式
(00101000) // 结果值
  • 右移>> 将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。

左侧运算对象移出,右末端的值丢。

对于无符号类型,用0填充空出的位置。

对于有符号类型,其结果取决于机器。空出的位置可用0填充,或者用符号位(即最左端的位)的副本填充。

每个位向右移动两个位置,空出的位用0填充。

移位运算符针对 2 的幂提供快速有效的乘法和除法

总结

运算符 说明
number « n number 乘以2的n次幂
number » n 如果number为非负,则用number除以2的次幂

1.4 位字段

位字段(bit field):一个signed int 或 unsigned int 类型变量中一组相邻的位(C99和C11新增_Bool类型的位字段)

通常使用位字段作为一种更紧凑的储存数据的方式

通过 结构声明来建立。此结构声明为每个字段提供标签,并确定字段的宽度(单位是 bit)。

struct {
	unsigned int autfd : 1;
	unsigned int bldfc : 1;
	unsigned int undln : 1;
	unsigned int itals : 1;
} prnt;

struct {
	unsigned int L : 2; //低位 2 位
	unsigned int M : 2;
	unsigned int H : 8; //高位 8 位
} prcode;



prnt.itals = 0;
prnt.undln = 1;

prcode.L = 0;
prcode.M = 3;
prcode.H = 102;

prnt 相当于创建了unsigned int 32 位( bit )的最后(低位)的四个位( bit )的结构

prcode 相当于创建了 unsigned int 32(bit), L低位(2bit) ,M 中位(2bit 为了形象点我乱说的),H高位(8bit)

prcode : 0000 0000 0000 0000 0000 [1111 1111] [00] [11]

​ [H ] [M ] [L ]

通过普通的结构成员运算符(.)单独给字段赋值。

需要确保所赋的值不能超出字段可容纳的范围

内含位字段的结构允许在一个存储单元中存储多个设置。

使用位字段通常使得程序的移植性较差

1.5 对齐特性(C11)

对齐:如何安排对象在内存中的位置。

_Alignof 运算符 给出一个类型的对齐要求,在关键字 _Alignof后面的圆括号中写上类型名即可。

size_t d_align = _Alignof(float);

使用_Alignas说明符 指定一个变量类型的对齐值不应该要求该值小于基本对齐值。