描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787121445316
作为Randall1Hyde经典著作《编程卓越之道》系列的第1卷,《深入理解计算机》深入地研究了计算机结构,却不需要读者掌握汇编语言。本书是为使用高级编程语言的读者编写的,填补了他们有关计算机底层细节的知识空白。这些知识往往被计算机科学和工程课程遗漏。通过本书可以了解:
● 数字、字符串及高级数据结构在计算机中是如何表示的,这样我们就能理解使用这些数据的固有成本
● 数据应该如何组织才能被计算机有效地访问
● CPU是如何运行的,这样我们可以遵循计算机的运行方式来编写代码
● I/O设备是如何运行的,这样我们就能了解应用程序访问这些设备的性能优化过程
● 如何充分地利用内存层次结构来生成快速运行的程序
卓越的代码是高效的。但在学会编写真正高效的代码之前,我们必须了解计算机系统是如何执行程序的,也必须了解编程语言中抽象的概念和计算机的底层硬件之间是如何映射的。毕竟,好的机器码是程序员写出来的,不是编译器编译出来的。本书的内容是构建所有伟大软件的基础。
卓越的代码需要利用现代编程语言的先进特性来实现软件功能。但软件最终都要运行在计算机上,无论它是采用哪种编程语言编写的。因此,卓越的软件代码也要充分地利用计算机中的各种资源,将计算机的性能发挥到极致。现代编程语言将这些知识隐藏了起来,容易被我们忽视。因此,《编程卓越之道》系列的第一卷《深入理解计算机》将重点放在软件执行背后的计算机底层上,深入浅出地介绍了计算机体系结构的方方面面,帮助我们理解如何才能写出在计算机上高效运行的代码。本书具体内容包括:数字、字符串及复合数据结构在计算机中的表示形式,以及如何在内存层次结构中访问这些数据;基本的二进制运算、位运算、布尔逻辑,以及如何设计完成运算的中央处理器指令集;输入/输出、大容量存储等丰富多彩的外设,以及把这些外设和计算机相连进行通信的各种总线技术。本书适合软/硬件开发人员及系统程序员、移动及嵌入式设备开发者、体系结构设计人员,以及高校计算机相关专业师生。
1 编写卓越代码须知 1
1.1 《编程卓越之道》系列 1
1.2 本书涵盖的主题 2
1.3 阅读本书的前提 4
1.4 卓越代码的特征 5
1.5 本书要求的环境 6
1.6 额外建议 7
1.7 更多信息 7
2 数字表示 8
2.1 什么是数字 8
2.2 计数系统 9
2.2.1 十进制位值计数系统 10
2.2.2 底数(基数) 11
2.2.3 二进制计数系统 12
2.2.4 十六进制计数系统 15
2.2.5 八进制计数系统 17
2.3 数字/字符串转换 18
2.4 内部数字表示形式 20
2.4.1 位 20
2.4.2 位串 21
2.5 有符号和无符号数 24
2.6 二进制数的属性 26
2.7 符号扩展、零扩展和收缩 27
2.8 饱和操作 31
2.9 二进制编码的十进制表示 32
2.10 定点表示形式 33
2.11 比例数字格式 35
2.12 有理数表示形式 37
2.13 更多信息 38
3 二进制算术运算和位运算 39
3.1 二进制和十六进制数字的算术运算 39
3.1.1 二进制加法 40
3.1.2 二进制减法 41
3.1.3 二进制乘法 42
3.1.4 二进制除法 43
3.2 位的逻辑运算 45
3.3 二进制数值和位串的逻辑运算 47
3.4 有用的位运算 48
3.4.1 使用AND运算判断位串中的一位 49
3.4.2 使用AND运算判断多个位为零或非零 49
3.4.3 比较二进制字符串中的多个位 50
3.4.4 使用AND运算创建模n计数器 51
3.5 移位和旋转 52
3.6 位字段和打包数据 55
3.7 数据的打包和解包 60
3.8 更多信息 65
4 浮点表示形式 66
4.1 浮点运算简介 66
4.2 IEEE 浮点格式 72
4.2.1 单精度浮点格式 72
4.2.2 双精度浮点格式 74
4.2.3 扩展精度浮点格式 75
4.2.4 四精度浮点格式 76
4.3 规约形式与非规约形式 76
4.4 舍入 77
4.5 特殊的浮点值 79
4.6 浮点数异常 80
4.7 浮点运算 81
4.7.1 浮点表示形式 82
4.7.2 浮点数的加减法 82
4.7.3 浮点数的乘除法 93
4.8 更多信息 102
5 字符表示形式 103
5.1 字符数据 103
5.1.1 ASCII字符集 104
5.1.2 EBCDIC字符集 107
5.1.3 双字节字符集 108
5.1.4 Unicode字符集 109
5.1.5 Unicode码位 110
5.1.6 Unicode编码平面 111
5.1.7 代用码位 111
5.1.8 字形、字符和字素簇 112
5.1.9 Unicode规范和规范等价性 115
5.1.10 Unicode编码 116
5.1.11 Unicode组合字符 118
5.2 字符串 120
5.2.1 字符串格式 120
5.2.2 静态字符串、伪动态字符串和动态字符串 127
5.2.3 字符串的引用计数 129
5.2.4 Delphi字符串 130
5.2.5 自定义字符串格式 130
5.3 字符集数据类型 130
5.3.1 字符集的幂集表示形式 131
5.3.2 字符集的列表表示形式 132
5.4 设计自定义字符集 133
5.4.1 设计高效的字符集 134
5.4.2 数字字符的编码分组 135
5.4.3 字母字符分组 135
5.4.4 比较字母字符 138
5.4.5 其他字符分组 140
5.5 更多信息 143
6 内存结构和访问 144
6.1 基本系统组件 144
6.1.1 系统总线 145
6.2 内存的物理结构 148
6.2.1 8位数据总线 151
6.2.2 16位数据总线 152
6.2.3 32位数据总线 155
6.2.4 64位数据总线 156
6.2.5 非80×86处理器对小单位内存的访问 156
6.3 大端序与小端序结构 157
6.4 系统时钟 163
6.4.1 内存访问和系统时钟 165
6.4.2 等待状态 166
6.4.3 缓存 168
6.5 CPU的内存访问模式 172
6.5.1 直接内存寻址模式 172
6.5.2 间接寻址模式 173
6.5.3 变址寻址模式 174
6.5.4 比例变址寻址模式 175
6.6 更多信息 175
7 复合数据类型与内存对象 176
7.1 指针类型 176
7.1.1 指针的实现 178
7.1.2 指针与动态内存分配 179
7.1.3 指针操作与指针运算 179
7.2 数组 184
7.2.1 数组声明 185
7.2.2 内存中的数组表示形式 188
7.2.3 访问数组元素 190
7.2.4 多维数组 190
7.3 记录/结构体 200
7.3.1 Pascal/Delphi记录 201
7.3.2 C/C 记录 202
7.3.3 HLA记录 203
7.3.4 Swift记录(元组) 203
7.3.5 记录的内存存储 204
7.4 判别联合 207
7.4.1 C/C 联合 208
7.4.2 Pascal/Delphi联合 208
7.4.3 Swift联合 209
7.4.4 HLA联合 211
7.4.5 联合的内存存储 211
7.4.6 联合的其他用途 213
7.5 类 214
7.5.1 继承 216
7.5.2 类构造函数 221
7.5.3 多态 224
7.5.4 抽象方法和抽象基类 225
7.6 C 类 229
7.6.1 C 中的抽象成员函数和类 230
7.6.2 C 的多重继承 231
7.7 Java类 233
7.8 Swift类 234
7.9 协议与接口 235
7.10 泛型和模板 239
7.11 更多信息 241
8 布尔逻辑与数字设计 242
8.1 布尔代数 243
8.1.1 布尔运算符 243
8.1.2 布尔假设 243
8.1.3 布尔运算符优先级 246
8.2 布尔函数与真值表 246
8.3 函数编号 248
8.4 布尔表达式的代数运算 250
8.5 规范形式 250
8.5.1 极小项和规范形式与真值表 252
8.5.2 使用代数方法得到极小项和规范形式 254
8.5.3 极大项积规范形式 255
8.6 布尔函数简化 256
8.7 这和计算机有什么关系 264
8.7.1 电路与布尔函数 265
8.7.2 组合电路 267
8.7.3 时序与时钟逻辑 274
8.8 更多信息 278
9 CPU 体系结构 280
9.1 CPU设计基础 280
9.2 指令的解码与执行:随机逻辑与微码 283
9.3 指令执行详解 284
9.3.1 mov指令 285
9.3.2 add指令 286
9.3.3 jnz指令 288
9.3.4 loop指令 289
9.4 RISC还是CISC:通过执行更多更快的指令来提高性能 290
9.5 提高处理速度的关键:并行 291
9.5.1 功能单元 294
9.5.2 预取队列 296
9.5.3 影响预取队列性能的情况 299
9.5.4 同时执行多条指令的流水线 299
9.5.5 指令缓存:提供多条内存访问通路 304
9.5.6 流水线冒险 306
9.5.7 超标量运算:并行执行指令 308
9.5.8 乱序执行 310
9.5.9 寄存器重命名 310
9.5.10 甚长指令字体系结构 312
9.5.11 并行处理 312
9.5.12 多处理 313
9.6 更多信息 315
10 指令集体系结构 316
10.1 指令集设计的重要性 317
10.2 指令设计的基本目标 318
10.2.1 操作码的长度选择 320
10.2.2 规划未来 322
10.2.3 选择指令 322
10.2.4 分配指令操作码 323
10.3 假想处理器Y86 324
10.3.1 Y86的限制 324
10.3.2 Y86指令 325
10.3.3 Y86的寻址模式 327
10.3.4 Y86指令编码 327
10.3.5 Y86指令编码示例 330
10.3.6 扩展Y86指令集 335
10.4 80×86 指令编码 336
10.4.1 指令操作码的编码 339
10.4.2 add指令编码的例子 346
10.4.3 x86的立即(常量)操作数编码 351
10.4.4 8位、16位和32位操作数的编码 352
10.4.5 64位操作数编码 353
10.4.6 指令的替代编码 353
10.5 指令集设计对程序员的意义 354
10.6 更多信息 354
11 内存体系结构与组织 355
11.1 内存层次结构 355
11.2 内存层次结构的工作原理 359
11.3 内存子系统的性能差距 360
11.4 缓存体系结构 362
11.4.1 直接映射缓存 364
11.4.2 全相联缓存 365
11.4.3 n路组相联缓存 365
11.4.4 缓存行置换策略 367
11.4.5 缓存写入策略 368
11.4.6 缓存使用与软件 369
11.5 NUMA与外设 370
11.6 虚拟内存、内存保护与分页 370
11.7 编写理解内存层次结构的软件 375
11.8 运行时的内存结构 376
11.8.1 静态对象与动态对象,绑定与生命期 378
11.8.2 代码段、只读数据段与常量段 379
11.8.3 静态变量段 380
11.8.4 存储变量段 380
11.8.5 栈 381
11.8.6 堆与动态内存分配 381
11.9 更多信息 388
12 输入与输出 389
12.1 连接CPU与外界 389
12.2 端口和系统连接的其他方式 393
12.3 输入/输出机制 394
12.3.1 内存映射输入/输出 395
12.3.2 I/O映射输入/输出 396
12.3.3 直接内存访问 396
12.4 输入/输出速度等级 397
12.5 系统总线与数据传输速率 398
12.5.1 PCI总线的性能 400
12.5.2 ISA总线的性能 401
12.5.3 AGP总线 401
12.6 缓冲 402
12.7 握手 403
12.8 I/O端口超时 404
12.9 中断与轮询式I/O 405
12.10 保护模式操作与设备驱动程序 406
12.10.1 设备驱动模型 407
12.10.2 与设备驱动程序通信 408
12.11 更多信息 409
13 计算机外设总线 410
13.1 小型计算机系统接口 410
13.1.1 限制 411
13.1.2 改进 412
13.1.3 SCSI协议 413
13.1.4 SCSI的优点 415
13.2 IDE/ATA接口 416
13.2.1 SATA接口 417
13.2.2 光纤通道 418
13.3 通用串行总线 418
13.3.1 USB设计 418
13.3.2 USB性能 420
13.3.3 USB传输的类型 421
13.3.4 USB-C 423
13.3.5 USB设备驱动程序 424
13.4 更多信息 425
14 大容量存储设备与文件系统 426
14.1 磁盘驱动器 426
14.1.1 软盘驱动器 427
14.1.2 硬盘驱动器 427
14.1.3 RAID系统 433
14.1.4 光驱 435
14.1.5 CD、DVD与蓝光驱动器 436
14.2 磁带驱动器 438
14.3 闪存 439
14.4 RAM盘 441
14.
推荐序1
给自己从底层重修的胆量
拿到新一版《编程卓越之道》的第一卷《深入理解计算机》的稿子,心里非常感慨:上次读这本书,已经是16年前,还留下了幼稚的读后感[ https://blog.csdn.net/gzlaiyonghao/article/details/766912]。今天回头看书稿和自己当年的文字,汇编语言以及WebAssembly等底层技术的新面貌再度翻红,而程序员的基本功仍然是与同行拉开距离的最大因素,花时间与精力深入理解计算机还是回报率最高的“投资”。
以此来看,2006年我在博客上留下的印记仍然有适用性,仍然值得新的读者参考,所以大胆地编辑了一下,作为推荐序。
本书是《编程卓越之道》(英文名:Write Great Code)四卷本中文版的第一卷。这本书是好书,作者Randall Hyde对计算机系统的深入理解跃然纸上,从数值在计算机中的表示到二进制算术和位运算从浮点数表示到字符表示及字符串组织,从内存的组织与访问到CPU体系结构,从指令集到输入/输出,娓娓道来,它们的优缺点和瓶颈了然于胸。
作者并没有教你优化的方法,而是告诉你哪里会有陷阱。记得《C 编程规范》里有一条规范是避免代码劣化,这本书全书都在印证这一说法——如果你没有能力优化,起码要保持它没有被劣化。参加过一些代码评审,有时候会看到一两段代码写得比较耗CPU和内存,比如在局面重置时全部生成新的对象,或者在条件判断时把不太可能发生的情况放在前面。当评审人指出问题时,听到的最多的辩解是:“嗯,这里是有问题,因为项目刚开始,代码不成熟,我们打算在正式版(下一版)优化它。”但我想说的是:“你不是在做优化,只是把劣化的代码改正过来而已。”同样是来自《C 编程规范》,有一句话说得很好:优化应该在代码稳定成熟了之后再做,防止劣化却要时刻进行(大意如此)。阅读本书能使你大大减少踩入劣化的陷阱。
作为以编写卓越代码为目标的程序员,精读《编程卓越之道》四卷本的意义绝不止于加固基础那么简单,我更大的感触是它让我认识到基础的重要性。从小学到大学,胸无大志的我耍着几分小聪明就轻松过关。而正是这当年引以为傲的小聪明,让我不重视基础,以为生活和工作也会像考试一样逃不出自己的聪明脑袋。大学毕业校招进了网易游戏部门,身边高手如云,想奋起直追时才知道自己下盘不稳、根基不牢。因为自己害怕离开自己熟悉的语言和平台不能让自己发挥小聪明,让人识破自己是只纸糊的“老虎”,心魔成了追求进步的最大障碍。直到工作了很久之后,才有胆量卸下“偶像包袱”,给自己从底层重修的胆量,慢慢走上自我修身之路。而《编程卓越之道》是很好的“修”技术之“身”的书,我打算四卷全读。
读完第一卷,我的感想是,做大事要有做大事的策略,但天下大事必作于细,没有坚实的基础知识,是没有掌控大事的能力的。所以,要放好心态,给自己慢慢来的胆量,一步一步来,从底层重修。
——小红花技术领袖俱乐部创始人 赖勇浩
推荐序2
什么是卓越代码(Great Code)?场景不同,角色不同,对卓越的定义自然有所不同。既然没有统一的标准,似乎可以放过不提。然而,本书系列题为《编程卓越之道》,又如何可以轻易放过对卓越的认识?细品作者Randall Hyde采纳的定义:
卓越代码是按照一套一致的优秀软件特征编写出来的,首要考虑的是优秀软件特征。特别是,卓越代码要遵循一套规则,这套规则能够指导程序员在用源码实现算法时的决策。
单就定义而言,依旧语焉不详。关于什么是优秀软件特征,或许大家可以从书中寻觅到答案。而我却透过书名,隐隐捕捉到Randall Hyde的一个观点——没有深谙计算机底层原理,不可能写出卓越的代码。——这也正是本书(卷1)的核心思想:深入理解计算机。
听听作者自己的解释:
了解了计算机如何表示数据,就了解了高级语言的数据类型是被如何转换到机器层次的;了解了CPU如何执行机器指令,就了解了高级语言应用程序中各种操作的代价;了解了内存性能,就了解了如何组织高级语言中的变量和其他数据,让缓存和内存的访问最优。
此言非虚。正如要学好Java,就有必要了解JVM的工作原理,而要彻底了解JVM,怎能不知道计算机的底层原理?以指令集为例,这是汇编程序员天天使用的基本编程要素,而Java程序员就鲜少涉猎。殊不知,这些Java程序员编写的每行代码都会被编译为运行在JVM中的指令。对照来看,恰好本书介绍了短指令和长指令在空间、性能与复杂度的取舍,而JVM则采用了折中的变长指令,允许操作码后跟零字节或多字节的操作数(operand)。同一条知识,打通了从计算机底层到高级语言开发的通路。
作为一名汇编语言高手,Randall Hyde极为推崇汇编语言对程序员的助力。他在本书后记中建议:“有一种强迫自己在机器层次编写代码的方法就是使用汇编语言。”许多新生代的程序员对此建议或许不以为然,毕竟,如今使用汇编语言的机会可谓少之又少,它的重要性已经淡化。
遥想当年,在我的大学时代,汇编语言还是计算机专业最重要的一门编程语言课,当然,也是公认最难啃的硬骨头。当时还能熟练编写汇编程序的我,早已不记得这门语言的大部分语法了。我不知道,学习和使用汇编语言是否真的有助于写出卓越代码?我也不知道,我之所以没能写出什么卓越代码,是否与我汇编水平不高有关?但我深信,倘若具有高超的汇编开发能力,必然理解计算机底层运行的细节;倘若能很好地掌握汇编语言,学习任何一门高级语言,也就不在话下。
当软件系统规模如滚雪球一般变得越来越大时,我们已不可能像当初求伯君那样用汇编语言去写十几万行的WPS。虽然使用的语言不同,编程态度却应该一以贯之。然而,当我们写出动辄数百万行代码的应用系统时,是否真的思考过每条语句背后的代价?——问程序员,有多少人以写出卓越代码为己任?问代码,又有多少是深谙计算机底层原理的程序员写出来的?我们这个行业,因为竞争加剧的原因,程序员变得更加地浮躁。没有办法让自己静下来,沉心打磨基础;当开发技能成为一种快餐时,还有谁会力求编码的精益求精?又有多少人舍得花费宝贵的时间来深入理解计算机?然则,“九尺之台起于垒土”,没有扎实的基础,开发的能力究竟能提升多高,编程的生涯究竟能走多远,我深表怀疑。
真的非常钦佩Randall Hyde多年如一日孜孜于《编程卓越之道》系列的写作,使之成为计算机图书中不朽的经典。而作者并不满足已经取得的成就,推陈出新,出版了本书的第2版。第2版加入了新鲜的元素,却又不损经典质量的一分一毫。如果你刚刚踏上编程之旅,我强烈推荐你阅读本书。正所谓“磨刀不误砍柴工”,这些底层原理和底层细节,看似对你的开发没有直接帮助,但它真的可能会决定你未来的高度!是为推荐序。
——《解构领域驱动设计》作者 张逸
译者序
回顾21世纪初以来计算机产业的发展,移动互联网的普及一定是绕不开的话题。计算机的性能按照摩尔的预测每18个月就提升一倍,计算机中的集成电路体积反而越来越小。从个人计算机进入手机、嵌入式设备时代,终端变得无处不在。网络技术的发展让终端能力可以近乎无限地扩展。
随着计算机性能的提升和应用的扩展,软件的规模和复杂度也在呈指数级增长,开发工作面临的挑战也越来越大。不断出现的新的高级编程语言通过先进的语法特性和编程范式来简化软件开发者的工作。利用这些高级编程语言提供的抽象技术,编写代码这项活动越来越接近人类对问题的分析和描述,与计算机内部的运行机制渐行渐远。我们对卓越代码的追求似乎过于重视优雅地让人理解代码背后的意图,逐渐忽略了代码在计算机上的运行效率,所以才有了对安迪比尔定律的吐槽:新软件总是会耗尽新硬件提升的全部计算能力。笔者作为一名移动应用开发者,对于应用动辄成百上千兆的体积和一段时间后磕磕跘跘的体验,着实汗颜。
好在计算机的基本组成在这20年中并没有发生根本性的变化。由中央处理器、存储、输入/输出设备构成的冯·诺依曼体系结构目前仍然是计算机界的绝对主流。本书的第1版于21世纪初面世,文笔浅显易懂,代码示例详尽,同时避免了晦涩难懂的汇编语言,是一部介绍计算机体系结构的佳作。现在本书第2版的出版恰逢其时,提醒我们不要忘记卓越的代码一定也是高效的。在保留第1版深入浅出特点的同时,作者对过去这些年计算机体系结构的发展和新兴的设备进行了总结,对原有的内容进行了删减和增补。第2版中的示例代码也采用近些年涌现出来的高级编程语言进行了重写,让年轻的读者朋友读起来更加亲切。阅读本书了解代码背后的运行原理,进而在编写代码时做出正确的选择,未为晚矣。
本书打开了笔者的记忆,仿佛又回到了大学时代学习计算机组成原理、模拟和数字电路的时光。有了第1版翻译的珠玉在前,第2版的翻译工作笔者不敢怠慢。一些当时新鲜的概念现在已成了业界主流,因此在第2版的翻译中对部分译法进行了更新。笔者也期望像作者那样与时俱进,但百密终有一疏,翻译中出现的错误也请读者们海涵并斧正。
最后,感谢在背后支持笔者完成翻译工作的家人和朋友们!
——覃宇
评论
还没有评论。