程序的编译、链接

目录

前言:

前置知识回顾

宏定义常量

宏定义语句

宏定义函数

条件编译

应用场景

编译过程概览

预编译阶段

编译阶段

 汇编阶段

 链接阶段


前言:

在ANSI C的任何一种实现中,存在两种不同的环境,第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令;第2种是执行环境,它用于实际执行代码,将磁盘中的可执行文件装载到内存中,CPU才能通过总线读取内存中的指令,才能真正执行程序;本文重点阐述程序的翻译坏境;

前置知识回顾

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro);
命名习惯: 宏名全部大写
//宏的声明:#define name( parament-list ) stuff
//其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中;
//注意:参数列表的左括号必须和宏名name紧邻;
//如果宏名与参数列表之间有任何空白存在,参数列表就会被解释为stuff的一部分;

宏定义常量

# define ROW 10            //宏定义整型常量
# define PI  3.14          //宏定义浮点型常量
# define STR "hello world" //宏定义字符串
int main()
{printf("%d %f %s\n", ROW, PI, STR);return 0;
}
运行结果:

宏定义语句

# define PRINTF printf("Hello Linux!\n");
int main()
{int i = 10;PRINTF;return 0;
}

运行结果:

宏定义函数

宏可以接收参数且不用指定参数类型;

# define ADD(x,y) ((x)+(y))
int main()
{int m = 10;int n = 10;float d1 = 4.5;float d2 = 5.5;printf("%d\n", ADD(m,n));printf("%f\n", ADD(d1, d2));return 0;
}

运行结果:

条件编译

编译程序时使用条件编译指令选择性的将一条语句/一组语句编译或者放弃;
//常见的条件编译指令
#if:    如果条件为真,则执行相应的操作;
#elif:   类似于else if的用法,当前面条件为假,再判断该条件是否为真,如果是真,则执行相应操作;
#else:   如果前面所有条件均为假,则执行相应操作;
#ifdef:  如果该宏已定义,则执行相应操作;
#ifndef: 如果该宏没有定义,则执行相应操作;
#endif : 结束对应的条件编译指令(不能省略);

应用场景

# define VERSION1 1
//# define VERSION2 2
int main()
{
#ifdef VERSION1printf("Hello Version1.0\n");
#elif VERSION2printf("Hello Version2.0\n")
#else printf("Hello Free Version");
#endifreturn 0;
}

运行结果:

//# define VERSION1 1
//# define VERSION2 2
int main()
{
#ifdef VERSION1printf("Hello Version1.0\n");
#elif VERSION2printf("Hello Version2.0\n")
#else printf("Hello Free Version\n");
#endifreturn 0;
}

运行结果:

编译过程概览

将一个.c文件翻译为可执行文件,需要经过预编译(prepressing) 、编译(compliation)、汇编(assernbly)、链接(linking)四个阶段;

预编译阶段

  • 头文件展开
  • 去掉注释
  • 宏替换
  • 条件编译
 //vim编辑器编写test.c文件# include <stdio.h># define M 100int main(){printf("%d\n",M);                                                                                                                           //printf("hello Linux!\n");//printf("hello Linux!\n");//printf("hello Linux!\n");printf("hello world!\n"); return 0;}

Linux环境使用选项 gcc -E test.c -o test.i

此条语句的含义为从现在开始进行程序的翻译过程,当预处理结束时,停止程序的翻译过程;

上图生成test.i文件,使用vim编辑器打开test.i文件;

注释被删除掉,宏定义的M被替换为100,使用选项 vim /usr/include/stdio.h 打开c标准库对比发现头文件被替换;

使用vim编辑器编写code.c代码,code.c代码使用条件编译指令;

//vim编辑器编写code.c代码
# define VERSION1 1
//# define VERSION2 2
int main()
{
#ifdef VERSION1printf("Hello Version1.0\n");
#elif VERSION2printf("Hello Version2.0\n")
#else printf("Hello Free Version\n");
#endifreturn 0;
}

编译阶段

1. 词法分析:词法分析器处理test.i文件,将字符串切割成一个个记号(mark)

      例如:sum=a+b;会产生五个记号:"sum" "=" "a" "+" "b"
2. 语法分析:语法分析器将产生的记号组织成一个个表达式,以表达式为节点,生成一颗语法树
3. 语义分析:语义分析器处理声明以及数据类型、给语法树的节点赋予数据类型
4. 中间代码:根据语法树生成中间代码,以上的步骤是硬件平台无关的,而中间代码之后的处理则需要根据程序运行的硬件平台来决定;
5. 代码生成器:代码生成器将中间代码转换成对应硬件平台的汇编代码test.s

Linux环境使用选项 gcc -S test.c -o test.s

此条语句的含义为从现在开始进行程序的翻译过程,当编译结束时,停止程序的翻译过程;

 汇编阶段

汇编器:汇编器根据 汇编指令与机器指令的对照表 将汇编代码翻译成机器指令,生成目标文件test.o;

目标文件由若干个段(section)组成,每个段中存放不同的内容;

目标文件中的基本段类型:文件头、代码段、数据段、bss段、常量段、段表、符号表、重定位表;

文件头:文件头位于目标文件开始位置,它定义了elf魔数,目标文件的属性、运行的软硬件平台、程序入口地址、段表的位置及长度、段的数量;

代码段:存放  机器指令

数据段:   存放 已经初始化的全局变量以及静态变量

常量段:存放  字符串常量以及被const修饰的变量

bss段: 存放  未初始化的全局变量以及静态变量所占用的内存大小

段表:    记录了目标文件中所有段的地址以及属性(读写or可执行)等信息;

符号表:记录与程序相关的所有符号(如变量、函数名),变量或者函数所对应的地址和属性

重定位表:重定位表用于指示需要进行重定位的指令或数据,记录了位置信息、长度以及对应的符号引用;

Linux环境使用选项 gcc -c test.c -o test.s

此条语句的含义为从现在开始进行程序的翻译过程,当汇编结束时,停止程序的翻译过程;

 链接阶段

链接器:合并输入的.o文件、确定符号内存地址、进行符号重定位,输出可执行文件;

 Linux环境使用选项 gcc test.c -o test.exe

 

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

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

相关文章

12.30 二叉树中等题

236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff…

yolov8实战第四天——yolov8图像分类 ResNet50图像分类(保姆式教程)

yolov8实战第一天——yolov8部署并训练自己的数据集&#xff08;保姆式教程&#xff09;_yolov8训练自己的数据集-CSDN博客在前几天&#xff0c;我们使用yolov8进行了部署&#xff0c;并在目标检测方向上进行自己数据集的训练与测试&#xff0c;今天我们训练下yolov8的图像分类…

【滑动窗口】C++算法:K 个不同整数的子数组

作者推荐 动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本 本题涉及知识点 滑动窗口 LeetCoe992 K 个不同整数的子数组 给定一个正整数数组 nums和一个整数 k&#xff0c;返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 …

【AI导师】利用Coding Agent完成AIGC编程

利用Coding Agent完成AIGC编程 一、前言二、Coding Agent三、1024code四、AI导师README项目初版功能定义代码结构设计方案函数方法设计方案迭代记录 一、前言 AI产品的发展确实在过去两年年中取得了显著进展&#xff0c;尤其是在编程领域。一开始&#xff0c;ChatGPT和类似的语…

前后端分离架构的特点以及优缺点

文章目录 一、前后端不分离架构(传统单体结构)1.1 什么是前后端不分离1.2 工作原理1.3 前后端不分离的优缺点1.4 应用场景 二、前后端分离架构2.1 为什么要前后端分离2.2 什么是前后端分离2.3 工作原理2.4 前后端分离的优缺点 参考资料 一、前后端不分离架构(传统单体结构) 首…

阿里后端实习二面

阿里后端实习二面 记录面试题目&#xff0c;希望可以帮助到大家 类加载的流程&#xff1f; 类加载分为三个部分&#xff1a;加载、连接、初始化 加载 类的加载主要的职责为将.class文件的二进制字节流读入内存(JDK1.7及之前为JVM内存&#xff0c;JDK1.8及之后为本地内存)&…

EBU7140 Security and Authentication(一)常见加密算法

前言 主要根据 EBU7140 课程内容整理&#xff0c;比较偏向应试~ Block1&#xff1a;介绍课程&#xff0c;传统加密方式。 Block2&#xff1a;公钥加密的原理和应用。 Block3&#xff1a;一些特定安全协议技术&#xff08;如防火墙 Kerberos身份验证协议等&#xff09;。 B…

【教学类-43-03】20231229 N宫格数独3.0(n=1、2、3、4、6、8、9) (ChatGPT AI对话大师生成 回溯算法)

作品展示&#xff1a; 背景需求&#xff1a; 大4班20号说&#xff1a;我不会做这种&#xff08;九宫格&#xff09;&#xff0c;我做的是小格子的&#xff0c; 他把手工纸翻过来&#xff0c;在反面自己画了矩阵格子。向我展示&#xff1a;“我会做这种&#xff01;” 原来他会…

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(15)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识&#xff08;14&#xff09; 1.3 PCI总线的存储器读写总线事务 1.3.4 PCI读写主存储器 前文已提到&#xff0c;由于本节内容较长&#xff0c;因此将后一部分内容放在本文中。 为…

Java多线程技术五——单例模式与多线程

1 概述 本章的知识点非常重要。在单例模式与多线程技术相结合的过程中&#xff0c;我们能发现很多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。本章的案例也充分说明&#xff0c;线程与某些技术相结合中&#xff0c;我们要考虑的事情会…

java注解和反射

java注解和反射 内置注解 Override 重写生命 Deprecated 已过时的方法&#xff0c;不推荐使用&#xff0c;可以使用 SuppressWarning 镇压警告&#xff0c;懂的都懂 元注解 作用&#xff1a;负责注解其他的注解 Target 描述注解的使用范围 Retention 描述注解的生命周期 Docu…

从座舱到跨域融合,老牌汽车零部件厂商如何破局数字化变革

当前&#xff0c;整个汽车供应链正在经历深层次的重构&#xff0c;传统零部件厂商必须加速“自我革新”。 在汽车“新四化”的巨变下&#xff0c;大量传统零部件濒临消失或者减少了需求&#xff0c;传统汽车零部件企业的相关业务开始日益萎缩&#xff0c;生存空间遭受不同程度…

我的128天之创作纪念日

目录 序 机缘 收获 日常 成就 憧憬 序 今天收到CSDN的一条消息推送&#xff0c;“初九之潜龙勿用 &#xff0c;不知不觉今天已经是你成为创作者的 第128天 啦。。。” 是啊&#xff0c;自今年8月24日开始写文章以来&#xff0c;时间过得好快&#xff0c;无论开心、痛苦…

51单片机之LED灯

51单片机之LED灯 &#x1f334;前言&#xff1a;&#x1f3ee;点亮LED灯的原理&#x1f498;点亮你的第一个LED灯&#x1f498;点亮你的八个LED灯 &#x1f4cc;让LED灯闪烁的原理&#x1f3bd; LED灯的闪烁&#x1f3d3;错误示范1&#x1f3d3;正确的LED闪烁代码应该是这样&am…

【开源】基于Vue+SpringBoot的公司货物订单管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 客户管理模块2.2 商品维护模块2.3 供应商管理模块2.4 订单管理模块 三、系统展示四、核心代码4.1 查询供应商信息4.2 新增商品信息4.3 查询客户信息4.4 新增订单信息4.5 添加跟进子订单 五、免责说明 一、摘要 1.1 项目…

4.26 构建onnx结构模型-Suqeeze

前言 构建onnx方式通常有两种&#xff1a; 1、通过代码转换成onnx结构&#xff0c;比如pytorch —> onnx 2、通过onnx 自定义结点&#xff0c;图&#xff0c;生成onnx结构 本文主要是简单学习和使用两种不同onnx结构&#xff0c; 下面以 Suqeeze 结点进行分析 方式 方法一…

three.js实现点击选中模型,模型描边高亮效果

射线投射器Raycaster通过.intersectObjects()判断模型是否选中EffectComposer.js进行后期处理&#xff0c;添加描边高亮效果 <template><div class"app"><div ref"canvesRef" class"canvas-wrap"></div></div> &…

Python面向对象编程 —— 类和异常处理

​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 1. 类 1.1 类的定义 1.2 类变量和实例变量 1.3 类的继承 2. 异常处理 2.1类型异常 2.…

【docker实战】安装tomcat并连接mysql数据库

本节用docker来安装tomcat&#xff0c;并用这个tomcat连接我们上一节安装好的mysql数据库 一、拉取镜像 [rootlocalhost data]# docker pull tomcat:8.5.69二、运行tomcat bitnami的tomcat的根目录在/opt/bitnami/tomcat/webapps下面&#xff0c;所以我们为了方便部署我们的…

Springboot整合MybatisPlus的基本CRUD

目录 前言1. 搭建项目2. 基本的CRUD 前言 发现项目框架是MybatisPlus的&#xff0c;由于个人使用该框架的CRUD比较少 对此学习过程中&#xff0c;从零到有开始搭建学习还是比较重要的&#xff0c;感悟会比较多 关于各个类的使用&#xff0c;可看如下文章&#xff1a; 剖析Ja…