系列文章目录
信息的表示和处理 :
- Information Storage(信息存储)
- Integer Representation(整数表示)
- Integer Arithmetic(整数运算)
- Floating Point(浮点数)
文章目录
- 系列文章目录
- 前言
- 一、十六进制表示法(Hexadecimal Notation)
- 二、字数据大小
- 三、寻址和字节顺序(Addressing and Byte Odering)
- 四、表示字符串(Representing String)
- 五、表示代码
- 六、布尔代数简介
- 七、C语言中的位级运算(Bit-Level Operations in C)
- 八、C语言中的逻辑运算(Logical Operation In C)
- 九、C语言中的移位操作(Shift Operation in C)
- 9.1逻辑右移
- 9.2算数右移
- 9.3示例解释
- 总结
- 参考文献:
前言
本文参考书籍是《深入理解计算机系统 3th 中文版》,本文的图片大多是参考和来自于b站up主九曲阑干。非常感谢大佬,侵权删。
内存:
对内存做一个抽象:
将整个内存看做一个大的数组。数组每个元素就是一个空间,空间大小为1字节,每个数组都有一个下标(也就是地址)
字节Byte:
1byte = 8bit
一个存储单元可以存储一个字节,也就是8个二进制位。所以字节计算机的最小存储单元。
可以这样想:一个字节对应一个地址(计算机能够访问的),如果再小,那么计算机就无法通过变量的形式访问。
最小存储空间的变量类型char
就占一个字节,而int
占4个字节
一、十六进制表示法(Hexadecimal Notation)
十六进制以 0x或者0X 开头。
A:10;C:12;F:15
16进制 转换 10进制 转换 2进制 下面尽量记住!
小技巧:记住A,C,F,通过+1 -1来退出另外几个
- 16进制与2进制之间相互转换很简单,详情参考书P25 习题2.1
- 16进制与10进制数之间的转换,详情参考书P26 习题2.2
- 小学奥赛的短除法
- 充分理解进制中每一位代表什么,比如n进制:
( 12345 ) n = 1 × n 4 + 2 × n 3 + 3 × n 2 + 4 × n 1 + 5 × n 0 (12345)_{n} = 1 \times n^{4} + 2 \times n^{3} + 3 \times n^{2} + 4 \times n^{1} + 5 \times n^{0} (12345)n=1×n4+2×n3+3×n2+4×n1+5×n0
其实不管什么方法本质都一样,而第二种方式直指本质。
二、字数据大小
每个计算机有对应的字长(word size),虚拟地址用一个字来编码,所以字长决定了虚拟地址空间的大小。
这样来理解:
每个内存单元式一个字节,一个字节存8bit。这个没有异议。然而还有每个字节都有地址啊,地址也要存储。存储地址用多少位(或者多少字节)?
存储地址用的位的数量越多(因为一一对应的缘故)地址的个数就越多,计算机访问的地址数量越多,能存储的变量所占内存也就越多(因为能访问到(寻址),就能被使用),所以内存就越大!!!
word size | Virtual Address Space |
---|---|
w bit | 0 ~ 2 w 2^w 2w -1 |
32 bit | 0 ~ 2 32 2^{32} 232 -1 ( 4 G B \textcolor{red}{4GB} 4GB) |
64 bit | 0 ~ 2 64 2^{64} 264 -1 |
int32_t 和 int64_t 类型分别为 4 字节和 8 字节,不受机器影响。使用确定大小的整数类型很有用(之前写程序的时候,不太关注类型的大小,以后还是要多关注,特别是嵌入式)。
对 32 位和 64 位机器而言,char、short、int、long long 长度都是一样的,为 1,2,4,8。long 的长度不一样。
float 和 double 的长度一样,分别为 4,8。
对于指针(地址)不同字长的计算机肯定是不同的:32位是4字节,64位是8字节
三、寻址和字节顺序(Addressing and Byte Odering)
对于跨越多字节的对象有两个规则要搞清楚:
- 这个对象的地址是什么
- 在内存中如何排列这些字节
先说结论:
- 多字节对象被存储在连续的字节序列中(连续的地址中)
- 对像的地址为所使用字节中最小的地址
假设有一个数 int
类型 0x01234567
这个数一位就占4bit,所以两位就占8bit(一个字节),在内存中应该是这个样子的:
小端法:数字的低位在前(前就是最小地址)
大端法:数字的高位在前(字节逆序,不是整个数字逆序啊!!)
不管用哪个方法存储,这个数的地址都是0x100
。因为在两种字节序中,0x01234567 的起始地址都是 0x100,但字节的排列顺序不同。这意味着不管是大端法还是小端法,整个 int 类型数据的存储都是从 0x100 开始,但字节内的顺序会根据字节序的不同而改变。
小练习:
输出结果:
67452301
由这个结论可以知道在我的电脑是小端法
四、表示字符串(Representing String)
C语言中字符串最后有个终止符{‘\0’}
- ASCII 字符适合编码英文文档。
- Unicode(UTF-8)使用 4 字节表示字符,一些常用的字符只需要 1 或 2 个字节。所有 ASCII 字符在 UTF-8 中是一样的。
- JAVA 使用 UTF-8 来编码字符串。
五、表示代码
- 二进制代码是不兼容的,一般无法在不同机器间移植。这个作者深有体会,有一次犯蠢把在导师发过来的程序文件中的可执行文件,直接拿到linux上跑,直接就崩掉了。查了一下gpt才知道原来不同机器之间不要跑可执行文件。换一台机器要重新编译。
- 从机器的角度看,程序就是一个字节序列。(详情请学习汇编语言)
六、布尔代数简介
推荐大家去玩Steam上的一个游戏叫做图灵完备(Turing Complete)。看能不能通过这个游戏开一门新的坑,讲讲布尔运算或者进一步讲数字电路(咳咳咳,有生之年系列)
这里的异或(XOR)比较难以理解:
它在两个布尔输入之间进行操作。异或运算符的结果是:当两个输入的值不相同时,输出为真(1);当两个输入的值相同时,输出为假(0)。换句话说,它只有在恰好一个输入为真时才返回真。
七、C语言中的位级运算(Bit-Level Operations in C)
位运算的常见应用是实现掩码。掩码表示从一个字中选出的位的集合。
“实现掩码”(applying a mask)通常指通过位运算操作来选择或屏蔽(mask)数据中的特定位(bits)。
常用的位运算掩码操作
- 与运算(AND):用于选取特定的位。
- 或运算(OR):用于设置特定的位。
- 异或运算(XOR):用于翻转特定的位。
- 非运算(NOT):用于翻转所有位,但通常与其它操作结合以影响特定的位。
示例:使用掩码来读取和修改特定位
假设我们有一个字节(8位)的值,例如 0b11010110,我们想要修改其中的第 4 和第 5 位(从右向左数,从 0 开始),但不影响其它位。
目标
- 确保第 4 和第 5 位被设置为 1。
步骤
- 定义掩码:
- 掩码:0b00110000(这表示只有第 4 和第 5 位是 1,其它都是 0)
- 应用掩码:
- 使用或运算(OR)来设置这两个位。
- 原始值:0b11010110
- 掩码: 0b00110000
- 结果: 0b11110110
#include <stdio.h>
int main() {
unsigned char original = 0b11010110;
unsigned char mask = 0b00110000; // 掩码,旨在设置第 4 和第 5 位
unsigned char result = original | mask; // 应用掩码
printf("Original: 0x%X\n", original);
printf("Mask: 0x%X\n", mask);
printf("Result: 0x%X\n", result);
return 0;
}
八、C语言中的逻辑运算(Logical Operation In C)
区分逻辑操作和按位操作
逻辑操作的结果只有0(False)或者1(True)
operator | |
---|---|
|| | OR |
&& | AND |
! | NOT |
逻辑运算符 && 和 || 如果第一个参数就能确定结果,就不再计算第二个参数(被称作“短路评估”(short-circuit evaluation))
九、C语言中的移位操作(Shift Operation in C)
左移 k 位丢掉最高的 k 位,并在右端补 k 个 0。
右移分为逻辑右移和算术右移。其中逻辑右移的逻辑和左移没啥区别,一个作一个右,超出的丢掉,多出的补个damn(0)(狗头)
9.1逻辑右移
逻辑右移(>> )会将数字的所有位向右移动指定的位数,并在左边空出的位填充0。逻辑右移不考虑数字的符号,即它仅仅是单纯地移动位,并且在左边补零。
适用性: 逻辑右移适用于无符号数字,因为它保持了数字的二进制表达形式不变,不涉及符号位的处理。
9.2算数右移
算术右移(通常表示为 >>)也会将数字的所有位向右移动指定的位数,但它在左边空出的位填充的是符号位(即最左边的位)的副本。这意味着如果数是正的(符号位为0),则左边填充0;如果数是负的(符号位为1),则左边填充1。
适用性: 算术右移适用于有符号数字,特别是在进行数学运算时保持符号位的一致性是非常有用的,例如,它可以被用来快速实现除以2的操作。
9.3示例解释
假设我们有一个字节(8位),数值分别为正和负:
-
逻辑右移:
- 正数: 00101100 逻辑右移2位变为 00001011
- 负数: 10101100 逻辑右移2位变为 00101011
-
算术右移:
- 正数: 00101100 算术右移2位变为 00001011
- 负数: 10101100 算术右移2位变为 11101011
可以看到,对于正数,逻辑右移和算术右移的结果是一样的。 但对于负数,算术右移保留了符号位,使得移动后的结果仍然保持为负数的表达== , 这是数学除法的要求(尤其是当向下取整时)。
总结
这一章的内容比较简单,主要是科普了一下一些基础概念:进制,内存地址,逻辑运算,移位运算等等。
参考文献:
- 《深入理解计算机系统 3th 中文版》
- b站up主九曲阑干
- 《深入理解计算机系统(CSAPP)》全书学习笔记(详细) 这一章直接的链接是2 信号表示和处理