深入理解计算机系统 第二章要点

1.每台机器都有一个字长,指明了整数和指针的标称大小(normal size),长整数(long int)和指针的大小都是字长(32位机器是32位,64位机器是64位),字长代表了机器的寻址时地址大小,进而限定了寻址空间的大小,字长w的寻址范围是0-2的(w-1)次方,32位机上线是4G。除了和字长同步的类型(long int和指针)其他类型大小和机器无关,比如char,short,int4,long long int8, float4, double8在32位机器上对8字节的类型数据操作时,先编译成一系列4字节的操作代码。

2.大小端:对一个2字节的short:0x1234
地址:0x01 0x02
大端:12 34 (先存高有效位,再存低有效位)
小端:34 12
(PS:十进制转十六进制可以用除法,不断除,但显然的,我们可以通过先把一个十进制数字存到内存,计算机会存为一个一个字节,这个时候我们只需按字节取出,
每个字节再细分为2个4位,通过移位得到每半个字节上的数字,然后把每个数字转为对应的十六进制字符(0-f),连起来就ok了,最后注意一下大小端就好了。
其实可以直接用%x输出十六进制结果的 =。=)
网络上字节流中的字节顺序是大端模式。
对多个字节存一个数据的整数,浮点数等,是受大小端影响的,但对字符串,则没有,它就是一个字节存一个字符。
PS:像utf-8这种使用字节序列表示一个字符的,受大小端影响吗?网上资料:字符串倒是没有大端小端的问题,但是字符可能会有大端小端的问题,
因为字符有可能不是一个字节,可能是2个(比如在Java里)或者4个字节(Python里有选项可以使用UTF16或者UTF32),C里也有wchar_t,可能是2个或者4个字节。

3.位向量表示有限集合:
如题,书上给出的例子是这样的:
a=[01101001]表示{0,3,5,6}
b=[01010101]表示{0,2,4,6}
最终a&b={01000001}={0,6}

谁能解释一下这8位二进制是如何表示集合的呢?
答案:第 i 位 为 1 表示 i 在 集合里。从右边数起,第一个是0位,对于a:第0位是1所以集合有0,第3位是1所以集合里有3...

4.布尔类型:
a^0 = a, a^1 = ~a

5.逻辑右移:左边补0,算术右移:左边补最高位。默认地,对无符号数,>>means逻辑右移,对有符号数,>>means算术右移,整数x>>1代表(x-1)/2

6.补码:在无符号数编码的基础上,最高位对应的数值加符号。计算机对有符号数一般使用补码编码
(注意,所谓无符号数编码,补码,反码,原码只是对一系列位的解释,对一个8位数,他们解释成不同的数值,这个解释的逆过程则是他们编码的过程)

7.有符号数和无符号数之间的转换,所谓转换,只是针对某个n位的数,换一种解释的方式,并不改变位值。
C语言在对同时包含有符号数和无符号数的表达式时,隐性把有符号数转成无符号数,再进行计算。
书中说:这个对标准的算术运算,结果和直观无多大差异,只对<和>有差异,但我的测试结果明显不对:

1    if (-1 < 0u)
2    {
3    int i = 0;
4    }
5    else
6    {
7    unsigned int a = 2147483648;// 0x80000000;
8    int c = -2147483647;//0x80000001
9    int j = c - a;//j结果是1
10    int k = 0;
11    }

第1行:-1转成无符号后变得很大,所以执行else,和直观不同
第7-9行:直观上j应该是一个很小的负数,担结果却是1
总结:尽量不要互转,除非你确定任何数值都没有问题。具体分析就是一步一步来,反正规则就是转换只改变解释方式,不改变位值,并且默认有符号转无符号。
在书中还举了个很容易犯的错误:

int sumElement(int a[], unsigned len)
{
int i = 0;
int ret = 0;
for (i = 0; i <= len - 1; ++i)//当len=0时,0u-1得到的无符号数很大,其实本质上是一个负的有符号数转为一个无符号数本身是有问题的!
{    //我想应该没有通用的解决方法,书中说的len改成int是一种解决方法显然不完全对:len很大至变成int是负数呢。
//第二种方法是i < len,这个是因为这个应用中i一定不是负数,
//我觉得应该谨记:避免负的有符号数转无符号数,或者它的逆过程。
ret += a[i];
}
return ret;
}

8.从小数据类型变成大数据类型,如short to int
无符号数左边补0,有符号数左边补最高位

9.同时改变大小和符号情况下,大小优先级高:
short x = -12345;
unsigned int y = x;//y = ff ff cf c7,等于y = (unsigned)((int)x);

10.两个无符号数相加是否溢出:s = x + y; 如果s < x则溢出,因为y < 2的w次方,(s < y也可以)
我突然想起以前做校招笔试题时,就有求2个整数的平均值的问题,(x+y)/2可能溢出,x/2+y/2是错的,正确方式:x + (y-x)/2

11.两个补码相加:
x+y>=2的(w-1)次方:正溢出
x+y<-2的(w-1)次方:负溢出
在中间则正常
x和y都是负数,x+y>=0则会发生负溢出;当x和y都是正数,但x+y<0则发生正溢出
书中特别提到Tmin(比如4位则Tmin=-8),-8的负还是-8!所以对tmin要保持警惕,看下一条:

12.补码的非:x=Tmin则x的非是Tmin,因为Tmin+Tmin=0(这个是对计算机而言哈,不是直观的)
x>Tmin则x的非是-x.
在位级表示上,求x的非的方法:书中提了2种方法,其实原理是一样的,反正x的非就是0-x,想象一下位级的减法:
00000000   :向最高位借1 => 11111112
xxxxxxxx            xxxxxxxx
所以非最低位就是1-原值(0则是1,1则是0,即原值的非),而最低位则是2-原值,即1-原值后+1,这就是书中的方法一了。
书中的方法二也可以推出:找到xxxxxxxx最右边的那个1,左边是原值的非,右边不用借位都保持0,自己的位借了2所以为1.

13.无符号数的乘法和补码的乘法 都使用位数截断。
判断乘法是否溢出可以用下面代码判断:
int mul_ok(int x, int y)
{
int p = x*y;
return !x || p/x == y;
}
x!=0情况的数学证明方法思路是x*y= a + t*2的w次方, b = a/x=>b*x + r = a,当b=y时,t=r=0:不溢出;b!=y时,t!=0溢出
上面是补码乘法溢出判定,无符号数乘法溢出也类似

也可以用先用更大的数据类型存结果,然后转为小数据类型,看相不相等:int x,y; long long int p = x*y; int q = (int)p;if (p!=q)溢出。

14.乘以一个常数可以把常数换成2的幂的和,即把乘法换成移位和加法(减法)

15.先不看浮点数相关,先看第3章:程序的机器级表示,第3章主要讲程序的汇编级别代码

时间: 2024-12-25 19:33:07

深入理解计算机系统 第二章要点的相关文章

CSAPP深入理解计算机系统第二章荟萃

1.可以利用数字的算数右移,然后利用0XFF这样的数字做掩码运算,可以获取到一个数字的符号位.计算机的移位运算有一种很重要的作用就是利用掩码运算去提取一个位模式的一段信息. 2.在C语言中的条件语句,以及三目的条件运算符,都可以用移位的方式来做. 3.在进行位扩展操作的时候,比较讲一个32位的有符号数扩展到64位,那么在保证原来的值不变的情况下,把31个低位扩展到64位的低位上,而最高的符号位扩展到高33位上. 4.利用位模式仅仅只能表示一些2的n次幂的一些浮点数,其他的比较特殊的有理数,会近似

深入理解计算机系统 第二章 信息的表示和处理

欣哥划重点: @所有人, 第二章比较难,我建议至少掌握下面几个知识点: 1. 字节顺序 : 大端和小端 2. 运行 图2-24, 图2-25程序 show-bytes.c 观察结果,看看有什么问题 3. 理解布尔运算,位运算 4. 理解无符号数和有符号数, 给一个数,能计算出补码 5. 理解浮点数的表示法,给一个十进制小数,能转换成二进制的浮点数表示 原文地址:https://www.cnblogs.com/stone94/p/9824395.html

深入理解计算机系统-第二章

疑惑: ***."十进制数字x的ASCII码正好是0x3x"(p31) ```.照上面这么说,十进制1的ASCII码该是0131,很明显错误的,找到一个ASCII码来看下"1"的ASCII码是"49", 再仔细参考下书中上下文,发现上面说了十进制1的ASCII码是31,那原句这么说"十进制数字_x的ASCII码正好是0x3_x"是不是更好理解点, 避免"x"的理解错误,你可能又会说,现在还是不对啊,现在1的

深入理解计算机系统 第二章 信息的表示和处理 part2

上一周遗留问题的解决 问题:原码.反码.补码是只针对有符号数吗?无符号数有没有这三种编码方式? 得到的答案:对于无符号数,原码.反码和补码是一致的 进一步,由于有符号数是以补码的形式存储在计算机中的,而无符号数三种编码都是一致的,所以我们可以说,整型数在计算机中是以补码的形式存在的. 参考文章: https://www.jianshu.com/p/ffc97c4d2306 浮点数 对于浮点数,看了刘大的文章<看完这篇文章,你肯定理解什么是浮点数了>之后,知道了两点 1.浮点数是如何存储的 2.

深入理解计算机系统第二章家庭作业

*2.91遵循位级浮点编码规则,实现具有如下原型的函数: /* Compute |f|. If f is NaN ,then return f. */ float_bits float_absval (float_bits f); 对于浮点数f,这个函数计算|f|.如果f是NaN,你的函数应该简单地返回f. 测试你的函数,对参数f可以取的所有2^32个值求值,将结果与你使用机器的浮点运算得到的结果相比较. 解题过程 ****2.95遵循位级浮点编码规则,实现具有如下原型的函数: /* Compu

深入理解计算机系统 第二章答案

http://rooftrellen.com/blog/computer-systems-a-programmers-perspective-chapter-2-homework-problem/

ASM学习笔记--ASM 4 user guide 第二章要点翻译总结

参考:ASM 4 user guide 第一部分 core API 第二章  类 2.1.1概观 编译后的类包括: l  一个描述部分:包括修饰语(比如public或private).名字.父类.接口或者注释区域. l  类中每个域声明的部分. l  类中每个方法以及构造函数声明的部分.也包含了方法编译后的代码,它是一系列Java字节码指令的形式. 编译后的类结构如下: 2.1.2内部名(internal name) 类或者接口使用内部名,内部名就是类的全限定名,即带斜杠的全称. 例如,Stri

操作系统概论知识理解(第二章)

编了几个故事加深对操作系统的理解: 进程的状态:初始状态,就绪状态,执行状态,等待状态,终止状态. 我初步准备3月6号上午10点找米老师聊天(初始状态):上午十点我站到米老师办公室门口,听了听办公室声音,挺安静的,准备敲门(就绪状态):进门后,和米老师聊天(执行状态):说着一半的时候,有人进来了,找米老师有急事,米老师先处理他的事情,这时我只能站着那里等着(等待状态):等米老师处理完他的事情之后,继续和我聊天,聊完后,心情好多了,和米老师告别后,离开了办公室(终止状态). 进程队列: 队列,队列

深入理解计算机系统第一章

第一章 计算机系统漫游在unix系统中 从源文件到目标文件的转化室由编译器驱动程序完成的linux > gcc -o hello hello.c 编译得过程预处理器,编译器,汇编器,链接器 原文地址:https://www.cnblogs.com/DreamKill/p/12274999.html