位操作
位操作
0011 1100 二进制左侧是高位,右侧是低位
1 二进制数、位和字节
以数字10
为基底表示的数字称为十进制数
。
以数字2
为基底表示的数字称为二进制数
。
用二进制系统
可以把任意整数表示为 0
和 1
的组合。
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说明符
指定一个变量
或类型的对齐值
。不应该要求该值小于基本对齐值。