信息的表示和处理
信息的存储(Information Storage)
通常情况下,程序将内存视为一个巨大的数组,数组中的元素是由一个个字节组成,每个字节都有一个唯一的数字表示,称之为地址(address),这些所有地址的集合就称为虚拟地址空间(virtual address space)
字节(Byte)
-
信息存储的基本单元
-
一个字节由8个位(bit)组成
- 二进制表示中,每个位有两个状态,0或1
- 8位全为0时,表示一个字节的最小值
- 8位全为1时,表示一个字节的最大值
- 范围:十进制:[0,255],把这种按照一位一位表示的模式成为位模式(个人理解位模式就是二进制表示法)
-
十六进制(Hexadecimal Notation)![[Pasted image 20240207205011.png]]
- 引入原因:2进制表示比较麻烦,10进制表示与位模式之间的转换又比较麻烦
- C语言中,16进制数以0x开头(x大小写均可),字母大小写均可,大小写混用也是可以的 -
进制转换
- 小技巧:记住0xA 1010 0xC 1100 0xF 1111 就能记住所有16进制表示(深入理解计算机系统一书提及)
-
Cocert between Hex and Binary
- 16->2:通过展开每个16进制数,然后转换成对应的二进制格式
- 2->16:将二进制四位一组,转换成16进制数,如果总位数不是4的倍数,最左边一组补0
-
将2的n次方的数快速转换成2进制
- 2 n = 1 ( 000 ) n 2^n=1(000)_{n} 2n=1(000)n,n次方就是1后面跟n个0, n = i + 4 j n=i+4j n=i+4j,i是余数{0,1,2,3},对应就是 000 0 2 = 0 16 0000_{2}=0_{16} 00002=016, 001 0 2 = 2 16 0010_{2}=2_{16} 00102=216, 0100 = 4 16 0100=4_{16} 0100=416, 100 0 2 = 8 16 1000_{2}=8_{16} 10002=816
- 2 n = 1 ( 000 ) n 2^n=1(000)_{n} 2n=1(000)n,n次方就是1后面跟n个0, n = i + 4 j n=i+4j n=i+4j,i是余数{0,1,2,3},对应就是 000 0 2 = 0 16 0000_{2}=0_{16} 00002=016, 001 0 2 = 2 16 0010_{2}=2_{16} 00102=216, 0100 = 4 16 0100=4_{16} 0100=416, 100 0 2 = 8 16 1000_{2}=8_{16} 10002=816
-
Covert between Hex and Decimal
- 方法:采用除法或者乘法
- 辗转相除法
-
10->16:10进制数除16,得到余数即为该位的值,最后结果从开始到最后对应从最大位到最小位
-
16->10:16的幂乘以相应位的16进制数
-
-
- 小技巧:记住0xA 1010 0xC 1100 0xF 1111 就能记住所有16进制表示(深入理解计算机系统一书提及)
-
字长(Words)
-
决定了虚拟空间地址最大可以到多少( w b i t = 2 w − 1 w\;bit=2^{w}-1 wbit=2w−1)
-
32位与64位机器
- 区别:系统如何编译的,而不是运行的机器类型
- 大部分系统都已经从32位迁移到64位,在嵌入式中的部分依然是32位,大多数的64位做了向后兼容,因此32位也可以运行在64位的机器上
- 64位的机器可通过命令
linux> gcc -m32 -o hello32 hello.c
编译生成可以在32位机器上运行的程序(hello32既可以运行在32位的机器上也可以运行在64位的机器上) - 32位的机器可通过命令
linux> gcc -m64 -o hello32 hello.c
编译生成可以在64位机器上运行的程序(hello64只能运行在64位的机器上)
-
C语言中的数据格式占用的字节(Bytes)
-
对于我们来说,我们需要搞懂存储数据的地址,以及数据是如何在内存中排布的
Addressing and Byte Ordering
- 例子说明
-
变量x = 0x01234567,地址位0x100 ,最高有效字节为0x01,最低有效字节为0x67
-
int型占4个字节,所以变量x被存储到地址为0x100,0x101,0x102,0x103的内存处
-
大端法(Big endian)
- 最高有效字节被存储到最前面(低地址处)
- 最高有效字节被存储到最前面(低地址处)
-
小端法(Little endian)
- 最高有效字节被存储到最后面(高地址处)
- 最高有效字节被存储到最后面(高地址处)
-
大多数 Intel 兼容机采用小端法,IBM与Sun公司的机器大多采用大端法,很多新的处理器支持双端法(基于ARMA架构的处理器),Android 和 IOS只支持小端法
-
-
在四种不同的系统上运行字节打印程序
- 字节打印程序,打印输出程序对象的字节表示。
byte_pointer
是强制类型转换,告诉程序把指针x看成指向一个字节的序列,而不是的原始数据类型![[Pasted image 20240207223516.png]] - 运行结果
-
整形
-
浮点型
-
指针的值
- 不同操作系统使用不同的存储分配规则,指针的值是完全不同的(32bit的机器使用4字节地址,64位使用8字节地址)
- 不同操作系统使用不同的存储分配规则,指针的值是完全不同的(32bit的机器使用4字节地址,64位使用8字节地址)
-
整型与浮点型
-
有着完全不同的字节模式
-
有13位的匹配序列
-
-
- 字节打印程序,打印输出程序对象的字节表示。
-
Representing Strings
-
C语言中的字符串被编码位以NULL字符结尾的字符数组
- 例子:
const char *s="abcde"
- s的长度为6,因为结尾字符null的存在
- 例子:
-
show_bytes((byte_pointer) s, strlen(s));
-
作用:得到每个字符串在内存中对应的存储信息
-
结尾字符(null)的十六进制表示为 0x00,使用ASCII来表示字符,在所有系统上会得到相同的结果,文本数据比二进制数据具有更强的平台独立性(计算机系统的平台独立性是指软件在不同的硬件平台上都能够运行,而不需要针对特定的硬件进行修改。这意味着软件可以在不同的操作系统和处理器架构上运行,而不需要进行修改。)
-
计算机编码,存储和操作信息的核心是二进制编码
-
Boolean Algebra
- 乔治布尔将逻辑值true和false编码成二进制的1和0,设计出了布尔代数作为逻辑推理的基本原则
- 布尔代数定义的运算
-
[ ~/NOT ] 非,取反
-
[ &/AND] 与
-
[ |/OR] 或
-
[
^/EXCULUSIIVE_OR
]异或
-
C语言中的位级运算(Bit-Level Operations in C)
- 确定一个位级表达式结果的方法
- 将十六进制扩展成二进制表示----->按位进行相应运算----->再转换回十六进制。其他位级运算操作相似![[Pasted image 20240210184924.png]]
掩码运算(Masking Operations)
- 通俗:通过位运算可以得到特定的位序列
- 例子:
- 对于操作数0x 89 AB CD EF(16进制转换成二进制再进行位运算),想得到该操作数的最低有效字节(LSB)的值
-
最低有效字节(LSB) 是一个二进制数字中的第0位(即最低位)
-
最高有效字节(MSB) 是一个二进制数字中的第n-1位(即最高位)
-
&0x FF,得到最低有效字节0x 00 00 00 EF
-
多字节序列中最小权重的字节是指在UTF-8编码中,由于采用了变长编码方式,一个字符可能由多个字节组成,而其中的最小权重字节是指编码值最小的那个字节。在UTF-8编码中,最小权重的字节通常是以10开头的字节。
-
小端方式:指令中给出的地址是操作数最低有效字节(LSB)所在的地址
-
- 对于操作数0x 89 AB CD EF(16进制转换成二进制再进行位运算),想得到该操作数的最低有效字节(LSB)的值
逻辑运算(Logical Operations in C)
逻辑运算认为所有非零的参数都表示true, 只有参数0表示false
例子:if(a && 5/a) :避免了a为0的情况
移位运算(Shift Operation in C)
左移:整体左移一位,丢弃左端数据,右端补0
- 例子:
-
初始:01100011
-
左移一位:11000110
-
右移:分为逻辑右移和算术右移,丢弃右端数据,左端补0
逻辑右移:只与左移有方向上的区别,整体右移一位,丢弃右端数据,左端补0
算术右移:
- 最高位为0:与逻辑右移一致
- 最高位为1:整体右移一位,丢弃右端数据,左端补1
虽然C语言中没有规定有符号数使用哪一种右移方式,但实际上几乎所有编译器以及机器的组合都对有符号数使用的是算术右移,对于无符号数使用的一定是逻辑右移