程序的编译与链接(详解)

news2024/10/6 8:37:33

程序的编译与链接


本章内容如下:

1:程序的翻译环境与执行环境的介绍


2:详解程序的翻译环境(编译+链接)

  • 2.1预处理阶段干了啥
  • 2.2编译阶段干了啥
  • 2.3汇编阶段干了啥
  • 2.4链接阶段干了啥

3:预处理详解

  • 预定义符号的介绍
  • #define 的介绍(宏与标识符号)
  • #与##的介绍
  • 宏与函数的对比
  • #undef的介绍

4:条件编译


5:#include文件

  • #include<>与#include""的区别
  • 条件编译在头文件包含中的使用场景介绍

以上就是本文章所要介绍的大概内容,下面让我们一起来学习以上的知识点吧!

1:程序的翻译环境与执行环境

首先我们知道计算机是只能识别二进制的文件的,而我们平常所写的c语言文件并不能够被计算机所直接识别,所以才有了程序的翻译环境

所以简单的来说:
翻译环境:是将文本文件(c语言写的源代码文件)转化为计算
机所能识别的二进制文件。
执行环境:用于执行实际代码的环境。

关于执行环境的内容
1:首先每个可执行程序都必须先加载到内存当中去,这个步骤在有操作系统的环境中,由操作系统来完成的。
2:程序的执行便开始了。开始调用main函数
3:开始执行程序的代码,开辟对应的函数栈桢,用来存放局部变量和返回地址,同时也可以使用静态的内存,用来存储静态变量的值和地址
4:程序的终止。这个终止可以包括意外的终止和正常终止main函数。


2:详解程序的翻译环境(编译+链接)
首先我们需要了解的就是翻译环境包括两个部分,编译+链接。

而编译又包括3个阶段。
1:预处理阶段
2:编译阶段
3:汇编阶段

我们在vs2019这样的集成开发环境下并不能够区别这三个阶段到底干了啥事,所以我们采用在linux环境下来介绍。

首先我们先来介绍在linux环境下的三条指令:
1: gcc -E 要编译的文件 -o 生成的文件名
意思为:当编译器编译到预处理阶段完成后就停止对程序的编译,也就
是只完成编译的预处理阶段。
2:gcc -S 要编译的文件 -o 生成的文件名
意思为:当编译器编译到编译阶段完成后就停止对程序的编译,也就
是只完成编译的编译阶段。
3:gcc -c(小写) 要编译的文件 -o 生成的文件名
意思为:当编译器编译到汇编阶段完成后就停止对程序的编译,也就
是只完成编译的汇编阶段。

首先我们先写一段代码,然后在linux系统下看看这段代码在不同的阶段完成了什么事情。代码如下:

#include<stdio.h>

//定义一个宏常量
#define M 3
#define N 2


int main()
{
	//main函数体
	int a =2;
	int b =2;
	int c =a+b+M;
	printf("%d\n",c);
	printf("%d\n",N);
	return 0;
}

在这里插入图片描述

我们能够看到在预处理阶段完成后的文件中,代码量明显就增多了
从原本的10多行到现在的800多行,并且在源文件中本来有的注释
和定义的宏,在预处理阶段完成后,都消失了。
这也从侧面告诉了我们预处理阶段会干的事情如下:

预处理阶段会干的事情
1.#include头文件的展开
2. 预定义符号的替换
3. 去除注释

注意:所有预定义符号的替换都是在预处理阶段完成的。

然后我们在来观察在编译阶段会做的事情
在这里插入图片描述

上图就是我们经过编译阶段所形成的test.s这个文件,我们发现里面并不是我们能够读懂的c语言代码了,而变成了汇编指令了。

	所以在我们的编译阶段会进行如下的过程
	1.语法分析
	2.语义分析
	3.词法分析
	4.符号汇总

编译目的:将c语言代码转化为汇编代码,并且进行符号汇总。

我们再来看一看汇编阶段到底干了啥事>

在这里插入图片描述
我们发现经过汇编所形成的文件后,文件我们就看不懂了,因为此时的文件是二进制文件。

	汇编阶段会干的事情
	1.形成符号表
	2.将汇编代码转化为计算机能够识别的二进制代码
	其实在linux系统下,gcc所产生的目标.o文件,可执行程序,
	它的文件格式为ELF这种类型的文件格式来进行存储的,
	而在linux环境下,可以用readelf命令来读取这样的文件。

关于编译阶段符号汇总与汇编阶段形成符号表的意思

符号汇总,其实本质上来说就是统计文件中所使用的函数名,这些符号
而形成符号表的意思我们可以简单的理解为:将函数与它的地址看作整
体。在链接的时候在使用这张表
如下图的意思

在这里插入图片描述

这三个步骤的完成就标志着我们翻译环境的编译过程就完成了。

链接阶段:

	gcc 源文件 -o 形成文件名
	本质上来说链接阶段就是形成可执行程序的最后一步。
	链接阶段所干的事情:
	1.合并段表
	2.符号表的合并与重定位
	
	段表的意思为:我们的每个目标文件都是按照elf的文件格式进
	行排版的,而elf会将文件划分为很多段,每一段执行不同的功
	能,而我们在一个项目中可以有很多个源文件,每一个源文件生
	成的目标文件都会按照这种格式进行分段,所以在链接的时候我
	们将具有相同功能的代码,放在同一个段表内。
	符号表的合并也是将不同源文件所包含的同一种符号进行合并,
	重定位表示的是给符号确定正确的地址。

对于符号表,段表的理解可能不是什么非常清楚,大家可以去看<编译原理这本书>


3:预处理阶段详解
1.预定义符号的介绍
预定义符号以下的几个都是语言内置的
__FILE__  //进行编译的文件
__LINE__  //文件输出这个当前的行号
__DATE__  //文件被编译的日期
__TIME__  文件被编译的时间

在这里插入图片描述

2.#define定义的标识符与宏
#define定义的标识符语法  #define name  内容 (无;)
#define M 3   //在预处理阶段只要程序中有M 就替换为3
#define DOU double// DOU-->double 
#define reg register// reg--->register

#define定义的宏
#define的一个规定,可以将参数替换到文本中去,这种实现就叫做宏。
我们通过讲解2个宏来掌握宏,并且了解一些注意事项。

#define ADD(x,y) ((x)+(y))

我们通过图片来讲解上面的宏
在这里插入图片描述
3.#与##的作用

#:可以将宏的参数化为字符串
##:可以将宏参数进行合并

直接讲语法可能有点抽象,我们通过具体的代码来进行讲解

#define PRINT(N,formate) printf("the value of 
"#N" is "formate"\n",N)
int main()
{
	/*printf("hello ""world\n");
	printf("hello world\n");*/ //这两种情况是一样的
	int a = 10;
	int b = 15;
	PRINT(a,"%d");
	PRINT(b,"%d");
	float c = 3.14f;
	PRINT(c, "%f");

	return 0;
}

在这里插入图片描述

//##在宏中的作用是将两个常数符号连接起来
#define CAT(x,y) x##y
int main()
{
	int c110 = 2024;

	int a = CAT(c, 110);
	printf("%d\n", a);


	return 0;
}

在这里插入图片描述
4.宏与函数的区别:

  1. 宏是直接对代码块进行替换的,函数则需要去掉用相应的函数。
  2. 宏不能进行调试,函数可以。
  3. 宏不能进行递归
  4. 宏没有函数参数类型的检查,可能比较危险
  5. 代码长度宏需要进行替换,所以长度大于函数的长度
  6. 运行效率 宏>函数
  7. 宏替换时,可能会涉及到操作符的优先级的问题

其次在好的编程习惯来讲,宏名一般全是大写,而函数不需要

5:#undef
作用:当我们在以后的代码中不需要在使用对应的宏的时候,我们可以用#undef 来去除对应的宏

命令行定义:我们可以在编译的过程中定义符号,
命令为 : gcc 编译文件 -D 符号定义

5:条件编译
在编译一个程序的时候我们需要放弃一条语句或者一组语句是非常容易
的,因为我们有条件编译指令
常见的条件编译指令有以下一些:
如:
1.单分支
#if 常量表达式
....
#endif
2.多分支
#if 常量表达式
........
#elif 常量表达式
......
#else
......
#endif
这两种条件编译的指令当表达式为真时就会保留对应的代码,比如说:

#define x 10
int main()
{
	
#if x==10
	printf("haha\n");
#elif x==2
	printf("hehe\n");
#else
	printf("heihei\n");
#endif

	return 0;
}

我们在linux系统的环境下进行查看。
在这里插入图片描述
应为我们定义了x=10,所以保留了haha


如果定义了符号则保留代码
#ifdef  symbol
......
#endif

//如果没有定义则保留代码
#ifndef symbol
....
#endif
这个语句是看我们定义了符号没,只要定义了就保留,我们在linux
下看一看

在这里插入图片描述


5#include文件的包含

1.#include<> 与#include“”文件的区别

		#include<>,一般来说这是包含库里面的文件,而""是包
		含我们自己所写的头文件。
		这两者的不同存在与:#include<>会直接去指定的标准路径
		下去进行查找。
		而#include“”会先在与源文件相同的路径下查找,如果没有
		找到则会想寻找库函数头文件的方式到标准的指定文件下去
		进行查找。
  1. 条件编译在头文件包含中的使用场景介绍
    我们知道当我们有许多源文件和头文件的时候,因为我们会包含对应的头文件,可能会导致在一个文件中可能会出现引入多个相同的头文件,而在预处理阶段头文件又会进行展开,导致代码的长度会持续的增加,所以这时候就需要我们的条件编译出场了
#ifndef __TEST.H__
#define __TEST.H__
#endif
或者
#pragma once
这样就可以避免头文件的多次包含了。

到这里本章就结束了,感谢大家的观看。

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

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

相关文章

对象的内部结构

在HotSpot 虚拟机里&#xff0c;对象在堆内存中的存储布局可以划分为三个部分&#xff1a;对象头&#xff08; Header &#xff09;、实例数据&#xff08;Instance Data &#xff09;和对齐填充&#xff08; Padding &#xff09;。 对象头 Mark Word&#xff08;标记字段&a…

RK3568驱动指南|第八篇 设备树插件-第72章 设备树插件语法和编译实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

[element-ui] el-dialog 中的内容没有预先加载,因此无法获得内部元素的ref 的解决方案

问题描述 在没有进行任何操作的时候&#xff0c;使用 this.$refs.xxxx 无法获取el-dialog中的内部元素&#xff0c;这个问题会导致很多bug. 官方解释&#xff0c;在open事件回调中进行&#xff0c;但是open()是弹窗打开时候的会调&#xff0c;有可能在此处获取的时候&#xff…

教师授课技巧

一名教师&#xff0c;授课技巧是提高教学效率和质量的关键。以下是几个实用的授课技巧&#xff0c;可以帮你更好的传授知识&#xff0c;激发学习兴趣。 一、做好课前准备 课前准备是授课技巧的重要环节。认真备课&#xff0c;熟悉教材内容&#xff0c;制定教学计划&#xff0c…

redis运维(二十一)redis 的扩展应用 lua(三)

一 redis 的扩展应用 lua redis加载lua脚本文件 ① 调试lua脚本 redis-cli 通过管道 --pipe 快速导入数据到redis中 ② 预加载方式 1、错误方式 2、正确方式 "案例讲解" ③ 一次性加载 执行命令&#xff1a; redis-cli -a 密码 --eval Lua脚本路径 key …

【Docker】Docker与Kubernetes:区别与优势对比

前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。   kubernetes&#xff0c;简称K8s&a…

MybatisPlus集成baomidou-dynamic,多数据源配置使用、MybatisPlus分页分组等操作示例

文章目录 pom配置示例代码 pom <dependencies><!--mybatisPlus集成SpringBoot起步依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version>&l…

荆涛演唱歌曲《老板的孤独》:孤独中的坚韧与担当

歌手荆涛演唱的《老板的孤独》不仅是一首歌&#xff0c;更是一种情感的宣泄和表达。歌曲中表达了老板们在面对压力、孤独和困难时&#xff0c;依然坚持、积极向前的坚韧精神。每一句歌词都充满了对生活的深刻理解和感悟&#xff0c;以及对团队、家人的深深牵挂。 一、欣喜时要h…

【Netty专题】Netty调优及网络编程中一些问题补充(面向面试学习)

目录 前言阅读对象阅读导航笔记正文一、如何选择序列化框架1.1 基本介绍1.2 在网络编程中如何选择序列化框架1.3 常用Java序列化框架比较 二、Netty调优2.1 CONNECT_TIMEOUT_MILLIS&#xff1a;客户端连接时间2.2 SO_BACKLOG&#xff1a;最大同时连接数2.3 TCP_NODELAY&#xf…

spring-framework-5.2.25.RELEASE源码环境搭建

环境准备 spring-framework-5.2.25.RELEASEIntelliJ IDEA 2022.3.1java version “11.0.20” 2023-07-18 LTSGradle 5.6.4java version “1.8.0_301” 下载spring-framework-5.2.25.RELEASE源码 git clone https://gitee.com/QQ952051088/spring.git cd spring gradlew buil…

车载通信架构 —— 传统车内通信网络FlexRay(较高速度高容错、较灵活拓扑结构)

车载通信架构 —— 传统车内通信网络FlexRay(较高速度高容错、较灵活拓扑结构) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,…

Mysql 解决Invalid default value for ‘created_at‘

在mysql版本 8.0 和 5.* 之间数据互导的过程中&#xff0c;老是会出现各种错误&#xff0c;比如 这个created_at 一定要有一个默认值&#xff0c; 但是我加了 default null 还是会报错&#xff0c;于是对照了其他的DDL 发现&#xff0c;需要再加 null default null 才行&#…

Element-UI Upload 手动上传文件的实现与优化

文章目录 引言第一部分&#xff1a;Element-UI Upload 基本用法1.1 安装 Element-UI1.2 使用 <el-upload> 组件 第二部分&#xff1a;手动上传文件2.1 手动触发上传2.2 手动上传时的文件处理 第三部分&#xff1a;性能优化3.1 并发上传3.2 文件上传限制 结语 &#x1f38…

软件测试 | 解决‘pip‘ 不是内部或外部命令,也不是可运行的程序或批处理文件

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

车载通信架构 —— 传统车内通信网络LIN总线(低成本覆盖低速场景)

车载通信架构 —— 传统车内通信网络LIN总线(低成本覆盖低速场景) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是…

前缀和+哈希表——974. 和可被 K 整除的子数组

文章目录 &#x1fa81;1. 题目&#x1f3a3;2. 算法原理&#x1fa84;解法一&#xff1a;暴力枚举&#x1fa84;解法二&#xff1a;前缀和 哈希表 ⛳3. 代码实现 &#x1fa81;1. 题目 题目链接&#xff1a;974. 和可被 K 整除的子数组 - 力扣&#xff08;LeetCode&#xff0…

【室内定位系统源码】UWB超宽带定位技术的特点和应用前景

uwb人员、物品定位系统源码&#xff0c;智慧工厂人员安全管理定位&#xff0c;高精度定位系统源码 UWB超宽带定位技术概念&#xff1a; 超宽带无线通信技术&#xff08;UWB&#xff09;是一种无载波通信技术&#xff0c;UWB不使用载波&#xff0c;而是使用短的能量脉冲序…

QEMU Guest Agent本地提权漏洞处理(CVE-2023-0664)

一、漏洞描述 QEMU Guest Agent&#xff08;qga&#xff09;类似于vmware中的 vmtools&#xff0c;相关安全报告显示它的Windows版本安装程序存在本地提权高危漏洞&#xff08;CVE-2023-0664&#xff09;&#xff0c;攻击者可利用该漏洞进行本地权限提升&#xff0c;获得SYSTE…

【图数据库实战】图数据库基本概念

1、图数据库的概念 维基百科图书库的概念&#xff1a; 在计算机科学中&#xff0c;图数据库&#xff08;英语&#xff1a;graph database&#xff0c;GDB&#xff09;是一个使用图结构进行语义查询的数据库&#xff0c;它使用节点、边和属性来表示和存储数据。该系统的关键概念…

2024年天津天狮学院专升本护理学专业《内外科护理学》考试大纲

天津天狮学院2024年护理学专业高职升本入学考试《内外科护理学》考试大纲 一、考试性质 《内外科护理学》专业课程考试是天津天狮学院护理专业高职升本入学考试的必考科目之一&#xff0c;其性质是考核学生是否达到了升入本科继续学习的要求而进行的选拔性考试。《内外科护理学…