本文是《C 和指针》第 2 章的笔记。
1. 环境
在 ANSI C 的任何一种实现中,存在两种不同的环境。第一种是翻译环境,在这个环境里,源代码被转换为可执行的机器指令。第二种是执行环境,它用于实际执行代码。 标准明确说明,这两种环境不必位于同一台机器上。例如,交叉编译器就是在一台机器上运行,但它产生的可执行代码运行于不同类型的机器上。操作系统也是如此。
1.1. 翻译环境
翻译阶段由几个步骤组成:
- 组成一个程序的每个源文件通过编译器进行编译分别转换为目标代码。
- 各个目标代码文件由链接器链接在一起,形成一个单一完整的可执行程序。链接器同时也会引入标准 C 函数库中任何被该程序所用到的函数,而且它也可以搜索程序员个人的程序库,将其中需要使用的函数也链接到程序中。
Q:链接函数的实现时,只链接那些调用过的函数吗?还是所有声明过的函数的实现都会被链接?
?
其中编译过程本身也由几个阶段组成:
- 预处理阶段。在这个阶段中,预处理器在源代码上执行一些文本操作。例如,用实际值代替由 #define 指令定义的符号以及读入由 #include 指令包含的文件的内容。
- 对源代码进行解析,判断它的语句的意思。在这个阶段是产生绝大多数错误和警告信息的地方(运行阶段是另一个产生错误的阶段)。
1.2. 执行环境
程序的执行过程也需要经历几个阶段:
- 程序必须载入内存中。在宿主环境中(也就是具有操作系统的环境),这个任务由操作系统完成。在独立环境中,程序的载入必须由手工安排,也可能是通过把可执行代码置入只读内存(ROM)来完成。那些不是存储在堆栈中的尚未初始化的变量将在这个时候得到初始值。
- 程序开始执行。在宿主环境中,通常一个小型的启动程序和程序链接在一起,它负责处理一系列日常事务,接着调用 main 函数。在绝大多数机器里,程序将使用一个运行时堆栈,它用于存储函数的局部变量和返回地址。程序同时使用静态内存,存储于静态内存中的变量在程序的整个执行过程中将一直保留它们的值。
- 程序的终止。
?
2. 词法规则
词法规则就像是英语中的拼写规则,决定你在源程序中如何形成单独的字符片段,也就是标记。
2.1. 字符
标准并没有规定 C 环境必须使用哪种特定的字符集,但它规定了字符集必须包括英文所有的大写字母和小写字母、数字 0~9、空白字符、三字母词、转义字符,以及下面的这些符号: ( ) [ ] { } < > " ’ + - * / % = \ ! ^ ~ # , . ? : ; _ |
2.1.1 空白字符
空格、换行符、水平制表符、垂直制表符和格式反馈字符称作空白字符。因为它们被打印出来时,在页面上出现的是空白而不是各种记号。
2.1.2 三字母词
标准还定义了几个三字母词,三字母词就是三个字符的序列,合起来表示另一个字符。三字母词是以两个问号?开头再尾随一个字符的形式来表示。因为这种形式一般不会出现在其他表达行驶中,不致于引起误解。下面列举一些三字母词:
三字母词 | 代表的字符 | 三字母词 | 代表的字符 |
---|
??( | [ | ??) | ] | ??< | { | ??> | } | ??! | | | ??’ | ??= | # | ??/ | ~ | ??- | ~ | | |
为什么要用三字母词? 因为三字母词使 C 环境可以在某些缺少一些必须字符的字符集上实现。
2.1.3 转义字符
当你在编写某些 C 源代码时,你在一些上下文环境里想使用某个特定的字符,却坑能无法如愿,因为该字符在这个环境里有特别的意义。例如,双引号 " 用于定界字符串常量,你如何在一个字符串常量内部包含一个双引号呢?转义字符就是用于克服这个难题的。 转义字符由一个反斜杠 \ 加上一个或者多个其他字符组成,表示 \ 后面的字符是被转换了意义的。例如,? 在书写连续多个问号时使用,防止它们被解释为三字母词;" 用于表示一个字符串常量内部的双引号;\ddd,其中 ddd 表示 1~3 个八进制数字。这个转义符表示的字符就是给定的八进制数值所代表的字符。\xddd,和上例类似,只是八进制数换成了十六进制数。
2.2. 标识符
标识符就是变量、函数、类型等的名字。它们由大小写字母、数字和下划线组成,但不能以数字开头。C 是一种区分大小写的语言。标识符的长度没有限制,但标准允许编译器忽略第 31 个字符以后的字符。
|