编译和链接的过程

2023-05-16

程序要运行起来,必须要经过四个步骤:预处理、编译、汇编和链接。接下来通过几个简单的例子来详细讲解一下这些过程。

对于上边用到的几个选项需要说明一下。

使用 gcc 命令不跟任何的选项的话,会默认执行预处理、编译、汇编、链接这整个过程,如果程序没有错,就会得到一个可执行文件,默认为a.out

-E选项:提示编译器执行完预处理就停下来,后边的编译、汇编、链接就先不执行了。

-S选项:提示编译器执行完编译就停下来,不去执行汇编和链接了。

-c选项:提示编译器执行完汇编就停下来。

所以,这三个选项相当于是限定了编译器执行操作的停止时间,而不是单独的将某一步拎出来执行。

上述程序的执行过程大家应该都很熟悉了,就不浪费口舌了。

一、预处理:

       使用-E选项,表示只进行预编译,对应生成一个 .i 文件。

预处理过程进行的操作:

  • 将所有的“#define”删除,并且展开所有的宏定义
  • 处理所有的条件编译指令,比如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”
  • 处理“#include”预编译指令,将被包含的头文件插入到该编译指令的位置。(这个过程是递归进行的,因为被包含的文件可能还包含了其他文件)
  • 删除所有的注释“//”和“/* */”。
  • 添加行号和文件名标识,方便后边编译时编译器产生调试用的行号心意以及编译时产生编译错误或警告时能够显示行号。
  • 保留所有的#pragma编译指令,因为编译器需要使用它们。

使用一个简单的程序来验证一下事实是否如上述所说的一样

编写一个简单的程序,然后使用-E选项执行预处理过程,打开生成的 .i 文件与源文件进行比对,结果一目了然

       对于给代码加上行号这个就不在这里演示了,我们在写代码的时候是不会手动添加行号的,我们看到的行号都是自己使用的编辑工具自动加上的,而这些行号编译系统是看不到的,但是呢,我们发现如果我们哪一行的代码出现了问题,编译的时候就会给出提示说哪行的代码有什么问题,这就已经证明,编译器是会自动添加行号的。

二、编译:

        使用-S选项,表示编译操作执行完就结束。对应生成一个 .s 文件。

        编译过程是整个程序构建的核心部分,编译成功,会将源代码由文本形式转换成机器语言,编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。

  • 词法分析:

        词法分析是使用一种叫做lex的程序实现词法扫描,它会按照用户之前描述好的词法规则将输入的字符串分割成一个个记号。产生的记号一般分为:关键字、标识符、字面量(包含数字、字符串等)和特殊符号(运算符、等号等),然后他们放到对应的表中。

  • 语法分析:语法分析器根据用户给定的语法规则,将词法分析产生的记号序列进行解析,然后将它们构成一棵语法树。对于不同的语言,只是其语法规则不一样。用于语法分析也有一个现成的工具,叫做:yacc。

  • 语义分析:

       语法分析完成了对表达式语法层面的分析,但是它不了解这个语句是否真正有意义。有的语句在语法上是合法的,但是却是没有实际的意义,比如说两个指针的做乘法运算,这个时候就需要进行语义分析,但是编译器能分析的语义也只有静态语义。

       静态语义:在编译期就可以确定的语义。通常包括声明与类型的匹配、类型的转换。比如当一个浮点型的表达式赋值给一个整型的表达式时,其中隐含一个从浮点型到整型的转换,而语义分析就需要完成这个转换,再比如,将一个浮点型的表达式赋值给一个指针,这肯定是不行的,语义分析的时候就会发现两者类型不匹配,编译器就会报错。

       动态语义:只有在运行期才能确定的语义。比如说两个整数做除法,语法上没问题,类型也匹配,听着好像没毛病,但是,如果除数是0的话,这就有问题了,而这个问题事先是不知道的,只有在运行的时候才能发现他是有问题的,这就是动态语义。

  • 中间代码生成

       我们的代码是可以进行优化的,对于一些在编译期间就能确定的值,是会将它进行优化的,比如说上边例子中的 2+6,在编译期间就可以确定他的值为8了,但是直接在语法上进行优化的话比较困难,这时优化器会先将语法树转成中间代码。中间代码一般与目标机器和运行环境无关。(不包含数据的尺寸、变量地址和寄存器的名字等)。中间代码在不同的编译器中有着不同的形式,比较常见的有三地址码和P-代码。

       中间代码使得编译器可以分为前端和后端。编译器前端负责产生于机器无关的中间代码,编译器后端将中间代码换成机器代码。

  • 目标代码生成与优化

代码生成器将中间代码转成机器代码,这个过程是依赖于目标机器的,因为不同的机器有着不同的字长、寄存器、数据类型等。

最后目标代码优化器对目标代码进行优化,比如选择合适的寻址方式、使用唯一来代替乘除法、删除出多余的指令等。

三、汇编

汇编过程调用汇编器as来完成,是用于将汇编代码转换成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。

使用命令as hello.s -o hello.o 或者使用gcc -c hello.s -o hello.o来执行到汇编过程结束,对应生成的文件是.o文件。

四、链接

链接的主要内容就是将各个模块之间相互引用的部分正确的衔接起来。它的工作就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定向

符号决议:有时候也被叫做符号绑定、名称绑定、名称决议、或者地址绑定,其实就是指用符号来去标识一个地址。

                比如说 int a = 6;这样一句代码,用a来标识一个块4个字节大小的空间,空间里边存放的内容就是4.

重定位:重新计算各个目标的地址过程叫做重定位。

最基本的链接叫做静态链接,就是将每个模块的源代码文件编译成目标文件(Linux:.o  Windows:.obj),然后将目标文件和库一起链接形成最后的可执行文件。库其实就是一组目标文件的包,就是一些最常用的代码变异成目标文件后打包存放。最常见的库就是运行时库,它是支持程序运行的基本函数的集合。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

编译和链接的过程 的相关文章

  • Python中集合的使用

    1 set add xff09 xff1a 向集合中添加元素 xff0c 是整体添加进集合set中 xff1b set update 向集合中添加元素 xff0c update是将字符串中的拆分成字符进行追加 xff1b eg s1 61
  • Resource not found问题

    在运行ros中的xacro文件时出现的如下问题 resource not found mbot description ROS path 0 61 opt ros melodic share ros ROS path 1 61 opt ro
  • 启动Moveit Setup Assistant出错

    1 首先安装moveit配置助手 xff0c 我的ubuntu版本是18 04 xff0c 所以运行 xff1a sudo apt get install ros melodic moveit 填写个人密码安装 source opt ros
  • 形参如何改变实参

    把实参数组传递给函数 xff0c 则形参从数组那里得到了起始地址 xff0c 因此数组与实参数组共占了同一段内存单元 xff0c 在函数调用期间 xff0c 该变了形参数组的值 xff0c 也就改变了实参数组的值 例 xff1a int i
  • Linux下ARM 和单片机的串口通信设计

    摘要 xff1a 介绍Linux 环境下串口通信的设计方法和步骤 xff0c 并介绍了ARM9 微处理器s3c2440 在Linux 下和C8051Fxxx 系列单片机进行串行通信的设计方法 xff0c 给出了硬件连接和通信程序流程图 该方
  • AT+CSQ信号质量指示含义

    AT 43 CSQ 命令解释 xff1a 检查网络信号强度和SIM卡情况 命令格式 xff1a AT 43 CSQ lt CR gt 命令返回 xff1a AT 43 CSQ lt rssi gt lt ber gt 其中 lt rssi
  • MIPI接口和DVP接口的区别及优点

    DVP是并口 xff0c 需要PCLK VSYNC HSYNC D 0 xff1a 11 可以是8 10 12bit数据 xff0c 看ISP或baseband是否支持 xff1b MIPI是LVDS xff0c 低压差分串口 只需要要CL
  • 立体耳机插头和四极耳机插头三段、四段处的区别

    立体 耳机插头 和四极 耳机插头 三段 四段处的区别 在日常生活中 xff0c 通常较为细心的消费者就会发现 xff0c 适用于NOKIA手机的 耳机插头 和适用于iphone的 耳机插头 是互补兼容的 xff0c 但是iphone HTC
  • Nuttx学习笔记(一)

    最近在工作上需要用到这个nuttx实时操作系统 xff0c 并且对这个系统进行学习记录以及记录下自己所遇到过的问题 目录 一 环境配置 xff08 1 xff09 基础环境 xff08 2 xff09 下载nuttx xff08 3 xff
  • kernel command line 参数详解

    Linux内核在启动的时候 xff0c 能接收某些命令行选项或启动时参数 当内核不能识别某些硬件进而不能设置硬件参数或者为了避免内核更改某些参数的值 xff0c 可以通过这种方式手动将这些参数传递给内核 如果不使用启动管理器 xff0c 比
  • Internal error: Oops:

    01 02 00 02 24 110 SysRq Emergency Remount R O 01 02 00 02 24 221 mdss fb release all unknown process adbd pid 61 415 mf
  • /proc/meminfo详解

    cat proc meminfo MemTotal 2052440 kB 总内存 MemFree 50004 kB 空闲内存 Buffers 19976 kB 给文件的缓冲大小 Cached 436412 kB 高速缓冲存储器 http b
  • 浅谈Camera工作原理

    一 摄像头简介 摄像头 xff08 CAMERA xff09 又称为电脑相机 电脑眼等 xff0c 它作为一种视频输入设备 xff0c 在过去被广泛的运用于视频会议 远程医疗及实时监控等方面 近年以来 xff0c 随着互联网技术的发展 xf
  • EVT、DVT、PVT、MP等简介

    PLM xff08 Product Lifecycle Management xff09 System xff1a PLM是协助产品能够顺利完成在新产品开发 xff08 NPI xff1a New Product Introduction
  • UbuntuServer 12.04 svn服务的创建

    以下是我整理后的步骤 xff1a 1 安装必要的软件包 xff1a sudo apt get install subversion sudo apt get install libapache2 svn 2 创建一个SVN账号和SVN组 x
  • 在ESXi上把OpenWrt变成真正的路由器

    前面把openwrt装到了VMware workstation上 xff0c 本来想把openwrt直接安装到ESXi的 xff0c 但是转换镜像的时候不能生成OVF或者OVA文件 所以就先把镜像安装到了workstation xff0c
  • 电源和电池两种电源选一的芯片

  • can总线中的SOF、SRR、IDE和RTR数据位都是指什么

    帧起始 SOF xff1a 帧起始 SOF 标志着数据帧和远程帧的起始 xff0c 仅由一个 显性 位组成 仲裁域由标识符和RTR位组成 xff0c 标准帧格式与扩展帧格式的仲裁域格式不同 标准格式里 xff0c 仲裁域由1l位标识符和RT
  • linux makefile的一些变量

  • Nuttx学习笔记(二)————在STM32上部署Nuttx系统

    目录 一 平台配置 二 在ubuntu下使用串口来烧录至目标文件至STM32F07 xff08 一 xff09 ubuntu下stm32flash工具下载 xff08 二 xff09 Ubuntu20 04安装stm32开发环境 xff08

随机推荐

  • linux种Makefile一些自动化变量

  • arm 中的三级流水线中的PC值和当前指令的关系

  • TIM输出比较的三种模式

    TIM输出比较的三种模式 此项功能是用来控制一个输出波形 xff0c 或者指示一段给定的的时间已经到时 当计数器与捕获 比较寄存器的内容相同时 xff0c 输出比较功能做如下操作 xff1a 将输出比较模式 TIMx CCMRx寄存器中的O
  • TIM_OCMode_PWM2;TIM_OCMode_PWM1

    首先 xff0c 本人虽然初学STM32但极力反对一种误人子弟的观点 xff1a 对于STM32这样级别的MCU xff0c 有库函数就不用去看寄存器怎么操作的了 xff01 好了 xff0c 言归正传 xff0c 最近总看到很多朋友对于P
  • MOS器件的重要特性——15个为什么?

    MOS器件的重要特性 15个为什么 xff1f xff08 一 xff09 xff08 1 xff09 为什么E MOSFET的阈值电压随着半导体衬底掺杂浓度的提高而增大 xff1f 而随着温度的升高而下降 xff1f 答 E MOSFET
  • 采样频率、采样点数、频率分辨率

    1 频率分辨率的2种解释 解释一 xff1a 频率分辨率可以理解为在使用DFT时 xff0c 在频率轴上的所能得到的最小频率间隔f0 61 fs N 61 1 NTs 61 1 T 其中N为采样点数 xff0c fs为采样频率 xff0c
  • 32位单片机 一个32位地址代表一个字节而不是4个字节(32位)

    在数据手册上 xff0c BSRR的偏移地址为0X18 xff0c 然后手册讲完BSRR后直接讲LCKR了 xff0c 并且LCKR的偏移地址是 OX1C 所以根据 OX1C 0X18 61 0X04 就知道BSRR是32位寄存器了 因为一
  • μC/OS-Ⅲ系统的任务切换和任务调度

    C OS 系统的任务切换和任务调度 一 任务切换 在操作系统中当任务需要从一个任务切换到另外一个任务时 xff0c 要将当前任务的现场保存到当前任务的堆栈中 xff08 当前任务现场主要指CPU相关寄存器 xff09 xff0c 然后回复新
  • 反射系数、驻波比、S参数之间的关系

    反射系数 驻波比 S参数之间的关系 xff01 转载 回波损耗 Return Loss 入射功率 反射功率 为dB数值 反射系数 反射电压 入射电压 为标量 电压驻波比 Voltage Standing Wave Ration 波腹电压 波
  • 浅谈PWM控制电机

    先简单说说这几种模式 1 双极模式 xff0c 即电枢电压极性是正负交替的 xff0c 优点 xff1a 能正反转运行 xff0c 启动快 xff0c 调速精度高 xff0c 动态性能好 xff0c 调速静差小 xff0c 调速范围大 xf
  • Nuttx系统学习笔记(三)——使用Nuttx操作STM32F429外设

    在上一篇 xff0c 我们已经学会了如何将Nuttx进行烧录 xff0c 以及学会了如何部署这个操作系统 xff0c 接下来我们就要使用这个操作系统来实现我们对嵌入式设备的控制 xff0c 当然也是从点灯开始的 这个基于Posix架构的操作
  • .NetCore 5.0 WebAPI 发布到iis时访问api出现404的解决方案

    情况介绍 xff1a 新建了个 NetCore 5 0 的 WebAPI项目 xff0c 发布部署到WINDOWS10 的 IIS后 xff0c 默认打开 http 127 0 0 1 swagger 出现404找不到页面的错误 原因 xf
  • 新手如何快速入门人工智能?

    网上有很多关于 新手如何快速入门人工智能 的文章 xff0c 但是对于真正的小白来说并没有太多的指导作用 作为新手想进入人工智能领域 xff0c 首先是要明确需要掌握哪些基础知识 xff0c 其次是掌握一套行之有效的学习方法 xff0c 最
  • 人工智能入门需要学习哪些课程?AI基础知识

    要入门人工智能 xff0c 需要掌握一些基础知识和技能 以下是一些入门人工智能需要学习的课程和基础知识 xff1a 人工智能入门需要学习哪些课程 xff1f AI基础知识 数学基础 xff1a 人工智能需要用到许多数学知识 xff0c 包括
  • 模块学习2:基于PELCO-D协议对云台进行定点控制

    开发手上的一个云台 xff0c 使用的就是PELCO D协议 这个协议开始网上找了一圈 xff0c 发现下载完整版的协议大多是还都要收费 xff0c 后面在官方下载了一份原版完整版协议的协议内容 xff0c 配合网上搜索到的资料完成对手上这
  • C语言和C++的区别(函数重载)

    C和C 43 43 的区别主要分为三部分 xff1a 接下来详细介绍一下函数部分的区别 1 返回类型 2 参数列表 此外 xff0c 在C 43 43 中还支持缺省参数 xff0c 而C语言不支持 什么是缺省参数呢 xff1f 缺省参数是声
  • 动态创建二维数组的两种方法

    首先来讲解一下什么是二维数组 其实二维数组也可以说是一个一维数组 xff0c 只是这个一维数组比较特别 xff0c 它的每一个元素都是一个一维数组 虽然二维数组在底层是按照一维数组的存储方式来存储的 xff0c 即存完第一行 xff0c 紧
  • 什么是进程?

    程序 xff1a 完成特定任务的一系列指令集合 代码段 43 数据段 放在磁盘中的程序 进程 xff1a 进行就是正在进行中的程序 1 用户角度 xff1a 进程是程序的一次动态执行过程 2 操作系统 xff1a 进程是操作系统分配资源的基
  • 死锁的四个必要条件和解决办法

    死锁概念及产生原理 概念 xff1a 多个并发进程因争夺系统资源而产生相互等待的现象 原理 xff1a 当一组进程中的每个进程都在等待某个事件发生 xff0c 而只有这组进程中的其他进程才能触发该事件 xff0c 这就称这组进程发生了死锁
  • 编译和链接的过程

    程序要运行起来 xff0c 必须要经过四个步骤 xff1a 预处理 编译 汇编和链接 接下来通过几个简单的例子来详细讲解一下这些过程 对于上边用到的几个选项需要说明一下 使用 gcc 命令不跟任何的选项的话 xff0c 会默认执行预处理 编