程序员自我修养的九个问题
九个困扰了我很久的问题
学习程序员的自我修养的过程中,发现在书的开篇第一章第一节有9个问题,这九个问题从一个侧面归纳了学习这本书的动机和学习过后你将收获的内容。
他们分别是:
- 程序为什么要被编译器编译了之后才可以运行?
- 编译器在把C语言程序转换成可以执行的机器码的过程中做了什么?怎么做的?
- 最后编译出来的可执行文件里面是什么?除了机器码还有什么?他们是怎么存放的,怎么组织的?
- #include < stdio.h > 是什么意思?把stdio.h包含进来意味着什么?C语言库又是什么?它们是怎么实现的?
- 不同的编译器(MSVC GCC)和不同的硬件平台(X86 SPARC MIPS ARM),以及不同的操作系统(WINDOWS, LINUX, UNIX, Solaris),最终编译出来的结果一样么?为什么?
- …..
引自《程序员的自我修养》1.1节
这9个问题我现在还不全知道,或者说不知道。 这篇博客会把学习过程中现阶段我认为的的答案放在这里。随着学习的深入,会学到更多的知识。当我认为学习完了以后,再回来看这些问题的答案,会有惊喜吧?
问题1 为什么程序要被编译?
程序要被编译器编译过后才可以变为机器能够识别的机器码。这里说的程序应该是指的程序员编写的代码吧,编译还只是“真正意义的编译”(不是MSVC的F7),机器码也指得是计算机CPU能够识别的指令的2进制表示形式。
说代码为什么要被编译器编译这个问题,我理解就是因为计算机并不直接认识程序员所使用的计算机编程语言(如C C++ JAVA …)。程序员也并不容易直接写出计算机真正运行的指令。因此,计算机科学家们设计出编程语言,目的是为了让程序员可以使用类似自然语言的规则和表达形式描述计算机程序的逻辑,从而减轻工作。因此程序员的一切目的都是围绕着如何让计算机将你所写的程序(或者暂时叫代码吧)识别成为计算机可以运行的计算机指令而展开的。因此,写代码虽然重要但只是手段。也只是开始。代码写好了只是编写计算机程序的第一步,后面还有编译,链接,装载等等一系列的工作。当然,大部分复杂可以重复完成的工作被我们用到的各种开发环境中编译和链接的工具完成了,但是过程的重要性不言而喻。
问题2 编译器在把C语言程序转换成可以执行的机器码的过程中做了什么?怎么做的?
真正到生成机器码为止,计算机工具完成的整个过程包含了预编译,编译等步骤。其中编译过程有详细分解为词法分析,语法分析,语义分析等等。
预编译过程中,预编译器去掉C语言源代码中的宏定义字符,替换为宏所代表的值。并展开头文件,为C源代码编译准备出一份完整的可供编译的单元(.i)。
然后就是编译器分析代码中的关键字,将它们按照逻辑组合在一起。解析代码的语法,分析代码的语义。将C代码编译生成为汇编代码。
生成了汇编代码以后仍然不算结束,因为这个时候汇编代码存放的仍然是以汇编语言为表达形式的汇编语句。这个时候,汇编器将汇编它并最终生成机器代码。
问题3 最后编译出来的可执行文件里面是什么?
可执行文件对于WINDOWS来说是PE,对于Linux来说是ELF。他们里面又包含什么呢?
包含文件头,段头,各个段的内容。他们按照段头描述的位置和大小在可执行文件中安装顺序排放。
问题4 #include < stdio.h > 是什么意思?C库是什么意思?
stdio.h 头文件对C语言来说定义了很多C语言函数诸如printf sprintf 和常用的数据结构诸如unsigned int等等的定义。
C库又是什么?是为了让编译器找到C语言定义的一些函数等的符号的定义而实现的库。所有基于C语言实现的程序在链接的过程中必将包含C库。
go on