C/C++编译原理及过程整理

面试被问到C编译原理,所以回来整理一下。

编译主要分为四个大步骤:预编译、编译(.s、.asm)、汇编(.obj、.o、.a、.ko)、链接(.exe、.elf、.axf等),在C/C++中统称为编译。
前面文章 https://blog.csdn.net/a063225/article/details/90181715 介绍过集成开发环境、编译器,这里再说明一下,集成开发环境是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器,调试器和图形用户界面工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。

 编辑器:编写代码的一些窗口。

 编译器:检查用户代码的一些语法错误,将其编译成汇编代码。

 汇编器:将编译出来的汇编文件编译成一定功能的目标代码。

连接器:将目标代码连接成可执行文件。

(一)预编译

使用的gcc命令是:gcc –E
对应于预处理命令cpp
a. 宏定义指令:将所有的#define删除,并且展开所有的宏定义。
b. 条件编译指令:处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif等。
c. 头文件包含指令:处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
d. 特殊符号指令:预编译器可研识别一些特殊的符号,例如:删除所有注释 “//”和”/* */”。
e.为Debug及日志添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
f. 保留所有的#pragma编译器指令,因为编译器需要使用它们。

(二)编译

使用的gcc命令是:gcc –S
对应于编译命令 cc –S
a.词法分析
使用扫描器将源码分隔为一系列的记号(Token),即源码中的不可分隔项,较为容易理解,比如下面的:
int index = (2 + 8) * c 会被折分为 :int index = ( 2 + 8 ) * c 10个token,左右半括号各为一个
b.语法分析
将a中分出来的Token,映射为语法树。
c.语义分析
静态语义(在编译器可以确定的语义)、动态语义(只能在运行期才能确定的语义)。
在b中语法树的基础上,分析是否有错误语义,编译器所能分析的语义为静态语义,包括:声明是否正确、类型是否匹配、类型的转换是否符合要求。
d.源代码优化
经过前面三个过程后,将源代码转换为中间代码,(中间代码是与目标机器和运行环境无关的),可以理解为将c中通过的语法树通过一定的规则拍平,变为类假于目标代码的结构,为什么要引入中间语言呢,目标语言很多时候是硬件相关的,而中间语言与硬件无关。
e.生成目标代码并进行相应优化
目标代码的文件组织格式为.o文件,其内部的格式与具体设备有很大关系,比如在Android中,对arm7和x86CPU要编译出不同的so文件,此处同理,不同的硬件环境生成不同的目标代码。目标代码的优化也是针对不同情况有不同处理,在此不再展开,感兴趣的同学可以参考编译原理相关书籍。

(三)汇编

使用的gcc 命令是:gcc –c
对应于汇编命令是 as
汇编的目的是把汇编语言转为机器语言,基本是一条转一条,没啥特殊的,每一个汇编语句几乎都对应一条机器指令。根据汇编指令和机器指令的对照表一一翻译即可。

(四)链接

使用的gcc 命令是: gcc
对应于链接命令是 ld
链接是要解决目标文件之间的互相依赖关系,当a文件中的aa方法中调用了b文件的bb方法时,在汇编完成后,a文件的bb方法并没有准确的内存地址,链接后会转换为虚拟地址,虚拟地址可以依据一定的规则转换为实际地址,即可以运行时找到该方法。链接过程包括:地址和空间分配、符号决议和重定位。
函数库分静态链接库(又称静态库*.lib)和链接动态库(又称动态库*.dll)。
静态库的链接在编译时会被编译进汇编文件,这样的操作会改变文件大小;而动态库则是在执行时(双击运行),当需要动态库中的文件时才被链接到可执行文件的。

主要参考以下博文
https://blog.csdn.net/HSUPERA/article/details/51895230
https://blog.csdn.net/kcstrong/article/details/81216411

你可能感兴趣的:(C++)