C Primer Plus 第15章(位操作)

1. 二进制、位和字节

  • 以 2 为基底表示的数字被称为二进制数(binary number)
1		  1		 	0		  1
1 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0 = 13

1.1 二进制整数

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

    • 1字节 = 8位
  • 对 1 字节(8位)的不同方式解释位组合(bit pattern)

    • unsigned char: 0000 0000 ~ 1111 1111 = 0 ~ 255

    • signed char : 1000 0000 ~ 0111 1111 = -128 ~ 127

1.2 有符号整数

  • 符号量(sign-magnitude) 表示法:1 位**高阶位(high-order bit)**存储符号,剩下 7 位表示数字本身

    • 1111 1111 ~ 0111 1111 = -127 ~ 127
    • 有两个 0 :
      • 0000 0000 = +0
      • 1000 0000 = -0
  • 二进制补码(two’s-complement) 方法:取反,加1

    • 1111 1111 ~ 0111 1111 = -128 ~ 127
  • 二进制反码(one’s-complement) 方法:取反

    • 1000 0000 ~ 0111 1111 = -127 ~ 127
    • 有两个 0 :
      • 0000 0000 = +0
      • 1111 1111 = -0

1.3 二进制浮点数

  • 浮点数分两部分存储
    • 二进制小数
    • 二进制指数

1.3.1 二进制小数

  • 以 2 的幂作为分母
1	  0		1
1/2 + 0/4 + 1/8 = 0.625
  • 许多分数不能用二进制小数准确的表示
    • 只能精确表示多个 1/2 的幂的和

1.3.2 浮点数表示法

  • 若干位存储二进制分数,其他位存储指数

2. 其他进制数

  • 通常使用八进制和十六进制记数系统

2.1 八进制

  • 八进制(octal) 是指八进制记数系统
  • 以 8 为基底表示数字
4		  5			1
4 * 8^2 + 5 * 8^1 + 1 * 8^0 = 297
  • 每个八进制位对应 3 个二进制位

    • 与八进制等价的二进制位

      八进制位等价的二进制位
      0000
      1001
      2010
      3011
      4100
      5101
      6110
      7111

2.2 十六进制

  • 十六进制(hexadecimal 或 hex) 是指十六进制记数系统
  • 以 16 为基底表示数字
A			3			F
10 * 16^2 + 3 * 16^1 + 15 * 16^0 = 2623
  • 每个十六进制位对应 4 个二进制位

    • 十进制、十六进制和等价的二进制位

      十进制十六进制等价二进制
      000000
      110001
      220010
      330011
      440100
      550101
      660110
      770111
      881000
      991001
      10A1010
      11B1011
      12C1100
      13D1101
      14E1110
      15F1111

3. C 按位运算符

3.1 按位逻辑运算符

  • 按位(bitwise) 运算:操作都是针对每一个位进行,不影响左右两边的位

3.1.1 二进制反码或按位取反:~

  • 把 1 变为 0 ,把 0 变为 1
  • 运算符不会改变原值
char c = 0b10011010;
~c;
printf("%d\n%d\n", c, ~c);
// ~(1001 1010) = -102
//   0110 0101  = 101

3.1.2 按位与:&

  • 同为 1 才为 1
char c1 = 0b10010011;
char c2 = 0b00111101;
printf("%d\n", c1 & c2);
// 1001 0011
// 0011 1101
// &
// 0001 0001

3.1.3 按位或:|

  • 有 1 则为 1
char c1 = 0b10010011;
char c2 = 0b00111101;
printf("%d\n", c1 | c2);
// 1001 0011
// 0011 1101
// |
// 1011 1111

3.1.4 按位异或:^

  • 不同则为 1
char c1 = 0b10010011;
char c2 = 0b00111101;
printf("%d\n", c1 ^ c2);
// 1001 0011
// 0011 1101
// ^
// 1010 1110

3.7 移位运算符

3.7.1 左移:<<

  • 将运算符左侧的对象向左移动,右侧对象指定的位数
  • 运算符不会改变原值
char c = 0b10001010;
c << 2;
printf("%d\n%d\n", c, c << 2);
// 00 1000 1010
// 10 0010 1000
//    高位截断
//    0010 1000

3.7.2 右移:>>

  • 将运算符左侧的对象向右移动,右侧对象指定的位数
  • 运算符不会改变原值
char c = 0b10001010;
c >> 2;
printf("%d\n%d\n", c, c >> 2);
// 1000 1010
// 1110 0010 10
// 低位截断
// 1110 0010

3.7.3 用法:移位运算符

  • 针对 2 的幂提供快速乘法和除法
    • number << n :number 乘以 2 的 n 次幂
    • number >> n :如果 number 非负,则用 number 除以 2 的 n 次幂

4. 位字段

  • 位字段(bit field) 是一个 signed int 或 unsigned int 类型变量中的一组相邻的位
  • 通过一个结构声明来建立
struct {
    int a : 1;
    int b : 2;
    int c : 3;
} abc;
// abc 为包含 3 个 1 位的字段

abc.a = 0;
abc.c = 1;
// 由于字段位数为 1 ,所以只能赋值为 0 或 1
  • 如果声明的总位数超过 int (unsigned int 同理)的位数,会用到下一个 int 的存储位置

    • 发生次情况时,第一个 int 中会留下一个未命名的 “洞”
    • 可以使用未命名的字段宽度 “填充” 未命名的 “洞”
    • 使用宽度为 0 的未命名字段使下一个字段存储在下一个 int 中
    struct {
        int a : 1;
        int   : 2;
        int b : 2;
        int   : 0;
        int c : 3;
    } abc;
    // a 和 b 之间有一个 2 位的空隙
    // c 将存储在下一个 int z
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值