C 参考手册
- C 语言
- C 的历史
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 静态断言
- 字符常量
- 函数声明
- 函数定义
- 转义序列
- 翻译阶段
- 标识符
- 作用域
- 生存期
- 查找与命名空间
- ASCII 码表
- 类型
- 遵从性
- 算术类型
- restrict 类型限定符
- 类型
- 对象与对齐
- 主函数
- 未定义行为
- 内存模型
- if 语句
- switch 语句
- for 循环
- while 循环
- do-while 循环
- continue语句
- break 语句
- goto语句
- return 语句
- 值类别
- 求值顺序
- 整数常量
- 浮点常量
- 字符串字面量
- 复合字面量
- 常量表达式
- 隐式转换
- 成员访问运算符
- 逻辑运算符
- 比较运算符
- 算术运算符
- 赋值运算符
- 自增/自减运算符
- 其他运算符
- sizeof 运算符
- _Alignof 运算符
- 转型运算符
- C 运算符优先级
- 泛型选择
- 标量初始化
- 数组初始化
- 结构体与联合体初始化
- 指针声明
- 数组声明
- 枚举
- 存储类指定符
- const 类型限定符
- volatile 类型限定符
- 结构体声明
- 联合体声明
- 位域
- _Alignas
- typedef 声明
- 原子类型
- 外部及试探性定义
- inline 函数指定符
- _Noreturn 函数指定符
- 变长参数
- 内联汇编
- 可分析性
- 替用运算符及记号
- C 关键词
- 预处理器
- C 标准库头文件
- 类型支持
- 程序支持工具
- 变参数函数
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 算法
- 数值
- 文件输入/输出
- 本地化支持
- 原子操作库
- 线程支持库
- 实验性 C 标准库
- 有用的资源
- 符号索引
- 注释
翻译阶段
编译器如同下列阶段以此准确顺序发生一般处理 C 源文件。实际实现可以组合,或以不同方式处理这些动作,只要行为相同。
阶段 1
1) 以实现定义方式,映射源文件(通常是以某种多字节,例如 UTF-8 编码的文本文件)的单独字节,为源字符集的字符。特别是以换行字符替换依赖 OS 的行尾指示符。
- 源字符集是包含作为单字节子集的基本源字符集的多字节字符集,后者由以下 96 个字符组成:
a) 5 个空白字符(空格、水平制表、垂直制表、换页、换行)
b) 10 个数字字符,从 '0' 到 '9'
c) 52 个字母,从 'A' 到 'Z' 以及从 'a' 到 'z'
d) 29 个标点字符: _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
2) 以对应的单字节表示替换三标符。
阶段 2
1) 凡在反斜杠出现于行尾(立即为换行符所后随)时,删除反斜杠和换行符,把二个物理源码行组合成一个逻辑源码行。这是单趟操作:以二个反斜杠结束,后随一个空行的行不会把三行组合为一。
2) 若此步骤后,非空源文件不以换行符结束(无论是原本就无换行,还是以反斜杠结束),则行为未定义。
阶段 3
1) 将源文件分解为注释、空白字符(空格、水平制表、换行、垂直制表、换页)序列和下列预处理记号:
a) 头文件名: <stdio.h> 或 "myfile.h"
b) 标识符
e) 运算符与标点,例如 + 、 <<= 、 <% 或 ## 。
f) 不属于任何其他类别的单独非空白字符
2) 以一个空格字符替换每段注释
3) 保持换行符。是否可将非换行的空白符序列缩减成单个空格字符是实现定义的。
若已经分析输入为到给定字符为止的预处理记号,则通常将能构成一个预处理记号的最长字符序列处理成下个预处理记号,即这会导致后继分析失败。这常被称为最大吞噬 (maximal munch) 。
int foo = 1; int bar = 0xE+foo; // 错误:非法的预处理数字 0xE+foo int baz = 0xE + foo; // OK int quux = bar+++++baz; // 错误: bar++ ++ +baz ,而非 bar++ + ++baz 。
最大吞噬规则的单独例外是:
- 头文件名预处理记号仅在
#include
指令中和#pragma
指令中的实现定义位置形成。
#define MACRO_1 1 #define MACRO_2 2 #define MACRO_3 3 #define MACRO_EXPR (MACRO_1 <MACRO_2> MACRO_3) // OK : <MACRO_2> 不是头文件名
阶段 4
1) 执行预处理器。
2) #include 指令所引入的每个文件都经历阶段 1 到 4 ,递归执行。
3) 此阶段结束时,从源码移除所有预处理器指令。
阶段 5
1) 将字符常量及字符串字面量中的所有字符及转义序列从源字符集转换成执行字符集(可为如 UTF-8 的多字节字符集,只要来自阶段 1 中所列的基本源字符集的所有 96 个字符拥有单字节表示)。若转义序列所指定的字符不是执行字符集的成员,则结果是实现定义的,但保证不是空(宽)字符。
注意:某些实现中,能以命令行选项控制此阶段所进行的转换: gcc 和 clang 用 -finput-charset 指定源字符集的编码,用 -fexec-charset 和 -fwide-exec-charset 指定无编码前缀的 (C11 起)字符串字面量和字符常量中的执行字符集的编码。
阶段 6
连接相邻的字符串字面量。
阶段 7
发生编译:按照语法和语义分析记号,并将它们翻译成翻译单元。
阶段 8
发生链接:将翻译单元和满足外部引用所需的库组件到汇集成程序映像,它含有在其执行环境(操作系统)中执行所需的信息。
引用
- C11 standard (ISO/IEC 9899:2011):
- 5.1.1.2 Translation phases (p: 10-11)
- 5.2.1 Character sets (p: 22-24)
- 6.4 Lexical elements (p: 57-75)
- C99 standard (ISO/IEC 9899:1999):
- 5.1.1.2 Translation phases (p: 9-10)
- 5.2.1 Character sets (p: 17-19)
- 6.4 Lexical elements (p: 49-66)
- C89/C90 standard (ISO/IEC 9899:1990):
- 2.1.1.2 Translation phases
- 2.2.1 Character sets
- 3.1 Lexical elements