2.2 运行时刻环境[Run Time Environment]
2.2.1 前言
LZ之前有两篇帖子, 一篇是《程序员的基本概念》, 一篇是《C语言函数调用的汇编级解释》,这两篇帖子都是理解C语言程序如何运行的一些基础, 都发在本贴吧之中, 找精品贴应该能找到. LZ现在简单地阐述一下.
计算机语言就是人类和计算机沟通的方式(The way to communicate with computer).
首先我们把语言分类. 目前的语言分类一般从两个角度去分, 一是该语言所遵从的范式, 二是该语言的解释/执行方式.
从语言的范式(Paradigm)上来说, 语言一般分为声明式的(Declarative Language), 函数式的(Functional Language)和命令式的(Imperative Language).
声明式的语言如Prolog(Programming in Logic). 只需要给出一个问题的"正确描述", 它就自动找到答案.
函数式的语言如erlang, haskell, clojure, 某种程度上说, 它们的主要宗派是Lisp[List Processing]. Lisp不太像是一门语言, 它没有"官方"的说法, 各种各样的实现都是Lisp.
命令式的语言. C/C++, Java, C#, Objective C等等等等. 所谓命令式, 在于"指定计算机指令执行的过程, 计算机就照此执行"的意思. C++是集多重范式于一身的语言, 命令式范式和纯函数式范式, 乱七八糟的各种范式只要程序员想要C++几乎都提供支持, 以至于LZ常常对C++的复杂性感到不可思议[换句话说C++是怪胎, 但偶尔解决某些问题时又特方便好用]. LZ最终在语言上的选择是回归简单, 由于LZ是C语言出身, 所以最终LZ手上的语言是C语言. 除C语言之外, Shell script, Makefile, Lisp scheme, sed awk LZ都略懂. C++/Java也是略懂[LZ有段时间工作时常看大段的Java(单个文件一不小心就上万行, 几十个文件的那种--当然LZ才不会傻到想去看完它们)].
语言的解释/执行方式分类某种程度上使语言有了一些"本质上的"差别.
从这个角度, 语言分为"编译, 然后执行的", 和"不需要编译, 由解释器解释执行的"语言.Java则是怪胎, 它是"编译, 然后解释执行"的混合物, 好听的说法是混血, 不好听的说法就是杂(^^)种. 另外这种差别也使得, "是否能够在运行期维护类型系统?" -- 这种差别导致了静态类型和动态类型的区分.
============> 分割线 <============
LZ现在废话好多... 难道是因为LZ退出开发生涯并从事了讲师这个职业的原因吗...
============> 分割线 <============
OK... 正题开始...
C语言是静态弱类型的编译型语言.
静态类型是说它的类型系统只在编译期存在. 弱类型是说它允许不一定(运行期)安全的隐式类型转换. 编译型语言是说它必须要先编译然后执行.
静态类型限制程序员太随意自由; 弱类型给予程序员自由; 编译型就是说它写出来的程序运行时非常快, 非常非常快, 目前没有比它更快的高级语言, C语言就是高级一点的汇编而已.而且, 如果汇编代码写得挫, 未必就比C语言快, 因为编译器的优化偶尔是很恐怖的. 汇编码的优势在于有时有C语言有无法操作到的东西, 比如CPU内部寄存器, 这一点一般通过C语言内嵌汇编码来解决.
============> 分割线 <============
既然是编译型语言, 那么自然需要编译了.
目前来说, 大多C语言实现, 都将编译C语言分为4步.
第一步是预处理. 就是处理掉宏, 还有包含头文件之类的事情.
第二步是编译, 这是真正的编译, 这一步把C语言代码转化为对应平台的汇编码. 这一步是由C语言编译器(也就是通常说的C语言实现)来做的.
第三步是汇编, 这一步将汇编代码转换为目标文件. 目标文件已经不是纯文本文件了; 目标文件是二进制文件. 在目标文件中, 所有的代码段以地址0开始, 所有的数据段以地址0开始.
第四步是链接, 这一步将各个目标文件中的代码段汇总, 将各个目标文件中的数据段汇总, 然后给予汇总的代码段和数据段以运行时起始地址, 并解决和动态库的符号链接问题, 如果是静态库则当作一般目标文件一样处理.
以上这四步通常统称编译期(Compiler Time). 因为这是一个C语言程序从源代码构建出来开始出生的过程, 因此通常就称之为编译或者构建了, 因为其中最主要的步骤是第二步也即编译[实际上每步都很重要].
============> 分割线 <============
在上面的4步需要用到的工具, 即, 预处理器, 编译器, 汇编器, 链接器, 统称为编译工具链[Compile Chain]. Linux系统上的GCC, 即GNU Compiler Collection, 亦可称之为GNU Compile Chain. 不过, 链接器因为目标文件/二进制文件处理的原因, 在其代码维护中被放到binutil[ Binary Utilities , 二进制工具]一类了.
其实...要说吧, 是否理解这四步中的工具到底做了什么, 还有一些二进制工具该怎么用, 其细节如何, 通常已经是区分一个C程序员是否经验老到的标志了. 一个经验老到的C程序员, 清楚他所写下每一个字节. 话题太长, 不便展开. 这些东西虽然基础, 但对C程序员来说实际上极为重要(通常它们也是C程序员理解计算机系统的极其重要的途径). 不过毕竟只是程序员的基本功底, 东西要称得上"计算机科学", 怎么都得和可计算理论和各种算法沾边, LZ本文描述的只是基础, 而不是"计算机科学".

