bits bytes and integer
课件
第一部分:
第二部分:
课程连接
https://www.bilibili.com/video/BV1iW411d7hd?p=2
https://www.bilibili.com/video/BV1iW411d7hd?p=3
如何表示 bit
- 把模拟信号量化为 bit,高电平代表 1,低电平代表 0
- 存储 bit 比存储模拟信号要简单
字节
C 语言中变量的字节长度
不同的机器不一样
布尔运算
bit 向量布尔运算
bit 和集合
使用 bit 为来表示一个集合,布尔运算可以看做是对集合进行运算:
$
:交集|
:并集^
:对称差集(两个集合各自独有元素组成的集合)~
:补集(针对一个集合进行运算)
C 语言中的逻辑运算
注意
不要和布尔运算符号混淆
图中有一个语句,p && *p
,可以避免空指针引用。GPT 解释:
表达式 p && *p
用于 C 或 C++ 编程中,以确保安全地访问指针指向的值。这个表达式的目的是避免空指针访问,即访问一个未初始化或显式设置为 NULL 的指针,这通常会导致程序崩溃或未定义行为。
组件解释
- p: 这是一个指针变量。在 p && *p 的上下文中,先评估 p 确认它不是 NULL。在 C 或 C++ 中,NULL 指针表示没有指向任何内存位置的指针。
- *p: 这表示解引用 p,即访问 p 指向的值。如果 p 是一个空指针(NULL),解引用它将导致运行时错误。
操作过程
• 逻辑与操作 (&&): 这是一个短路逻辑操作符。它首先检查左侧的表达式(这里是 p),如果 p 为 NULL(在布尔上下文中等同于 false),则整个表达式立即求值为 false,右侧的表达式(*p)将不会被执行。这是关键的,因为它防止了在 p 为 NULL 时尝试解引用 p。
• 如果 p 不是 NULL,则表达式继续评估 *p。这里,*p 将检查 p 指向的值。如果该值为 0(或者在布尔上下文中视为 false),则整个表达式结果为 false。如果 *p 有一个非零值,整个表达式的结果是 true。
使用场景
这种模式经常出现在条件语句中,尤其是在处理可能为 NULL 的指针时。例如,在处理字符串或链表等数据结构时,经常需要检查指针是否为空,以及指向的数据是否有效或具有特定的值。
示例代码
在这个例子中,如果 get_string()
返回一个非 NULL 指针,且指向的第一个字符不是字符串结束字符 \0(在 C 中字符串以 \0 结尾),则第一个 printf 语句将执行。如果指针是 NULL 或指向的内容是 \0,则执行第二个 printf 语句。这种检查方式非常有用,可以避免在访问字符串或数组内容时出现错误。
位移运算
- 左移:最高位舍弃,低位补 0 即可。
- 逻辑右移:高位补 0
- 算术右移:高位补最高位的值
当使用右移运算符号的时候,大多数语言使用的是算术右移。但是 C 语言没有明确的规定是要使用逻辑右移还是算术右移。
如果移动的位数大于了本身的位数,大多数语言会先把移动的位数取模,再进行移动。
整数编码
如何快速的计算补码表示的十进制数笔记中使用的原理其实就是这个幻灯片中所提到的。
4 个 bit 编码示例
4 个 bit 总共有 16 情况,即 0000-1111
。
绘图代码:
16 种情况表示无符号数
二进制 | 十进制 |
---|---|
0000 | 0 |
0001 | 1 |
0010 | 2 |
0011 | 3 |
0100 | 4 |
0101 | 5 |
0110 | 6 |
0111 | 7 |
1000 | 8 |
1001 | 9 |
1010 | 10 |
1011 | 11 |
1100 | 12 |
1101 | 13 |
1110 | 14 |
1111 | 15 |
16 种情况表示原码(有符号数)
二进制 | 十进制(原码) |
---|---|
0000 | +0 |
0001 | +1 |
0010 | +2 |
0011 | +3 |
0100 | +4 |
0101 | +5 |
0110 | +6 |
0111 | +7 |
1000 | -0 |
1001 | -1 |
1010 | -2 |
1011 | -3 |
1100 | -4 |
1101 | -5 |
1110 | -6 |
1111 | -7 |
- 最高位(最左边)为符号位:
0
表示 正数(如0001
表示+1
)。1
表示 负数(如1001
表示-1
)。
- 数值范围
- 4 位原码可表示的数值范围为 -7 到 +7(包括两种零:
+0
和-0
)。
- 4 位原码可表示的数值范围为 -7 到 +7(包括两种零:
- 零的两种表示
0000
表示+0
,1000
表示-0
。原码中零有两种形式,但实际运算中通常视为同一个值。
- 数值计算
- 后三位二进制位表示绝对值,按无符号数转换为十进制,再根据符号位添加正负号。
- 例如:
1010
的数值部分是010
(十进制 2),符号位为 1,因此结果为-2
。
- 优点:直观,符号和数值分离。
- 缺点:
- 存在两种零,增加了逻辑复杂性。
- 加减运算需要额外处理符号位(需判断符号位是否相同),硬件实现复杂。
- 现代计算机通常使用补码(Two’s Complement)替代原码。
16 种情况表示补码(有符号数)
二进制 | 十进制(补码) |
---|---|
0000 | 0 |
0001 | +1 |
0010 | +2 |
0011 | +3 |
0100 | +4 |
0101 | +5 |
0110 | +6 |
0111 | +7 |
1000 | -8 |
1001 | -7 |
1010 | -6 |
1011 | -5 |
1100 | -4 |
1101 | -3 |
1110 | -2 |
1111 | -1 |
- 最高位(最左边) 为符号位:
0
表示 正数(数值直接按无符号二进制转换)。1
表示 负数(数值部分需通过补码规则转换)。
- 数值范围
- 4 位补码的数值范围为 -8 到 +7。
- 最小负数:
1000
(对应十进制-8
),这是补码独有的特殊值。
- 负数计算
- 补码的负数转换步骤:
- 符号位为 1 时,剩余位取反(按位取反)。
- 将取反结果加 1,得到原码的绝对值。
- 添加负号即为十进制值。
- 示例
1010
(补码)→ 符号位为1
,剩余位010
→ 取反得101
→ 加 1 得110
(十进制 6)→ 最终值 -6。1000
(补码)→ 直接对应 -8(无对应正数,无需转换)。
- 补码的负数转换步骤:
优点 | 缺点 |
---|---|
零的唯一性:仅 0000 表示零,无 +0 和 -0 歧义。 | 正负数范围不对称:负数比正数多一个最小负数(如 4 位补码范围为 -8 到 +7 )。 |
运算统一性:加减法可直接用二进制运算,无需额外判断符号位。 | 负数转换复杂性:需通过“取反加 1”步骤转换负数,对初学者不够直观。 |
硬件实现高效:无需设计特殊逻辑处理符号位和数值位。 | 最小负数无对应正数:如 -8 无法取反得到 +8 ,导致绝对值运算溢出。 |
广泛兼容性:现代计算机均采用补码,统一标准简化系统设计。 | 溢出检测复杂:需通过符号位变化判断溢出(如正数相加变负数)。 |
节省存储空间:与反码、原码相比,无需为两种零分配额外位。 | 历史兼容性挑战:旧系统使用原码或反码时,数据迁移需额外转换步骤。 |
数的范围
- 无符号数
- 最小值:0
- 最大值:2 的 w 次方 - 1
- 有符号数
- 最小值:负的 2 的 w-1 次方
- 最大值:2 的 w-1 次方 - 1(因为最高位被用来作为符号位,所以这里是 w-1)
- 最大的负值:-1
常用的数
补码和无符号数之间的转换
todo https://www.bilibili.com/video/BV1iW411d7hd?t=3471.5&p=2