12 September 2013

第二章 编译和链接

对于平常的应用程序开发,我们很少需要关注编译和链接的过程

使用本章的第一句话作为开头,深切的表达了我在学习这一章时候的心情。VS开发环境下甚至根本分不清楚编译和链接。gcc在使用的时候,照着别人的模版改改makefile,你真的理解每个编译选项是什么意思么?

编译和链接为什么引起我的兴趣去学呢?这还要从我过往的一次经历开始说起。朋友们,记得你第一次在VS下编译程序的时候的情景么?我至今都记得。 那是我在入职培训以后不久的时间,师父在我写完代码以后让我编译一下。我说:“什么编译?点什么地方?”。“F7啊!”

我从那个时候第一次真正意义上的开始写程序了。 ‘F7’对我来说是个比较神秘的东西。代码写完了F7再F5就能跑了?是怎么做的?我怎么不知道呢。

磕磕绊绊至今两年多了,比起其他学习计算机的人来说。在25岁第一次编译VC程序,实在是晚了一点。所以我老说我基础差,这确实是不是瞎说的。路实在是长了点儿,难了点。

题外话说完了,下面就开始说这一章我们学习到了什么吧。 这一章可以说是对编译和链接过程的概述。也是后几章的基础。学习了这一章以后可以解决一些概念上的问题例如

  • F7在按下去以后,VS编译器到底做了什么?区别生成静态库与动态库和exe的工程,F7分别又做了是那么?
  • 我的程序编译出来的结果是什么?是二进制?是汇编?还是??
  • 什么是链接?为什么我在一个cpp中写的代码可以被另一个cpp引用?为什么引用的时候一般要在头文件中暴漏自己的定义然后在引动的地方引用该头文件?
  • 宏是什么?编译器是对宏怎么处理的?我的代码怀疑是宏的问题,怎么定位?#ifdef用的太多了,怎么看真正的分支是哪个呢?
  • syntax error是什么?
  • gcc和VS对同样一段代码编译的过程有什么区别?要写一段在不同编译器都能正常编译链接和运行的程序应该注意些什么?
  • ….

坑就不多埋了。挖了不见得能填回来。下面总结一下我的收获吧。

  • 关于编译和链接的过程,我总结了例子,放在了github的另一个代码仓库上。

    例子中对于2.1中每一个步骤都有示范。完整的过程演示了从.cpp到.out的整个过程。事实上就是预处理,编译,汇编和链接。 其中让我印象比较深刻的时候预处理后的产物.i文件。对于gcc关于.i文件的描述也一直没有找到。

    值得一提的是,对于预编译的详细说明有另外一个例子,这个例子是在别处人家写的代码。因为例子实在是太好了,被我拿来存下来。

  • 对于语法分析过程中的上下文无关文法,查了编译原理一书才有了简单的认识。使用上下文无关文法可以描述任何一种编程语言,将token变成语法树的过程就是语法分析的过程。

  • 对于编译过程中的每个步骤,书中在P42 2.2的开头有一个图,这个图很好的描述了编译中每个过程的步骤的输入和输出,还把每个步骤的英文名字列出来了

截图示意

对于编译过程的整个过程,相信看完了这张图以后就有了比较全面的了解了。

  • 关于中间语言,IL也叫Intermediate Representation,前两天在工作的过程中还碰到了这个中间语言引申出来的问题。可以看另一个POST,这个帖子记录了这个问题。 另外补充一点,实际应用中对于windows可以使用dumpbin工具反汇编静态库来确定编译过程中是否使用了/GL的编译选项。

  • 最后关于链接,在这一章的最后部分介绍了连接器和静态链接的过程。关于链接的详细学习可以等到后面几个章节,这里我们只学习了简单的重定位的概念,在学习了elf文件格式以后,可以对链接的过程有个详细和具象的了解。