1. 信息存储

系列文章目录

信息的表示和处理 :

  1. Information Storage(信息存储)
  2. Integer Representation(整数表示)
  3. Integer Arithmetic(整数运算)
  4. Floating Point(浮点数)


前言

本文参考书籍是《深入理解计算机系统 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来退出另外几个
在这里插入图片描述

  1. 16进制与2进制之间相互转换很简单,详情参考书P25 习题2.1
  2. 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)

对于跨越多字节的对象有两个规则要搞清楚:

  1. 这个对象的地址是什么
  2. 在内存中如何排列这些字节

先说结论:

  1. 多字节对象被存储在连续的字节序列中(连续的地址中)
  2. 对像的地址为所使用字节中最小的地址

假设有一个数 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。
    步骤
  1. 定义掩码:
  • 掩码:0b00110000(这表示只有第 4 和第 5 位是 1,其它都是 0)
  1. 应用掩码:
  • 使用或运算(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

可以看到,对于正数,逻辑右移和算术右移的结果是一样的。 但对于负数,算术右移保留了符号位,使得移动后的结果仍然保持为负数的表达== , 这是数学除法的要求(尤其是当向下取整时)。

在这里插入图片描述

总结

这一章的内容比较简单,主要是科普了一下一些基础概念:进制,内存地址,逻辑运算,移位运算等等。

参考文献:

  1. 《深入理解计算机系统 3th 中文版》
  2. b站up主九曲阑干
  3. 《深入理解计算机系统(CSAPP)》全书学习笔记(详细) 这一章直接的链接是2 信号表示和处理

相关推荐

  1. 分布式存储系统学习(1

    2024-04-15 06:10:03       33 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-15 06:10:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-15 06:10:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-15 06:10:03       87 阅读
  4. Python语言-面向对象

    2024-04-15 06:10:03       97 阅读

热门阅读

  1. [蓝桥杯 2018 省 A] 付账问题

    2024-04-15 06:10:03       39 阅读
  2. C语言经典例题(3)

    2024-04-15 06:10:03       36 阅读
  3. 深入理解SOAP协议:基于XML的分布式通信协议

    2024-04-15 06:10:03       42 阅读