目录
一 代码的编译
程序要运行起来,必须要经过四个步骤:预处理、编译、汇编和链接。接下来通过几个简单的例子来详细讲解一下这些过程。
对于链接,是先将所有.c
文件编译,最后汇总链接
组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个 人的程序库,将其需要的函数也链接到程序中。
1.1 编译,汇编,链接
编译过程是将预编译处理好的C代码经过一系列处理转换为汇编代码。
主要有以下几个方面的处理:
1、语法分析
2、词法分析
3、语义分析
4、符号汇总
编译过程完成后,进入汇编过程,该过程会将汇编代码转换为二进制代码(机器语言),并会形成符号表。
链接过程会对所有源文件编译汇编后的代码进行合并段表和对符号表进行合并和重定义,也就是链接。
1.2 程序的执行过程
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
1.3 预处理
程序只进行预编译,对应生成一个.i文件。
预处理过程进行的操作:
1、将所有的“#define”删除,并且展开所有的宏定义
2、处理所有的条件编译指令,比如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”
3、处理“#include”预编译指令,将被包含的头文件插入到该编译指令的位置。(这个过程是递归进行的,因为被包含的文件可能还包含了其他文件)
4、删除所有的注释“//”和“/* */”。
5、添加行号和文件名标识,方便后边编译时编译器产生调试用的行号心意以及编译时产生编译错误或警告时能够显示行号。
6、保留所有的#pragma编译指令,因为编译器需要使用它们。
二 #define定义宏
1、不带参数的宏
我们可以使用宏来替换一些常量,关键字等标识符。注意宏末尾不要加分号
宏的替换列表可以包括标识符、关键字、数值常量、字符常量、字符串字面量、操作符和排列。当预处理器遇到一个宏定义时,会做一标识符代表 替换列表的记录。在文件后面的内容中,不管标识符在哪里出现,预处理器都会用替换列表代替它。
#define 标识符 替换列表
#define MAX 100
#define MIN 1
#define _CRT_SECURE_NO_WARNINGS 1 //vs编译器下,防止使用不安全函数而报错,如sca