【C语言】程序环境与预处理
目录
程序的翻译环境和执行环境
粗谈编译+链接
翻译环境
编译的几个阶段及链接
运行环境
预处理详解
预定义符号
#define
#define 定义标识符
#define 定义宏
#define 替换规则
#和##
带副作用的宏参数
宏和函数的对比
命名约定
#undef
命令行定义
条件编译
文件包含
头文件被包含的方式
程序的翻译环境和执行环境
在ANSI C(标准C)的任何一种实现中,存在两个不同的环境。
第一种是翻译环境,在这个环境中源代码(.c 文件)被转换为可执行的机器指令(二进制指令,.exe文件)。
(VS->生成->生成解决方案)
VS 是集成开发环境,在以上过程中,它充当了翻译环境。
第二种是执行环境,它用于实际执行代码。
计算机只能执行二进制指令
粗谈编译+链接
翻译环境
● 组成一个程序的每个源文件(.c) 都单独通过编译器分别转换成目标代码(object code , obj)。
● 每个目标文件由链接器 (linker) 捆绑在一起,形成一个单一而完整的可执行程序。
● 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。
编译的几个阶段及链接
编译还可以分为三个阶段:预编译(预处理)、编译和汇编。
各个阶段的工作:
预处理阶段:进行 1、头文件的包含 (头文件在预处理阶段被展开,以后就不存在头文件了,即头文件不参与预处理以后的步骤。) 2、define 符号替换和删除 3、注释的删除 ,这些都是文本操作,最终生成 .i 文件。
编译阶段:(详见《编译原理》)分别对每个 .i 文件进行语法分析、词法分析、语义分析、符号汇总(符号汇总:记录全局变量名、自定义函数名和 main 函数名,如果这些函数有定义,会生成它们的地址,将符号和地址一一对应的表格,就叫符号表), 把代码翻译成汇编代码。生成 .s 文件
汇编阶段:把汇编代码翻译成二进制指令,生成目标文件(gcc 是 .o 文件,VS 是 .obj 文件),二进制指令存放在目标文件,并形成符号表(符号汇总时的符号和它们的地址所形成的表格)。
链接阶段:在这之前,每个源文件都是独立的,它们互不干扰,在链接阶段,它们就有一定的联系,这个阶段主要进行:1、合并段表 2、符号表的合并和重定位(每个目标文件都形成了一个符号表,这些符号表可能有一些符号的地址是无效的,比如 main 函数中 extern int Add(int x,int y),声明外部函数 Add ,Add 在 main 函数的源文件所生成的符号表的地址就是无效的(没有在mian函数定义),通过合并符号表将无效的地址重定位(比如 Add 函数在其他源文件找到定义,也就是说在其他源文件形成的符号表找到 Add 的函数地址),如果在链接阶段之后还是发现有无效地址(有函数找不到定义),就会报出“无法解析的外部符号”的错误)
运行环境
程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用注体运行时堆栈(函数栈帧)(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。4.终止程序。正常终止main函数;也有可能是意外终止。
(推荐阅读:《程序员的自我修养》)
预处理详解
预定义符号
__FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 _