预处理,编译,汇编,链接
Posted HQK666999
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了预处理,编译,汇编,链接相关的知识,希望对你有一定的参考价值。
目录
前言
一个c/c++文件想要变成可执行文件要经过预处理生成预处理文件(.i文件),编译阶段对预处理文件进行编译生成汇编文件(.s文件),汇编阶段对汇编文件进行处理生成目标文件(.o文件),最后链接目标文件生成可执行程序。下面我将介绍在各个阶段对程序进行了哪些处理。
1.预处理:
c/c++源文件中,以#开头的命令被称为预处理命令,如#include、#define、条件编译命令#if、#ifdef等。所做的主要工作如下:
将所有的#define删除,并展开所有的宏定义
处理所有的条件预编译指令,如:#if #ifdef #elif #else #endif
处理#include预编译指令,将被包含的文件插进到该指令的位置,这个过程是递归的
删除所有的注释//与/* */
添加行号与文件名标识,以便产生调试用的行号信息以及编译错误或警告时能够显示行号
保留所有的#pragma编译器指令,因为编译器需要使用它
宏替换:
#define可以定义宏也可以定义标识符(重命名)
在预处理阶段会把A替换成100,MAX(x,y)替换成(a)>(b)?(a):(b)要注意的是原封不动的替换。带有参数时每个参数都要带有括号。
需要注意的是宏参数和#define可以出现其他#define定义的变量,但是对于宏不能出现递归。当预处理器 搜索#define定义的符号时,字符串常量的内容并不被搜索。
头文件展开:
#include <> 是引系统提供的头文件,优先到库里面去找, #include" "是引自己定义的头文件,优先到当前路径去找。找到之后在#include<xx.h>的那一行,将xx.h这个头文件的内容原地展开替换这一行#include语句。
条件编译:
就是选择编译,满足条件就编译不满足条件就不编译。
对于单分支因为1为真所以下面的printf会编译,对于多分支就是考虑多种情况,当然A=100成立所以下一句会编译A=200不成立所以不会编译。#if defined(MAX)这是判断MAX是否定义,定义了就编译没定义就不编译。
2.编译:
编译阶段做的事情就是对预处理文件进行词法分析(lex)、语法分析(yacc)、语义分析及优化(就是检查语法)后生成汇编代码生成汇编文件(.s文件)。
3.汇编:
就是将编译阶段生成的汇编代码转换为计算机能识别的机器码生成目标文件(.o文件)。反汇编是指将机器代码转换为汇编代码,这在调试程序时常常用到。
通常一个目标文件包含两部分:
代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。
数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。
4.链接:
链接文件主要是将有关的目标文件彼此相连,就是在一个文件中引用的符号和该符号在另一个文件中的定义链接起来,使得这些目标文件成为一个能被操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种。
(1)静态链接
在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
(2) 动态链接
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
以上是关于预处理,编译,汇编,链接的主要内容,如果未能解决你的问题,请参考以下文章