从零开始的CSAPP(个人记录)

  • 持续更新


前言

  • 大一编程小白,刚学完C++基础内容,一点点的项目经验。
  • 学了sql、数据结构、微信小程序、深度学习等,啥都只会一点点。
  • 此博客根据csapp和哔站csapp的配套课程,写下自认为的重点和理解,内容比较草率。
  • 写此博客作为对自己读薄csapp的监督。
  • 欢迎大佬们对笔记内容的指正和对自己见解的分享
    那我们正式开始吧!

第一章:计算机漫游

Lecture 01: Course Overview

8月25日

书籍内容

  1. C语言是作用于Unix的程序语言而开发出来的
预处理器cpp
编译器cll
汇编器as
链接器ld
磁盘
链接器ld
源程序hello.c
修改了的源程序hello.i
汇编程序hello.s
可重定位目标程序hello.o
可执行的目标程序hello
可执行文件
printf.o
  1. 寄存器 > 高速缓存(SRAM) > 主存(DRAM) > 本地储存(本地磁盘) > 远处储存(Web服务器)

  2. 利用高速缓存,可以将程序性能提升一个数量级

  3. 操作系统的两个功能:

  • 防止硬件被应用程序滥用
  • 向应用程序提供简单的机制来控制低级硬件设备
    文件是对I/O设备的抽象。虚拟内存是对主存和磁盘I/O设备的抽象。进程是对处理器、主存和I/O设备的抽象
  1. 进程:
  • 进程相当于操作系统对一个正在运行的程序的抽象
  • 操作系统保存对进程运行所需的所有状态信息进行跟踪(也就是上下文)
  • 操作系统内核(kernel):管理一个进程到另一个进程的转换。它是系统管理全部进程所用代码和数据结构的集合
  1. 线程:一个进程由多个线程组成。实现并行处理
  2. 虚拟内存:没搞懂
  3. 文件:文件就是字节序列。任何I/O设备都能看成文件。它向应用程序提供了一个统一的视图。
  4. Amdahl定律:当我们对系统的某个部分加速时,对其整体的影响取决于该部分重要性和加速程度
    S = 1 ( 1 − α ) + α / k {\color{red}S = \frac 1{(1-\alpha)+\alpha/k}} S=(1α)+α/k1
    S :加速比(初始所需时间 T o l d / 加速后所需时间 T n e w ) α :系统某部分所需执行时间和系统执行总时间的比例。 k : 该部分性能提升比例 S:加速比(初始所需时间T_{old}/ 加速后所需时间T_{new})\\ \alpha:系统某部分所需执行时间和系统执行总时间的比例。\\ k:该部分性能提升比例 S:加速比(初始所需时间Told/加速后所需时间Tnewα:系统某部分所需执行时间和系统执行总时间的比例。k:该部分性能提升比例

视频补充

  • 整形溢出时,将会成负数

总结

  • 第一章为对全书的概括与入门,因此不过深研究


第二章:信息的表示和处理

Lecture 02: Bits,Bytes,and Integers

8月27日

书籍内容

  1. 64位机器可运行32位
  2. 1字节8位,字节是最小的可寻址的内存单位,而不是位
  3. 指针指向的虚拟地址
  4. 十六进制以0x开头
  5. 字节储存顺序:
  • 最低有效字节放在最前面:小端法(占大多数)
  • 最高有效字节放在最前面:大端法
  1. 强制类型转换对系统级编程非常有用
  2. 使用typedef来给数据类型重命名,提高可读性
  3. int32_t:指定int为32位的
  4. EXCLUSIVE-OR:异或 (^)
^01
001
110

原码:最高位表示符号位,0表示正数,1表示负数,其余位表示数值大小。例如,+5的原码是00000101,-5的原码是10000101。
反码:正数的反码和原码相同,负数的反码是将原码中除符号位外的所有位按位取反。例如,+5的反码是00000101,-5的反码是11111010。
补码:正数的补码和原码相同,负数的补码是将原码中除符号位外的所有位按位取反后加1。例如,+5的补码是00000101,-5的补码是11111011。
补码是计算机中最常用的表示带符号整数的方式,其好处是可以用同一种方式进行加减运算,且减法可以转换成加法。
————————————————
版权声明:本文为CSDN博主「牧鸯人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_61703913/article/details/129331632

  1. x<<k(逻辑左移):x向左移动k位,丢弃最高k位,右端补k个0
  2. x>>k:1. 逻辑右移:x向右移动k位,丢弃最低k位,左端补k个0
    2. 算术右移:x向右移动k位,丢弃最低k位,左端补k个最高值
  • 位移量应小于待位移值的位数
  1. 记录一下练习题2.13与其拓展:
//x:数据字    m:掩码
//bis(位设置):以x为基础,在所有m = 1的位置上,输出z = 1
//bic(位清除):以x为基础,在所有m = 1的位置上,输出z = 0

int bis(int x, int m);
int bic(int x, int m);

//或
int bool_or(int x, int y){
	int res = bis(x, y);
	return res;
}
//异或
int bool_xor(int x, int y){
	int res = bis(bic(x, y), bic(y, x));
	return res;
}

//与    这个是自己写的,不知道能不能化简
int bool_and(int x, int y){
	int res = bic(bic(bis(x, y), bic(x,y)), bic(y, x));
	return res;
}
  1. 如果对第一个参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值
  • 例: a && 5 / a (a && 5)并不会受到之后运算的影响,因此不可能造成被零整除
  1. 仅用位级和逻辑运算,实现x,y是否相等的函数
bool is_same(auto x, auto y){
	return !(x ^ y);
}
  1. 无符号数据类型会比有符号的最大值大一些
  2. 有符号数的最小值的绝对值比最大值大1
  3. Java只支持有符号数
  4. 二进制转无符号数:B2Uw ( w:长度 )
  • B2U4([1011]) = 1 * 23 + 0 * 22 + 1 * 21 + 1 * 20 = 11
  1. 无符号编码具有唯一性,每个二进制对应唯一的无符号数
  2. 补码转有符号数:B2Tw (w:长度)
  • B2T4([1011]) = -1 * 23 + 0 * 22 + 1 * 21 + 1 * 20 = -5
  1. 补码编码同样有唯一性
  2. Java只有补码
  3. 有符号与无符号之间的强制类型转换:
	int a = -123;
	unsigned int b = (unsigned int)a;
	cout << b << endl;
	//输出:4294967173
  • 原因:不改变位表示,仅仅改变了二进制的转换方式
  1. 可以执行一个符号扩展,来保存有符号值的符号,来让补码数字转换成一个更大的数据类型
  2. 隐式的强制类型转换容易发生难以找到的错误!尽量少用无符号数!
int sum_element(int a[], unsigned length){
	int res = 0;
	for(int i = 0; i < length - 1; i++){
		res += a[i];
	}
	return res;
}
//当length传入0时,将会出现内存错误!

视频补充

  • 在访问指针前,先确保它不是空指针

总结

  • 有符号数到无符号数的隐式转换容易发生错误或漏洞,尽量少用
  • 在C/C++中的>>符号可能为算数右移或逻辑右移
  • 字节是最小的可寻址的内存单位,而不是位

Lecture 03: Bits,Bytes,and Integers cont

8月28日

书籍内容

  1. 无符号数加法:
  • 若两个无符号数相加后溢出,则y = y - MAX (MAX:无符号数的最大值)
  • 例:(MAX = 1234)1232, 1233, 0, 1, 2

  • 如何检测? return (x + y) >= x;
  1. 无符号数求反:
  • 加法逆操作 -x = MAX - x
  1. 补码加法:
  • 正溢出,则y = y - MAX
  • 负溢出,则y = MAX + y
  • 例:(MAX = 1234) 1232, 1233, -1234, -1233, -1232, … , 1232, 1233, -1234, -1233

  1. 补码的非:
  • 当x > TMinw时,x补码的非即为-x
  • 当x = TMinw时,x补码的非为TMinw
  • 例:1011(-5) -> 0101(5), 1000(-8) -> 1000(-8)

  • 推理:对每一位求补,再对结果加一([1011] -> [0100] -> [0101])
  1. 无符号乘法:
  • 无符号数x,y实际乘积为(x * y) mod 2w(截断)
  • 例:
    x = [101] --> 5
    y = [011] --> 3
    x * y = [001111] --> 15(截断前)
    x * y = [111] --> 7(截断后)

  1. 补码乘法:
  • 同样mod 2w进行截断,然后再把无符号数转为补码
  • 例(同上):
    x = [101] --> -3
    y = [011] --> 3
    x * y = [110111] --> -9(截断前)
    x * y = [111] --> -1(截断后)
    位级表示是和无符号乘法相同的

  1. 乘以常数:
  • 乘法:10+个时钟周期。除法:30+个时钟周期。其他:1个时钟周期
  • 原因:计算机的乘法相当慢,因此,编译器使用了一个优化----用位移和加减法的组合来代替乘法,也就是LEA指令
  • LEA原理:对一个数左移k,相当于和2k相乘
  • 例:x * 14 = (x<<3) + (x<<2) + (x<<1) = (x<<4) - (x<<1)

  1. 除以2的幂
  • 同上,可以用逻辑,算数右移来实现
  • 但与乘法不同,除法只能除以二的幂,无法表示除以任何常数

视频补充

  • 在64位的计算机上,最大能访问的地址为47位(2 ^ 47)~= 128 * 10 ^ 12字节(非实际)
  • 即使在64位计算机上,不加限定符的int,是32位的
  • 大多数计算机为小端序,但Internet是通过大端序传输的,因此在网络接口,必须进行转化

总结

  • 计算机对整数的运算实际上是模运算
  • 编译器通过把乘除法转换成位移和加减法来加快运行速度

Lecture 04: Floating Point

8月30日

书籍内容

  1. 二进制表示方法:
  • 例:10.1.11 = 1 * 22 + 0 * 21 + 1 * 20 + 1 * 2-1 + 1 * 2-2 = 15 / 4

  • b = ∑ i = − n m 2 i × b i   m : 小数点前的位数 − n : 小数点后的位数 i : 第 i 位 b = \sum\limits_{i = -n}^{m} 2^i \times b^i\\ \space\\ m:小数点前的位数\\ -n:小数点后的位数\\ i:第i位 b=i=nm2i×bi m:小数点前的位数n:小数点后的位数i:i
  1. 二进制的小数点向左移动一位相当于这个数被2除
  2. 定点表示法缺点:无法有效表示非常大的小数
  3. IEEE浮点表示:
  • V = ( − 1 ) s × M × 2 E   s ( 符号 ) : 决定正负。 s = 1 ( 负数 ) , s = 0 ( 正数 ) M ( 尾数 ) : 二进制小数 E ( 阶码 ) : 对浮点数加权,权重是 2 E V = (-1)^s \times M \times 2^E\\ \space\\ s(符号):决定正负。s = 1(负数), s= 0(正数)\\ M(尾数):二进制小数\\ E(阶码):对浮点数加权,权重是2^E V=(1)s×M×2E s(符号):决定正负。s=1(负数),s=0(正数)M(尾数):二进制小数E(阶码):对浮点数加权,权重是2E

单精度浮点(float):
s(1位)+ E(8位)+ M(23位)= 32位
双精度浮点(double):
s(1位)+ E(11位)+ M(52位)= 64位

视频补充

总结



第三章:程序的机器级表示

Lecture 05

9月1日

书籍内容

视频补充

总结


Lecture 06

9月2日

书籍内容

视频补充

总结


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值