CSAPP中文版原书第三版挑毛病
这篇书评可能有关键情节透露
第一次写这个评论是在2018年,我曾经断断续续地翻过这本书很多次,却始终没有完整地从头到尾读完。最近一个月,因为要找工作。所以从头到尾读了一遍,顺便复习一下基础知识。直到今天(2022/1/5)我终于把这本书读完了。4年时间真的好快,天知道我这四年都经历了什么。这四年里我因为对心理学着迷,考上了北师大的应用心理硕士,所以读了很多心理学的教材。我原本以为心理学领域的外国教材的中译本的翻译质量会好一些,可是我错了。如果跟《心理学与生活》、《社会心理学》这两本书比起来,CSAPP这本书的翻译质量简直好到爆。虽然有少数词句比较生涩,但是绝大部分的翻译还是可以的。看这样的中文版至少比直接看英文原版的速度快很多。如果英文好,或者时间充裕,可以直接去啃英文版。否则,我还是建议大家看这本中文版,同时手里要有英文原版,当遇到中文版中看不懂的地方,去翻一下英文版即可。这样读书的效率会比较高。另外,所有电子信息类的国外教材,我都推荐用这种方法去读(尤其对于那些在校的本科生而言)。
另外,由于最近两年读的外文教材的中译本比较多,所以我现在对中文翻译的容忍度提高了。有一些以前看来不能忍的翻译,现在竟然也能够理解了,所以这次添加的勘误也不多。另外,我自己搞了个pdf,书上有翻译的不好但是不能算错的地方,我就自己重新翻译了一下,把原版覆盖了。里边还有我一些杂七杂八的读书笔记,如果谁想要可以私信我,只供学习交流,不能转发。
以下是原来的评论,我在其中添加了近期的勘误。
------------------------------------------------------
这本书是很好的书,我认为只要是工作中涉及编程工作的同学都要必须要熟读的书。我之前看过第二版,没看完。后来发现有第三版了,我就从网上找来一本二手的,重新从头认真读,现在读完了前5章,简单说一下。 跟之前的中文版第二版相比,这本第三版的印刷质量和纸张都有很大进步,但是翻译水平和排版的水平确有很多毛病可以挑,当然我并非因为毛病多就否认这本书的价值。因为这本书的无可替代性和权威性,这是一本无法绕过的书,所以没得选。正因为这是必读书,所以这本原书第三版的中文版本中的一些错误让我如鲠在喉,不吐不快。 我在读书的时候遇到翻译不通顺或者排版不好的地方都要特别做标注,用自己的话再翻译一遍。可能这也是一个学习的过程,第一遍读此书的时候,会很慢,因为很多地方的语言很生涩,有很多处翻译不通顺的句子可以明显看出是先用机器翻译然后人工润色的,可能译者并没有以读者身份深入地读原著,这是让我很不满的地方。对于一本经典著作,译者居然可以不用心去体会,居然可以用那种不通顺翻译敷衍,这是很不负责任的治学态度。翻译讲究信、达、雅。对于一本计算机科学领域的经典教材,我可以不要求你做到“雅”,但起码“信”和“达”必须要做到,可惜,本书的翻译水准并不能达标。也可能这是原书第三版的第一版中文版,所以错误比较多。以下分类列举几处错误: 一、翻译不当、翻译错误: 359页,倒数第13行,段尾的一句“那么,这些程序就没有一个能够完全得到多个功能单元带来的好处了。” 这句话很明显译者没有好好推敲,如果不反复读上下文,很难懂这种英语式的含有很多定语的句子到底在强调什么。这句话的前文说了,现代的新型处理器的功能单元的数量和性能都有所增加,而这些功能单元既能进行浮点操作也能进行整数操作。比如,假设新增的功能单元只能进行整数操作的话,那么当运行浮点操作的程序时,多增加的那些个功能单元不就然并卵了吗。如果体会到这个意思,那么才能理解到这句话所要表达的意思。所以只要稍微改一下,就能很好的表达原文的意思了。比如,改成“那么,这些程序就无法享受到完全得到多个功能单元带来的好处了”。 283页,第一段中有句话“从上到下写着一组操作(再次称作I1,I2,I3)”。这句话译的很不好,所以我认为译者可能都没有好好读过此书。应该译为“从上到下写着一组连续执行的3条指令I1,I2,I3。” 275页,第3段,有一句话是“即使所有的状态更新实际上同时发生,……”。这句话有歧义,这里的“即”和“使”要分开读,而不是“即使”的意思。所以要么翻译的时候在“即”后边加一个逗号,“即,使所有的状态更新实际上同时发生”;要么翻译成“即让所有的状态更新实际上同时发生”.
268页,图4-20,pop rA的访存一行,valE改为valM。
289页, 倒数第3行,“流水线寄存器在该图中用黑色方框表示,……,用白色方框表示。”这句话改成:“流水线寄存器在该图中用蓝色的长条方框表示,其中包含的白色方框代表该寄存器的不同字段。”WTF,难道翻译这段话的人是个蓝黑色盲?还是他不认识blue这个单词?我查了原书英文版没有错误。
302页,前两行。恕在下眼拙,在读原书英文版之前,我实在是读不通。如果有跟我一样笨的人,请看我的翻译:程序prog2~prog4中所描述的转发技术,转发的都是同一个值valE,这个值是由ALU产生并且其最终目的是寄存器的写端口W_valE。其实也可以转发从内存中读出的、目标为寄存器写端口M的值。
174页,3.7.6第一段的第二行,“因此多个未完成调用的局部变量不会相互影响”,改为“因此不同过程的局部变量不会相互影响。” 二、文本错误,编辑错误: 276页,最后一段中“(点1)”应该是“①”;下文还有个“(点2)”,应该是“②”。上图4-25中的“程序计数器”全都写成“程序计算器”了。很不严谨,这里有编辑的错误,也有译者的错误。 247页,最后一段,第一句话。“有些指令需要一个附加的4字节常数字。”这里写错了,应该是8字节常数字。
420页,6.2.3 局部性小结第4行末尾,应该是步长为1,(不是字母l) 三、排版不当: 349页,第一段。原文是这样的: ……特别地,使用声明: #define IDENT 0 #define OP + 它对向量的元素求和。使用声明: #define IDENT 1 #define OP * 它计算的是向量元素的乘积。 如果改成以下这样,看起来会舒服一些: ……特别地,我们用如下声明表示对向量元素的求和: #define IDENT 0 #define OP + 用如下声明表示对向量元素的乘积: #define IDENT 1 #define OP * 四、原书错误 不属于翻译错误,可能原书就写错了。
114页, 第15行, 应该是256TB,2的48次方是256T。其实上文110页的倒数第9行,已经出现过一次了。
229页,3.14题的D,<=应改为!=。
238页, 3.43。 &up->t1.w的代码第一行应该是 addq $11, %rdi,漏了11。
&up->t2.a的代码应该是 movq %rid, (%rsi),%rsi应该加括号。因为既然类型是int*,那么此时函数第二个参数就是 int ** dest,因为函数体中的赋值语句是个间接引用*dest = xxx,所以这里一定是(%rsi)。当然如果按照书上的答案,那么类型应该是int,而不是int*。所以要么是类型的答案错了,要么是代码的答案错了。
练习题5.5的答案是正确的,但是解释有误。 每次迭代需要两个乘法,一个是xpwr=x*xpwr,另一个是result=a[n]*xpwr。所以一个浮点数乘法需要5个周期的话,一次迭代应该需要2*5个周期。但是我们的参考机有2个浮点数乘的功能单元,而且这两个乘法是相互独立的。所以只需要一个浮点数乘法的5个周期就OK。
700页,图12-17,右侧汇编代码从第4行到第8行很奇怪。可以改成下边这样。
movl $0, %edx
.L3:
movq cnt(%rip), %rdx // Li: 从内存加载cnt到CPU寄存器
addq $1, %rdx // Ui: 更新寄存器的值
movq %rdx, cnt(%rip) // Si: 将更新后的寄存器值存入cnt的内存位置
其实这一段汇编代码能不能看懂不重要,只要能理解Li、Ui、Si这三步操作就可以。