《CSAPP》二三章小结

  此书第二次看的时候确实不如第一遍看激动人心。

在第二章主要是叙述二进制的运算。虽然这回读的是第三版,但依然是不变的二进制表示,加法,乘法。补码,二进制位移。以及类型转换。

这里面有一些很有意思的符合直觉的东西:

位移分左移(右边添加0),逻辑右移(左边添加0),算术右移(左边添加最高位),与此对应的是较小类型整数与其较大类型整数转换,无符号数就补全0,有符号数就补全最高位(因为要保证数字的值是不变的嘛。)

而且有符号无符号数的来回转换也高度符合这个思想:信息的不变性。

计算机是要用寄存器或者内存保存信息的,不能因为随便的转换就把01序列给改变了啊。所以只能是重新解释这一串01序列,也就是最高位是解释成负权值还是正权值的问题。

与此对应的截断,也是底层的01不变,但是确确实实把前面的部分去掉了,然后依据剩余的01序列解释这个数字。

因此要我看,CSAPP里的某些公式(比如T2U之类的),根本不用记忆,某些符合直觉的思想已经告诉我们应该怎样去看待了。

有了这些依据,也就知道为什么负数表示的范围比整数多一个了。(因为实际上负数是与非负数对应的,差的那个便是0)

再说浮点数,浮点数比较奇特,还有+0,-0....

浮点数的描述是按照IEEE754来表达的,一位的符号位,一部分的小数位,一部分的权重。(这两部分在double与float各不一样),由此可以看出浮点数表示不了精确的数字,只是近似值,这在python里依然有这个毛病,做浮点运算总是差一点点。

第三章讲了机器指令,实际上就是汇编语言。

汇编产生的代码往往能反映出机器运行的本质,比如赋值,加减乘除,引用,等等。

这里让我感兴趣的是leaq指令,这个在第二版并没有提到,这个是“披着寻址指令的加乘法”,实际上等于一条mov指令,把地址计算出来然后放到目的寄存器,计算方式等价于数组寻址方式。

数组,结构体实质上是一样的,都是一段连续的内存,但是结构体会补齐空隙,达到2、4、8的倍数,仅仅是给了每段内存的类型罢了。比如s->x就是计算x成员的首地址。甚至二维、多维数组也是如此。这个在第一次看的时候让我着实惊讶了一下。

比如一个数组int a【2】【3】那么a【1】【1】实质上是引用了a+(2*1+1)*4==>a+12处的地址,也就是依靠划分每段为一个“一维数组”,这就能解释为什么一个二维数组按行遍历比按列遍历更快了,这里面实际上还涉及了缓存命中以及局部性的问题。

而联合是max{e1,e2,e3...}即最大元素的空间大小,机器指令中的三种循环都是以do-while实现的,有的加了条件分支罢了。

分支预测有时候并不可靠,但是流水线工作模式会让它继续执行,直到发现错误就返回原来的地方,这称为分支错误处罚。

调用函数会产生控制传递:把当前调用者下一条指令地址保存,跳转到调用的地址处。然后会在栈上分配空间,留给调用函数的运行。其中需要记住的是寄存器最多保存六个参数,再多就要放进内存啦。

对抗缓存区溢出攻击的方法有:栈随机化(分配时地址随机),溢出检测(用金丝雀值做哨兵,监管这个值是否被修改。

猜你喜欢

转载自blog.csdn.net/weixin_37373020/article/details/80259856