✍前言:
今天让我来抽空带大家来看一下我们编写的代码是如何生成可执行文件的,中间他的过程是什么样的,我们的代码发生了什么样的变化,如何你们好奇了,那么让我们就往下看,让我带着大家用最简单的方法告诉大家!!!
编译的过程
1.编译链接的总体过程分为两个大步骤 : 1.编译 2. 链接
我们可以看到,在编译的时候,其中又产生了3个小步骤 1.预处理 2. 编译 3.汇编
下面我们先看一下编译中的这三个小步骤
预处理
预处理做的工作是:
1.注释的删除和替换(把注释替换为空格)
2.头文件的包含(会把头文件全部展开)
3.#define 符号的替换,所有的预处理指令都会这个步骤处理
4.把我们写的 .c文件生成了 .i文件
这些操作我们成为文件操作
让我们先看一下这段代码,既然我们知道了预处理的工作,那让我们把它执行起来看一下是否正确呢 ?
执行前:
执行后:
我们可以看到这个.i的文件,本来12行的代码,变为了848行的代码。说明我们的头文件已经正常的展开了,同时NUM也被处理为了数字,注释也被替换为了空格!
编译
编译做的工作:
1.词法分析 2.语法分析 3.语义分析 4.符号汇总
5.把代码翻译成了汇编代码 生成了 .s文件
汇编
汇编做的工作:
1.把汇编代码翻译成了电脑可以看懂的二进制指令,生成了 .o文件
2.生成符号表
我们看完编译的过程,最后要是想生成一个可执行的文件,我们还要进行最后一步,把这些.o文件全部连接起来
链接
链接做的工作:
1.把目标文件和链接库生成可执行的二进制程序
2.合并段表
3.符号表的合并符号表的重定位
当然了,在本章节我们还会继续朝着预处理中的细节深入
预处理解析
预定义符号,这些符号是语言内置的
1.__FILE__ 进行编译的源文件
2.__LINE__ 当前文件的行号
3.__DATE__ 文件被编译的日期
4.__TIME__ 文件被编译的时间
5.__STDC__ 如果编译器遵循ANSI C,其值为1,否则未定义
#define
define定义常量
#define MAX 1000
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break;case //在写case语句的时候自动把 break写上。
// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )从这里我们可以知道define定义常量实行的是替换
注:
#define MAX 1000 ;不要加 ; 如果加了分号也会被替换过去,这样的换我们定义变量的时候就不要加分号了, int a = MAX 就不要加分号了
define定义宏
#include <stdio.h>
#define ADD(x,y) (x+y)
int main()
{
int a =10;
int b =20;
int ret = ADD(a,b);
return 0;
}
上面就是一个宏替换 ,但是我们要注意的是:
1. #define name( parament-list ) stuff,其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中
2.参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
宏替换规则:
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先
被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上
述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
#和##
#include <stdio.h>
#define PRINT(N) printf("the value of "#N" is %d\n",N)
int main()
{
int a = 10;
PRINT(a);
int b = 20;
PRINT(b);
return 0;
}
#是把一个宏参数变成对应的字符串
#include <stdio.h>
#define CLASS(Class,num) Class##num
int main()
{
int Class106 = 100;
printf("%d\n", CLASS(Class, 106));
return 0;
}
##把两段分离的字符合并起来
以上就是全部代码,还有很多需要优化的地方,我之后也会继续改良,如有错误和不足的地方。欢迎大家指正,完结撒花