基本信息
- 原书名:Advanced C and C++ Compiling

编辑推荐
学习如何编写C/C++代码仅仅是个开始。如果你希望从事系统底层开发,或想深入理解操作系统、编译器及它们之间内在的关联,成为“编程专家”,那么就必须对编译器生成的二进制文件(目标文件、静态库、动态库和可执行文件)的作用和结构进行充分的了解。开源已经在许多方面从根本上改变了软件的原有面貌,越来越多的系统开始采用或集成开源代码,因此对每位开发人员来说,学习和理解这些底层技术也变得十分重要。 米兰·斯特瓦诺维奇编著的这本《高级C\C++编译技术》深入浅出地讲解了构建过程(编译、链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架构设计方法,以及系统开发过程中疑难问题的解决方案。同时,本书也是一本C/C++二进制文件方面的软件工程指南,涵盖中级和专家程序员所需的各方面内容和信息。
内容简介
计算机书籍
米兰·斯特瓦诺维奇编著的这本《高级C\C 编译技术》从多个角度全面、系统地讲解多任务操作系统中编译、链接、装载与库的内幕和技术细节,为深入理解和掌握系统底层技术提供详实参考和实践指南。与纯粹讲解理论与技术细节的书不同。本书一方面对基本的理论进行了阐述,另一方面则聚焦于C/C 使用静态库和动态库的一些注意事项,并举例说明如何解决实际的链接与装载问题。此外,本书尽量使用通俗易懂的语言来阐述这些知识,并补充了大量示例,避免让读者整天纠结于枯燥的理论。
本书共14章,其中第1章至第4章对多任务操作系统、程序生命周期以及代码重用等重要概念进行介绍,为后续内容做铺垫;第5章介绍静态库的使用方法及其设计技巧;第6章至第11章介绍动态库的相关概念,包括不同平台中动态库的技术细节,比如库文件定位、引用解析与符号处理等,以及一些动态库设计的基本方法与原则和不同平台下应当注意的设计细节;第12章至第14章主要给出一些实践方面的总结,便于读者快速查找相关的概念,而且还总结了一些特定平台的二进制文件分析工具。
作译者
目录
前言
第1章 多任务操作系统基础 1
1.1 一些有用的抽象概念 1
1.2 存储器层次结构与缓存策略 2
1.3 虚拟内存 3
1.4 虚拟地址 5
1.5 进程的内存划分方案 5
1.6 二进制文件、编译器、链接器与装载器的作用 6
1.7 小结 7
第2章 程序生命周期阶段基础 8
2.1 基本假设 8
2.2 编写代码 9
2.3 编译阶段 11
2.3.1 基本概念 11
2.3.2 相关概念 11
2.3.3 编译的各个阶段 12
2.3.4 目标文件属性 23
2.3.5 编译过程的局限性 24
2.4 链接 26
译者序
虽说计算机软件编程领域的技术发展日新月异,但我始终坚信所有程序开发技术演进都万变不离其宗,其本质自始至终从未发生过改变。就编程语言来说,无论抽象到何种层次,使用何种风格,最终都会回归到本质——机器代码。而在我们常用的高级语言中,最贴近机器及操作系统底层的恐怕就是C语言了。
从一定程度上来讲,C语言堪称一门革命性的语言,它完美平衡了语言中机器相关与机器无关的部分,使得我们可以用机器无关的方式来处理程序逻辑,但必要时又可以直接控制底层硬件,C语言被广泛运用在操作系统开发中正是这一点的绝佳例证。同时,C语言的核心是非常简单的,一切细节都暴露在程序员面前,不会因为某种语法构造而导致隐藏的性能消耗。这使得C语言成为程序员在追求程序效率时的一个绝佳选择。C语言为了保证核心语言的简单(包括标准库的简单)与高效,没有将很多必要的现代语言特性融入标准中,比如C语言自身没有提供任何反射机制。这是一把双刃剑,也就是说,如果想在C语言中实现任何动态语言特性,必须使用和系统相关的特性,尤其是在动态库、共享库、插件等概念日益重要的今天,这给C程序员带来很多麻烦。虽说现在各种主流操作系统中都很好地支持动态库或共享库,也提供了相应接口,但是不同平台中的概念都会有细微差别,而且在具体技术细节上也会不同,这使得程序员在处理跨平台问题时会遇到很多问题。
C++的出现则让这一切变得更加错综复杂。
C++是一门多范式语言,在提供了面向对象和泛型编程的同时,为了保证效率,依然坚持不加入任何动态特性,或者提供某些非常有局限性的动态特性(比如RTTI),为了实现多态则采用了虚函数表这种折中方法。除了C++语法给编译器实现带来的复杂性之外,受到更大挑战的则是C++的链接器和装载器实现。符号名称修饰、全局对象管理、模板支持等各种特性使得链接器和装载器为了支持C++需要付出更多的努力。
同时,C++程序员处理动态库或共享库时也同样需要更加细心、耐心。很多时候,我们一不留意就会被各种链接器或者装载器错误提示搅得心如乱麻,而查遍代码也找不出问题所在。编译器优化的不确定因素更加剧了这种情况。另一方面,现在的计算机教育中,包括程序设计语言课程、编译原理课程、操作系统课程,但并没有一门关于链接和装载的课程,链接和装载往往只是在这些课程中一带而过。或许这是由于链接和装载是非常纯粹的技术性话题,并不像其他课程那样需要传授各种理论,但这导致很多人对链接和装载一知半解,根本没有系统认识。
这些因素叠加起来的后果是,许多初级C/C++程序员遇到链接和装载问题时感到束手无策,根本不知问题出在何处。如果说Windows平台下的程序员得益于Visual Studio这种强大的IDE,在处理动态链接库时颇为方便,那么对Linux程序员来说,这便是一场噩梦。他们需要手动集成各种第三方库,有的是开源的,有的是非开源的,有的只提供了源代码,有的只提供了二进制文件,有的文档详尽,有的文档匮乏……他们永远不知道会遇到什么情况。即便是使用IDE的初级程序员,有时也不得不手动解决各种链接问题,但往往由于他们满足于IDE的良好封装,而忽略其底层编译链接的细节,因而在处理这些问题时更加盲目。在这种情况下,对链接和装载(其实也包括C/C++语言本身以及编译过程)认识并不深刻的那些程序员在日常工作中很容易在处理这类问题时“触礁”。由于缺乏系统认知,他们需要在一次又一次的失败实践中总结,这会走许多弯路。
由于我本人在大规模分布式实时系统研发方面具有一定的经验,因此许多人在C/C++开发中遇到问题时会咨询我,其中一部分问题出在C++语法上,而更多的问题则出在链接和装载上。本书在这些方面进行了翔实总结和讨论。与纯粹讲解理论与技术细节的书不同,本书一方面阐述基本的理论,另一方面则聚焦于C/C++使用静态库和动态库的一些注意事项,并举例说明如何解决实际的链接与装载问题。此外,本书尽量使用通俗易懂的语言来阐述这些知识,并补充了大量示例,避免让读者纠结枯燥的理论。
相信你会和我一样,在本书中发掘出大量有价值的资料,以便在日后的工作中游刃有余,并在处理C/C++相关问题的时候厘清思路,排除障碍。
在翻译本书的过程中,我不仅查阅了大量国内外的相关资料,还与英文原著作者进行了深入沟通,力求做到专业词汇准确权威,书本内容正确,意译部分既无偏差又不失原著
意境。在翻译过程中得到了很多人的帮助,这里一一感谢。感谢我的家人,他们是我学习和前进的动力。感谢鲁昌华教授,他在我的成长道路上给予了很大的支持和鼓励。感谢我在思科系统(中国)研发的同事们,他们在我的学习、工作中给予了很大帮助。感谢我的好友金柳颀,感谢他在我翻译本书过程中与我的通力合作。还要感谢机械工业出版社的陈佳媛编辑对我的信任。
现在我怀着期盼和忐忑的心情将这本译著呈献给大家,我渴望得到你的认可,更渴望和你成为朋友,如果你有任何问题或建议,请与我联系(samblg@me.com),让我们一起探讨、共同进步。
卢誉声
前言
说到烹饪和编程的比较,我的脑海中首先浮现出来的是烹饪专家和程序员的工作目标非常相似:都是为了满足特定对象的需求。对一个厨师来说,他的服务对象是食客,他需要使用大量的食材,一方面满足人们的温饱与营养需求,另一方面则要让人们享受到美食带来的快乐。而对一个程序员来说,其服务对象是微处理器,程序员使用大量不同的程序来为其提供代码,不仅要让微处理器产生有意义的动作,还需要以最优的形式将代码交付给微处
理器。
虽说这种对比看起来有些牵强而且过于简单,但我们会在本书中列出一些更加合适和更具说服力的对比。
介绍烹饪方法的食谱的数量繁多。几乎所有的流行杂志都会开设专栏来介绍形形色色的美食和烹饪方法,无论是快餐式的食谱还是精致复杂的食谱、注重食材的食谱还是注重搭配稀有食材的食谱,你都能够找到。
但如果你希望自己成为烹饪大师,就会发现很难找到可供参考的资料,比如食品行业经营(批量生产、饭店或餐饮企业的经营)、食品生产的供需管理、选料和食材保鲜方面的指南或资料。很显然,这就是业余烹饪爱好者和专业食品企业之间的区别。
这种情况与程序设计其实非常相似。
我们可以轻松地从成千上万的书籍、杂志、文章、网络论坛和博客中搜集到编程语言方面的各类信息,无论是入门教程,还是“谷歌编程面试指南”这样的技巧。
但是,这类主题所涵盖的内容只能满足成为专业软件工程师一半的要求。我们不能一直沉浸在因程序实际执行(且执行正确)而带来的喜悦当中,而需要着重考虑接下来的问题:如何组织代码结构以便将来修改、如何从功能模块中提取出可重用代码,以及如何让程序能够适应不同的运行环境(无论是不同的人类语言和字符,还是在不同的操作系统环境中
运行)。
相较于其他编程主题来说,人们很少讨论这类问题。时至今日,这类问题变成了只有计算机科学专业人士(绝大多数软件架构师和构建工程师)和大学课堂上讲解编译器、链接器设计时,才会了解的“黑科技”。
由于Linux市场份额增加,而且越来越多的人都将Linux作为其编程环境,这促使开发人员开始关注Linux编程的相关问题。与在一些封装良好的平台(在Windows和Mac平台上利用IDE和SDK将程序员从一些特定的编程细节问题中解放出来)开发软件的开发人员不同,Linux开发人员在日常工作中需要将来自不同项目且编码风格迥异的代码组合起来,这需要开发人员充分理解编译器、链接器的内部工作机制和程序装载机制,以及不同库的设计细节和使用方法。
本书将许多零碎的知识点进行汇总,并讨论其中那些有价值的内容,这些内容则通过一系列精心设计的简单示例进行验证。需要注意的是,本书的作者并非计算机科学科班出身。20世纪90年代末至今的数字革命中,作者作为电气工程师供职于硅谷的一家多媒体行业高新技术企业,并因此掌握了相关领域的知识。希望本书的主题和内容能够让更多读者受益。
读者对象
作为一名软件设计实践顾问(虽然很忙,但我还是非常自豪的),我经常会与不同专业背景和资历的人群沟通。我在工作周中需要经常在不同的办公环境中工作,因此接触了许多开发人员(绝大多数来自硅谷),这也让我更加了解了本书的受众群体。其中包括以下几类人群。
第一类受众群体是来自不同工程领域的C/C++开发人员(电气工程、机械、机器人技术和系统控制、航天、物理和化学等领域),这类人需要在日常工作中通过编程来解决问题。对缺乏正规计算机科学课程和理论教学的人来说,本书所提供的资料弥足珍贵。
第二类受众群体是具有计算机科学教育背景的初级程序员。本书能够帮助大家将主修课程中学到的知识具体化,并注重实践。将第12章~第14章的内容作为手册查阅,对资深工程师而言,也会有所受益。
第三类受众群体是操作系统集成和定制的爱好者。理解二进制文件及其内部工作机制将有助于在解决问题的过程中扫除障碍。
关于本书
我最初并没有计划去写这么一本书,甚至都没有打算写一本计算机科学领域的书。(我有可能会去编写信号处理或程序设计艺术方面的书,但编写计算机科学方面的书?不……)