C语言基础——编译器工作原理
代码编译过程分为四个阶段:
- 预处理阶段
- 编译阶段
- 汇编阶段
- 链接阶段
接下来我们写一段简单的代码 demo.c 看一下编译器的工作过程,这里用的是ubuntu里面的vim编辑器以及gcc编译器。
#include <stdio.h>
#define MAX_NUM 100
int main()
{//打印MAX_NUMprintf("MAX_NUM=%d\n",MAX_NUM);int a=1,b=2;int c=a+b;printf("c=%d\n",c);return 0;
}
以上就是demo.c的代码。
下面,我们将通过控制gcc编译器的参数,让gcc编译器一步一步的编译,而不是一次性完成编译。首先,简单看一下gcc的参数:
在ubuntu里面输入指令 man gcc
即可找到gcc编译器的参数。我们将使用的是最前面的-C,-S,-E指令。下面我们开始用指令来控制。
1.预处理阶段
输入指令:gcc -E demo.c -o demo.i
,得到的demo.i文件就是预处理之后的文件。我们可以进入这个文件。
进入demo.i,我们可以看到,预处理阶段将头文件、宏定义展开,并且删除了注释部分,而main()函数部分还是c语言代码。因此,预处理阶段的任务的就是:
- 展开头文件
- 展开宏定义
- 删除所有注释
2.编译阶段
输入指令:gcc -S demo.i -o demo.S
,得到的demo.S文件就是编译阶段的文件,.S后缀名表示的就是汇编代码。同样我们可以进入demo.S:
进入之后可以发现,代码都已经变成了汇编代码。这一阶段的主要任务就是:
- 检查语法错误
- 翻译成汇编语言
3.汇编阶段
输入指令:gcc -C demo.S -o demo.o
,得到的demo.o就是汇编阶段后的代码:
我们可以看到,这个时候已经是机器码了。但是这个文件能不能直接运行呢?我们输入指令:./demo.o
试一下:
这里会报错。报错就说明.o不是最终能跑起来的文件。但是为什么会报错呢?这已经是机器码了,为什么还是不能直接运行呢?
因为我们看不懂机器码,所以我们先用反汇编来看看这个时候demo.o里面的内容。输入反汇编指令:objdump -d demo.o
系统里面会有两套地址,一套是系统自己用的的默认地址,一套是用户代码运行时用的内存地址。cpu是跳到内存里拿地址的,代码运行时,操作系统会把他放到用户代码运行的内存空间里,所以,编译器编译后的最终能运行的那个文件里面的地址不能是系统默认地址,而应该是内存地址。
demo.o里面分配的是默认地址,操作系统把demo.o拿到内存时,不知道放在哪里(因为demo.o里面不是内存地址),因此无法运行。
为了把代码放到内存里,要给代码的每一条指令链接一个内存地址,链接后的地址就是其在内存中存放的地址。这就是编译的第4个阶段。
汇编阶段系统主要做的是
- 将汇编语言生成机器指令
4.链接阶段
输入指令gcc demo.o -o demo.elf
,这时候的.elf文件就是最终能运行的文件。我们可以反汇编一下这个文件,输入反汇编指令:objdump -d demo.elf
,可以看到:
链接阶段主要做了三件事
- 添加地址:把各种地址信息添加到headinfo中
- 补代码:补充的是固定的进程的启动代码和初始化代码
- 分段:一种技术,将机器码链接成段
总结
- 上述是用代码控制了编译过程。如果想要一步到位,我们可以直接输入指令
gcc demo.c -o demo.elf
,后面的demo.elf,就算不加后缀名,默认也是elf的文件。 - 学习c语言不能单单学习语法,还要学习其他相关的基础知识。编译器是学习任何一门都需要接触的,所以了解编译器的工作原理也是很有必要的。
以上就是文章的主要内容,如有错误,请各位朋友给我留言嗷。谢谢你们~
C语言基础——编译器工作原理相关推荐
- C/C++编程笔记:C语言的编译器工作原理
以gcc编译器为例子,编译实际上总共经历了四个阶段 预处理--->编译--->汇编--->链接 1.预处理阶段:编译器以cpp文件作为一个单元,首先读这个cpp文件,发现第一句与第二 ...
- c语言是以文件为单位编译,c语言从头开始(三:编译器工作原理) (我们还可以自己编写头文件后缀是xx.h并把它当前代码文件所在目录我们要用就可以直接通过下面代码使用)...
c语言从头开始(三:编译器工作原理) [[枫歌枫歌]c语言从头开始(三:编译器工作原理)]https://toutiao.com/group/6568056688174170628/?iid=1590 ...
- 并发问题的解决思路以及Go语言调度器工作原理
上周的文章<Go并发编程里的数据竞争以及解决之道>最后留下了一个用并发解决的思考题,期间有几位同学留言说了自己的实现思路,也有两位直接私信发代码让我看的,非常感谢几位的积极参与.今天的文章 ...
- c语言5v电源电路工作原理,稳压电源电路图详解_5v稳压电源电路原理图
描述 稳压电源(stabilized voltage supply)是能为负载提供稳定的交流电或直流电的电子装置,包括交流稳压电源和直流稳压电源两大类.当电网电压或负载出现瞬间波动时,稳压电源会以10 ...
- 步进驱动器基础及工作原理
从步进电机的转动原理可以得出,要使步进电机正常运行,必须按规律控制步进电机的每一相绕组得电.步进驱动器接收外部的信号是方向信号(DIR)和脉冲信号(CP).另外步进电机在停止时,通常有一相得电,电机的 ...
- c语言5v电源电路工作原理,创易AC-DC RCC3W开关电源工作原理
创易AC-DC RCC3W开关电源工作原理 本文由华禹同事所写,博主指导.修改 一:AC_220V输入部分 AC_220V由CON1/CON2或J1进入后,经过R100(降低C100初始充电电流冲击和 ...
- 网络基础-路由器工作原理
路由器工作原理 一.路由概述: 1.路由:从源主机到目标主机的转发过程. 二.路由器的工作原理: 1.根据路由表转发数据: 2.作用: 三.路由表的形成: 1.路由表: 2.路由表形成: 3.静态路由 ...
- c语言实现编译器编译原理,编译原理课程设计--C语言编译器实现.doc
编译原理课程设计--C语言编译器实现 甘肃政法学院 编译原理课程设计 题 目 C语言编译器实现 计算机科学学院计算机科学与技术专业10 级 计本 班 学 号: 201081010137 姓 名: 杨青 ...
- git基础及工作原理
目录 前言 1. git是什么 2. 集中式版本控制与分布式版本控制 2.1 集中式版本控制 2.2 分布式版本控制 3. git基本原理 3.1 工作区 3.2 暂存区 3.3 仓库区 3.3.1 ...
最新文章
- windows10 mysql 5.5.36 安装
- c 中ajax不起作用,Jquery AJAX調用:$(this)在成功后不起作用
- Python3之打印出map结果的print(list())用法
- [云炬商业计划书阅读分享]洗车店创业计划书
- 6.4 JAVA 方法重载
- vim配置php语法高亮
- php实现第三方邮箱登录_PHP实现用户异地登录提醒功能的方法
- int.class 与 Integer.class
- php 重定向 post,使用php curl getpost方法向页面文件发送重定向指令
- modbus_tk与Modubs Slave结合使用
- VC下关于debug和release的不同的讨论(收藏-转载)
- Mac安装Mysql,并启动
- WPS Office.10.1.0.6445绿色免安装版下载
- 使用python处理视频文件,提取关键帧并保存【已调通】
- 后台管理导航菜单及模板
- 基于Java的微小企业人事管理系统的设计与实现 毕业设计-附源码231012
- python3socket非阻塞在linux里无效_Linux Socket - 内核非阻塞功能
- 批量提取 srt 字幕文件中的文字
- BERT通俗笔记:从Word2Vec/Transformer逐步理解到BERT
- 2022年全国职业技能大赛-网络系统管理竞赛-网络模块-Ruijie-AC-SSH
热门文章
- JQuery从入门到精通
- 开源IM-免费企业即时通讯-恩布互联ENTBOOST 1.4发布,增加管理中心
- 【小玩意儿】使用Python自动化发送微信消息进行订水
- uni-app微信小程序使用ECharts
- VScode运行C语言代码的方法
- 输入一个年份,月份,输出该月份的日历。
- android:maxHeight,android:maxWidth失效
- Visual Studio 2012 Ultimate Release Candidate 体验
- vs2010下ogre1.8.1+bullet-2.82
- 世界上最富有的前十个国家