目录
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 个二进制位
-
与八进制等价的二进制位
八进制位 等价的二进制位 0 000 1 001 2 010 3 011 4 100 5 101 6 110 7 111
-
2.2 十六进制
- 十六进制(hexadecimal 或 hex) 是指十六进制记数系统
- 以 16 为基底表示数字
A 3 F
10 * 16^2 + 3 * 16^1 + 15 * 16^0 = 2623
-
每个十六进制位对应 4 个二进制位
-
十进制、十六进制和等价的二进制位
十进制 十六进制 等价二进制 0 0 0000 1 1 0001 2 2 0010 3 3 0011 4 4 0100 5 5 0101 6 6 0110 7 7 0111 8 8 1000 9 9 1001 10 A 1010 11 B 1011 12 C 1100 13 D 1101 14 E 1110 15 F 1111
-
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