文件的编译与链接

news2024/12/26 0:07:04

目录

翻译环境与链接环境:

翻译环境:

 编译器部分:

预处理:

编译:

词法分析:

语法分析:

语义分析:

汇编: 

小总结:

 链接器部分:

 运行环境:


翻译环境与链接环境:

在ANSIC的任何一种实现中,存在两个不同的环境。

  • 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  • 第2种是执行环境,它用于实际执行代码。

翻译环境:

代码通过翻译环境进行编译,变成一个可执行的程序,可执行的程序其实就是二进制指令或者叫他机器指令,二进制指令在运行环境中运行和执行。

也因此翻译环境分为两个部分,一个是编译另一个是链接。

  •  win:目标文件 的后缀是.obj可执行文件的后缀是.exe
  • Linux:目标文件 的后缀是.o可执行文件没有后缀

 

 

 编译器部分:

是源文件通过了编译器内部的预编译、编译、汇编进行了文件的转化,最终变为目标文件,同链接库一起进入了链接器中进行最后的转化。

  • 链接库是指运行时库(它是支持程序运行的基本函数集合)或者第三方库。
  • 类似scanf和printf这种库函数其实就是通过链接库传递到文件中,并在目标文件链接的过程中,一同和目标文件走向链接器。

当一个C语言的项目中可能有多个c 文件一起构建,那多个c文件如何生成可执行程序呢?

  • 多个.c文件单独经过编译出编译处理生产对应的目标文件。
  • 注:在Windows环境下的目标文件的后缀是obj,Linux环境下目标文件的后缀是.o
  • 多个目标文件和链接库一起经过链接器处理生成最终的可执行程序
  • 链接库是指运行时库(它是支持程序运行的基本函数集合)或者第三方库。 
预处理:

预处理会把头文件的内容添加到文件中代替原来的头文件,且预处理也叫做预编译。

预处理阶段主要处理那些源⽂件中#开始的预编译指令。⽐如:#include,#define,处理的规则如下:

  • 将所有的 #define 删除,并展开所有的宏定义。
  • 处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif 。
  • 处理#include 预编译指令,将包含的头⽂件的内容插⼊到该预编译指令的位置。这个过程是递归进 ⾏的,也就是说被包含的头⽂件也可能包含其他⽂件。
  • 删除所有的注释
  • 添加⾏号和⽂件名标识,⽅便后续编译器⽣成调试信息等。
  • 或保留所有的#pragma的编译器指令,编译器后续会使⽤。
  • 经过预处理后的.i⽂件中不再包含宏定义,因为宏已经被展开。
  • 并且包含的头⽂件都被插⼊到.i⽂件 中。所以当我们⽆法知道宏定义或者头⽂件是否包含正确的时候,可以查看预处理后的.i⽂件来确认。
编译:

编译过程就是将预处理后的文件进行一系列的:词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件。

词法分析:

将源代码程序被输入扫描器,扫描器的任务就是简单的进行词法分析,把代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)。

举例:

array[index] = (index+4)*(2+6);

进行分析:

 

语法分析:

接下来语法分析器,将对扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树。

 

语义分析:

由语义分析器来完成语义分析,即对表达式的语法层面分析。编译器所能做的分析是语义的静态分析。静态语义分析通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息。

 

 

汇编: 

汇编器是将汇编代码转转变成机器可执⾏的指令,每⼀个汇编语句⼏乎都对应⼀条机器指令(二进制指令)。

就是根 据汇编指令和机器指令的对照表⼀⼀的进⾏翻译,也不做指令优化。

汇编其实是将之前的文件转化为二进制文件,而后在和链接库一同进入链接器中。

小总结:

 

 链接器部分:

 链接是一个复杂的过程。

链接的时候需要把一堆文件链接在一起才生成可执行程序。

链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤链接解决的是一个项目中多文件、多模块之间互相调用的问题。

举例:
add.c
int g_val = 2022;
int Add(int x, int y)
{
 return x+y;
}

test.c

#include <stdio.h>
//test.c
//声明外部函数
extern int Add(int x, int y);
//声明外部的全局变量
extern int g_val;
int main()
{
 int a = 10;
 int b = 20;
 int sum = Add(a, b);
 printf("%d\n", sum);
 return 0;
}

 

链接器中的分配功能其实离不开编译和汇编的作用。

图例: 

 

 运行环境:

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须1.由手工安排,也可能是通过可执行代码置入只读内存来完成
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态 (static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值.
  4. 终止程序。正常终止main函数:也有可能是意外终止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1050123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLMS: 将模型与人类价值观对齐Aligning models with human values

欢迎回来。让我们回到 生成式 AI 项目的生命周期。 上周&#xff0c;你 仔细研究了一种叫做微调的技术。 使用 指令&#xff08;包括路径方法&#xff09;进行微调的目标是 进一步训练 模型&#xff0c;以便它们更好地理解 类似人类的提示并 生成更多类似人类的响应。 与基…

2023版 STM32实战5 基本定时器中断

基本定时器简介与特性 -1-时钟可分频 -2-计数模式只可以选择累加 -3-只可以用来定时&#xff08;含中断&#xff09; 查看时钟源 如图定时器7的时钟最大为72MHZ 定时时间的计算 通用定时器的时间计算公式为 Tout &#xff08;&#xff08;arr1&#xff09;&#xff08;psc1&…

[Framework] Android Binder 工作原理

Binder 是 Android 系统中主要的 IPC 通信方式&#xff0c;其性能非常优异。但是包括我在内的很多开发者都对它望而却步&#xff0c;确实比较难&#xff0c;每次都是看了忘&#xff0c;忘了看&#xff0c;但是随着工作的时间约来越长&#xff0c;每次看也都对 Binder 有新的认识…

【图像处理】SIFT角点特征提取原理

一、说明 提起在OpenCV中的特征点提取&#xff0c;可以列出Harris&#xff0c;可以使用SIFT算法或SURF算法来检测图像中的角特征点。本篇围绕sift的特征点提取&#xff0c;只是管中窥豹&#xff0c;而更多的特征点算法有&#xff1a; Harris & Stephens / Shi–Tomasi 角点…

一种节约存储空间的技术——数据压缩

数据压缩是指&#xff1a;通过特定的算法&#xff0c;将计算的中的文件大小得到降低的一种机制。 目前生活中最常见的应用例子&#xff0c;比如&#xff1a;你通过聊天软件将一张图片发送给好友&#xff0c;再选择发送图片的时候&#xff0c;有一个选项为是否发送原图&#xf…

FL Studio21.1电脑试用体验版音乐制作软件

我一直以来对音乐艺术都很感兴趣。最近我接触到了一款名为 FL Studio 的电脑版音乐制作软件&#xff0c;深感其强大功能和广泛适用性。通过使用这款软件&#xff0c;我不仅深入了解了音乐制作的过程与技巧&#xff0c;也加深了对音乐创作的理解。 FL Studio 最初是一款针对 MI…

Flutter笔记 - ListTile组件及其用法

Flutter笔记 ListTile组件及其用法 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133411883 目 录 1. …

leetCode 213. 打家劫舍 II 动态规划 房间连成环怎么偷呢?

213. 打家劫舍 II - 力扣&#xff08;LeetCode&#xff09; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻的房屋装…

【Java 进阶篇】深入理解 SQL 聚合函数

在 SQL 数据库中&#xff0c;聚合函数是一组强大的工具&#xff0c;用于处理和分析数据。它们可以帮助您对数据进行统计、计算总和、平均值、最大值、最小值等操作。无论您是数据库开发者、数据分析师还是希望更好地了解 SQL 数据库的用户&#xff0c;了解聚合函数都是非常重要…

三个要点,掌握Spring Boot单元测试

单元测试是软件开发中不可或缺的重要环节&#xff0c;它用于验证软件中最小可测试单元的准确性。结合运用Spring Boot、JUnit、Mockito和分层架构&#xff0c;开发人员可以更便捷地编写可靠、可测试且高质量的单元测试代码&#xff0c;确保软件的正确性和质量。 一、介绍 本文…

(SAR)Sentinel-1影像自动下载

基于ASF网站提供的python代码&#xff0c;实现Sentinel-1影像的自动下载&#xff1b; 1、登录ASF网站 登录Sentinel-1影像ASF网站&#xff1a;https://search.asf.alaska.edu/&#xff1b; 点击网站最右侧Sign in图标&#xff0c;进行用户注册&#xff1b; 注册完用户之后&…

基于Vue+ELement实现增删改查案例与表单验证(附源码)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《ELement》。&#x1f3af;&#x1f3af; &#x1…

I2C外设

I2C的总结 I2C优点&#xff1a; 接口线少只有两根线&#xff0c;控制方式简单&#xff0c;通信速率较高&#xff1b; I2C 是飞利浦公司开发的两线式串行总线&#xff1b; I2C缺点&#xff1a; 硬件比较复杂&#xff0c;稳定性不太好&#xff0c;程序移植有点麻烦&#xff…

自定义v-resize指令并发布到NPM

自定义Vite库并发布到NPM 封装useResize 用于监听绑定元素的宽高变化&#xff0c;当元素宽高发生变化时触发回调并获取最新的宽高 新建项目 结合上面学到的 Hook 和 自定义指令封装一个监听元素宽高变化的指令&#xff0c;并发布到 npm 项目结构 useResize ├…

jQuery核心卷

目录 一.jQuery引用 二.jQuery语法 三.元素的属性 1.attr()方法 2.使用removeAttr()方法删除HTML元素的属性 3.使用text()方法设置HTML元素的文本内容 四.CSS元素控制 1.使用css()方法获取和设置css属性 2.与CSS类别有关的方法 3.获取和设置HTML元素的尺寸 4.获取和…

html 边缘融合加载

html 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>边缘融合加载</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {height: 100vh;padding-bottom: 80px;b…

No141.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【STM32】IAP升级00 预备知识

IAP&#xff08;In Application Programming&#xff09;简介 Flash够大的情况下&#xff0c;上电后的程序通过修改 MSP 的方式&#xff0c;可以在一块Flash上存在多个功能差异的程序。 IAP是为了在执行正常功能前&#xff0c;为了升级功能&#xff0c;提前运行的一段程序。这…

26608-2011 工业用回收一氯甲烷 学习笔记

声明 本文是学习GB-T 26608-2011 工业用回收一氯甲烷. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了工业用回收一氯甲烷的要求、试验方法、检验规则及标志、包装、运输、贮存及安全。 本标准适用于副产回收生产的工业用一氯甲…

一些杂题(9.23)

八月赛 A. Extra Large Knapsack 我的思路 是否可行只要看所有异或在一起是否为0就可以了 可行的方案只要有一个在第一个包里&#xff0c;剩下的都在第二个包里就可以了 注意&#xff1a;n1的时候不可行&#xff0c;要特判 代码 #include<bits/stdc.h> using name…