对于像hello.c这样简单的程序,我们能指望编译系统产生正确高效的机器码。然而,有几个重要原因使得程序员需要去理解编译系统是如何工作的:
优化程序执行效率。现代编译器都是非常聪明的工具,它们通常都能产生好的机器码。作为程序员,为了写出高效的代码,我们不需要去知道编译器的内部工作机制。然后,为了在我们的C程序中做出好的编码决定,我们确实需要对机器码和编译器如何把不同的C语句翻译成机器码有基本的了解。例如,switch语句是否总是比一系列if-else语句更高效?一个函数调用需要多少开销?while循环是不是比for循环更高效?指针引用是不是比数组索引更高效?为什么我们将求和结果放在本地变量里比放在通过引用传进来的参数中会使循环跑得快很多呢?我们怎样通过简单重新排列算术表达式中的元括号使函数跑得更快?
在第三章,我们将介绍两个相关的机器语言:IA32,32位机器码在运行Linux,Windows和最近的Macintosh操作系统的机器上无处不在,x86-64,64位扩张在最近的微处理器上能被发现。我们描述编译器怎么样把不同C语言结构翻译成这些语言。在第五章,你将会学到通过对你的C代码做简单的变形——这种形式帮助编译器更好的做它的工作——来调整你的C程序的执行效率。在第六章,你将会学习内存系统的层次特性,编译器如何把数组存储在内存中,以及你的C程序如何利用这些知识来让自己跑得更快。
理解链接时错误。在我们的经验里,一些最令人困惑的错误都与链接器操作相关,尤其是当你尝试构建大型软件系统时。例如,当连接器报告它不能解析一个引用时意味着什么?静态变量和全局变量的的区别是什么?如果你在不同的C文件中定义两个相同名字的全局变量会发生什么?静态库和动态库的区别是什么?为什么我们在命令行列举库的顺序是重要的?最吓人的是,为什么链接器相关的错误在运行时才出现?你将在第七章得到这些问题的答案。
避免安全漏洞。许多年来,缓存溢出缺陷已经引起了网络和互联网服务器中的大部分安全漏洞。这些缺陷之所以存在,是因为几乎没有程序员理解去仔细限制从不可信源接收到的数据的数量和形式的必要性。学习安全编程的第一步是数据和控制信息被存储在程序栈的方式所导致的结果。在第三章,我们讲解栈的问题和缓存溢出缺陷作为我们汇编语言学习的一部分。我们也会学到一些方法,这些方法能被程序员,编译器,操作系统用来减少被攻击的威胁。