代实现执行需要通过两个大体的过程
1.第一是翻译,把你敲的代码转换成机器的可执行指令
2.第二就是运行,机器执行由代码转换过来的指令
1.编译与链接
程序通常包括多个源文件,这些文件需要单独通过编译器转换成目标文件
![](https://img-blog.csdnimg.cn/img_convert/2e7d8be4500760282afdbb23f28077ae.png)
转换成目标文件之后再由链接器捆绑在一起之后形成可执行程序
链接器还会将代码中所引用的头文件链接到程序中
1.1编译本身也分为几个阶段
删除注释
处理预处理指令#include等等
符号汇总
转换成机器指令
关于符号汇总,就是将各个文件中的关键字汇总,比如函数,全局变量
1.2链接
合并段表
合并符号表和符号表的重定位
关于合并符号表,编译器会将各个文件生成的符号表进行合并,将其中重复的符号进行合并,如果合并符号表中后仍然存在地址无效的关键字,编译器将会报错(此情况原因可能是因为一个函数被声明了但是没有被定义)。
2.预处理详解
2.1预定义符号
__FILE__ __LINE__ __DATE__ __TIME__ __STDC__ | //进行编译的源文件 //文件当前的行号 //文件被编译的日期 //文件被编译的时间 //如果编译器遵循ANSI C,其值为1,否则未定义 |
这些符号都是c语言内置的
2.2#define
在使用#define定义宏的时候需要注意几个点
在使用宏是是直接替换的,并不会计算出结果之后再替换
#define X 1+2
int main()
{
int sum=2*X;
}
如果不够细心的话计算出的sum的结果是6
而在编译器眼中这段代码是这个样子的
#define X 1+2
int main()
{
int sum=2*1+2;
}
结果就是4了
可以在定义的时候多带几个括号,就尽可能避免这种问题
#define X (1+2)
int main()
{
int sum=2*(1+2);
}
在定义带参数的宏时候也是同理
在定义宏的时候不要带上;否则可能会引起语法问题
2.2.3#define中#和##的作用
在字符串中插入“#参数”可以将变量名转换成字符串并插入到字符串中
#define PRINT(X) printf("这个"#X"大小是%d",x)
int main()
{
int a=10;
PRINT(a);
}
![](https://img-blog.csdnimg.cn/img_convert/802d29567afa45646baefad6da6668cf.png)
##的作用是将两边的符号合并成一个符号
#define ADD(a,b) a##b+=10
这段代码的作用是把ab加上10,但是ab如果没有定义的话是会报错的
2.3预处理指令
2.3.4#undef
这条指令用于移除一个宏定义。
#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
2.4条件编译
有的时候为了避免重复定义符号或者避免重复引入头文件,但是又不知道在之前的代码中有没有定义,可以在定义符号和引入头文件的时候使用条件编译指令。
#if(常量表达式)
#else
#endif
判断是否被定义
#if defined(symbol)