软硬链接和动静态库

为什么一定要提供路径呢?

因为要根据路径找到文件

一切与路径相关的问题都是方便用户去访问文件

软硬链接

给我康康

软链接是这样的:

ln -s file_target1.txt file_soft.link

 

软链接有独特的innode

这是硬链接:

ln file_target2.txt file_hard.link

 

特征及使用场景

软链接是一个独立的文件,因为有独立的innode,软链接内容包含目标文件对应的路径字符串

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件

软链接像是Windows中的快捷方式(用绝对路径形成的,指向可执行程序)

软链接删掉不会影响目标文件(删快捷方式不影响应用本体)

软链接有何用呢?

就是快捷方式的作用

软链接为何要包含路径呢?路径唯一哎

硬链接不是一个独立的文件,硬链接的innode编号和文件一样,硬链接是一个文件名和innode的映射关系,建立硬链接就是在指定目录下,添加一个新的文件名和innode number的映射关系,指针指向同一个文件属性,指针计数为2

硬链接相当于重命名,属性中有一列硬链接数,文件的磁盘及引用计数:有多少文件名字符串通过innode指向文件,当引用计数为0时文件才相当于删除文件

定位一个文件只有两种方式:

1.通过路径

2.直接找到目标文件的innode

 

想必你已看清这个号和目录的关系

 任何一个目录在刚开始新建的时候,引用计数一定是2

目录A内部新建一个目录,会让A目录的引用计数自动+1

一个目录内部有几个目录:A引用计数-2

构建Linux的路径结构,让我们可以使用.和..来进行路径定位

Linux系统中,不允许给目录建立硬链接

文件名是固定的,所有的系统指令在设定的时候可以知道.和..的作用

.和..都删不掉(如果你在目录内部是删除不了目录的)

《乌申克的救赎》

一般用硬链接做文件备份

打开的文件:内核、内存

没有被打开的文件和磁盘、文件系统有关

文本写入是语言的概念(缓冲区),二进制写入

int a = 1234567;        //二进制写入
1234567 -> "1234567"    //文本写入

谁转呢?

以文本方式写入?

 

C语言提供的函数转啊

 由库函数转

动态库和静态库

我们用过C、C++的标准库

strerror,strstr、STL...

 这是C标准库:

 

#include<iostream>
#include<string>int main()
{std::string name = "hahaha";std::cout << name << std::endl;return 0;
}

 这是C++标准库

 Linux中.so是动态库,.a是静态库

动态库是系统公有的资源

绝大部分的指令都是用C写的

Windows动态库:.dll,.lib

游戏玩家有福啦

是什么

x.o和y.o和z.o。。。这种被称为可重定位目标文件,他们链接后就形成可执行程序

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库

动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码

一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码,在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)

动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间

操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间

/add.h/
#ifndef __ADD_H__
#define __ADD_H__ 
int add(int a, int b);
#endif // __ADD_H__
/add.c/
#include "add.h"
int add(int a, int b)
{return a + b;
}/sub.h/
#ifndef __SUB_H__
#define __SUB_H__ 
int sub(int a, int b);
#endif // __SUB_H__
/add.c/
#include "add.h"
int sub(int a, int b)
{return a - b;
}///main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"int main(void)
{int a = 10;int b = 20;printf("add(10, 20)=%d\n", a, b, add(a, b));a = 100;b = 20;printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
}

 一个小故事:

励志轩是一位学计算机的大学牲,

她有位舍友名为墨墨酱,她俩正在课设阶段,课设内容是完成库的编写

励志轩听完老师的要求直呼稳勒稳勒

墨墨酱找到励志轩,说她不会能不能帮帮她

但是励志轩想的是,帮肯定是要帮的,但是源文件肯定不能一毛一样

于是励志轩采取了一个措施:

gcc -c mystdio.c

 最终把这个编译完后的mystdio.o给了墨墨酱

励志轩打的算盘是,反正老师验收的时候是直接让跑代码,这样太容易蒙混过关了

函数方法的声明都放到头文件中

于是墨墨酱只需要编一个test.c测试一下运行就好勒:

#include"mymath.h"
#include"mystdio.h"
#include<stdio.h>
#include<string.h>int main()
{int a = 10;int b = 20;printf("%d+%d=%d\n", a, b, myAdd(a, b));myFILE* fp = my_fopen("./myfile.txt", "w");if (fp == NULL){return 1;}const char* message = "要不要出去玩...\n";my_fwrite(fp, message, strlen(message));my_fclose(fp);return 0;
}

什么?你说接口怎么实现的?那不关我的事啊宝

我只需要

gcc test.o mymath.o mystdio.o -o myexe

然后运行就好勒

游戏界面请认真辨别: 

 

 

言归正传: 

 

从这个样子再变成这样:

 

 

 头文件是一个手册,提供函数的声明,告诉用户怎么用

于是墨墨酱顺利蒙混过关咯

老师又发布了新指令,《关于我的老师让我大一就提供一百个源文件这件事》

于是励志轩还是老样子,把.o给了墨墨酱

但是墨墨酱拷丢了一两个,怎么编译都过不去就很难受

然后励志轩就干脆把那一百多个文件打包准备给墨墨酱传过去

紧接着就传来一声

“且慢!”

“我不会解压”

“啊?”

好吧。。。那只能献出这一招:

ar -rc libmyc.a *.o

 这是把源文件全打包,直接用就好,不需要解包

只不过在编译的时候需要把它也带上ww:

gcc main.c libmyc.a

 所谓的库文件就是把所有的.o打包

为什么

那为什么要有这个捏?

为了爱与和平

及提高开发效率

ar是gnu归档工具,rc表示replace and create(存在就替换,不存在就打包)

库的名字去掉点后缀只有myc

但是不仅墨墨酱想用啊,暖暖,燃燃子...励志轩的很多亲友都想用

于是励志轩拉了个群,把自己打包好的.tgz放到群文件里

谁想用谁用吧

要把库安装到系统中:把自己的头文件拷贝到系统头文件的搜索路径下

把源文件拷贝到系统源文件的搜索路径下

高攀上了:

 但是安装后编译又会发现编不过去

就是因为,,,编译器默认只认识C、C++的库

第三方提供的库编译器是不ins的

那怎么介绍它们认识啊?

gcc test.c -llibmyc.a

还是编不过啊

那怎么办啊

我要的是真名,要这样:

gcc test.c -lmyc

 但是还是不建议非官方的安装到库里(太矬了)

库的安装和卸载都是改变系统指定的库

如果不安装还想在当前目录下用该怎么做呢??

可以这样告诉gcc搜索头文件的额外路径:

gcc test.c -I ./mylib/include/

 但是还有对应的源文件怎么办捏?

这样就是顺便找一下库:

gcc main.c -I ./mylib/include/ -L ./mylib/lib

 我都指定路径了能不能放过我

你指定的目录很多库啊,链接哪个库?

gcc test.c -I ./mylib/include/ -L ./mylib/lib -lmyc

 -I:指定自定义头文件路径(这是i大写)

-L:指定用户自定义库文件路径

-l:指定执行的第三方库(这是l)

头文件制定了哦,在源代码里面就指定了呀,如果想要编译的时候不指定头文件路径,那在源码里做改动也是可以的:

#include"mylib/include/mymath.h"
#include"mylib/include/mystdio.h"
#include<stdio.h>
#include<string.h>int main()
{int a = 10;int b = 20;printf("%d+%d=%d\n", a, b, myAdd(a, b));myFILE* fp = my_fopen("./myfile.txt", "w");if (fp == NULL){return 1;}const char* message = "要不要出去玩...\n";my_fwrite(fp, message, strlen(message));my_fclose(fp);return 0;
}

 gcc在默认编译的时候是动态链接的

可是我不是已经指定了相应的库吗?为何ldd之后不会显示出我指定的库呢?

一点都不酷

 

静态链接需要加上选项-static

但是-static是强制的静态链接,就是全部都需要是静态链接

而不加是有动态库就用,没有动态库的话静态库也能用

会拷贝到可执行程序里

编译期间告诉了gcc和g++所以编过去了,但是没告诉操作系统所以找不到,我们需要给动态库建立软链接,这样就都能找到咯

有个环境变量:

echo $LD_LIBRARY_PATH

 

这样配置环境变量以后就再不会重新加载咯 

 

也是为了碟醋包了盘饺子 

动态库要在程序运行的时候找到动态库加载并运行

静态库在编译期间已经在库中的代码拷贝到可执行程序的内部了,所以加载和库无关咯

综上就是:

1.安装的系统

2.建立软链接

3.命令行导入环境变量

4.修改.bashrc配置文件,让环境变量永久生效

还有个方法:

ls /etc/ld.so.conf.d

 

可以把要用的库的链接放到这个配置文件下 

需要创建一个文件,后缀不能变

touch happy.conf

 动态库的绝对路径贴进去

就完事勒

这是第五种方法,任您选择~

-static的意义是强制进行静态链接,要求我们链接的任何库都必须提供对应的静态库版本

怎么办

怎么生成静态库捏?

ar -rc libmymath.a add.o sub.o 

 ar是gnu归档工具,rc表示(replace and create)

这是查看静态库的目录列表:

ar -tv libmymath.a 

t:列出静态库中的文件                 v:verbose 详细信息  

这是指定:

gcc main.c -L. -lmymath

 -L 指定库路径 -l 指定库名 测试目标文件生成后,静态库删掉,程序照样可以运行

库的搜索路径:

从左到右搜索-L指定的目录

由环境变量指定的目录 (LIBRARY_PATH)

由系统指定的目录:

/usr/lib

/usr/local/lib

怎样生成动态库捏? 

这是gcc、g++,生成共享库格式:

gcc -shared *.o -o libmyc.so

所谓的库文件,本质就是把.o打包成-FPIC

产生位置无关码:

gcc -fPIC -c mystdio.c

 如果我们使用别人的库

别人会给我们提供一批头文件+一批库文件(.so,.a)

使用动态库的编译选项:

l:链接动态库,只要库名即可(去掉lib以及版本号)

L:链接库所在的路径.

 系统有很多的库,他们通常由一组相互关联的用来完成某项常见工作的函数构成(比如用来处理屏幕显示情况的函数:ncurses库):

yum install -y ncurses

nothing to do:

 再装个开发环境:

yum install -y ncurses-devel

 

耶耶:

可以借助这个库写个窗口小程序:

#include <ncurses.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>#define DELAY 100000int main() {int x, y, maxX, maxY; //蛇头的位置和终端窗口的大小int direction = KEY_RIGHT; //方向int snakeLength = 5; //蛇的长度int snakeX[100], snakeY[100]; //蛇身的位置int foodX, foodY; //食物的位置int score = 0; //得分int gameOver = 0; //游戏结束标志// 初始化ncurses库initscr();noecho();curs_set(0);keypad(stdscr, TRUE);timeout(0);// 获取终端窗口的大小getmaxyx(stdscr, maxY, maxX);// 初始化蛇的初始位置和长度x = maxX / 2;y = maxY / 2;for (int i = 0; i < snakeLength; i++) {snakeX[i] = x - i;snakeY[i] = y;}// 生成食物的初始位置srand(time(NULL));foodX = rand() % maxX;foodY = rand() % maxY;// 游戏循环while (!gameOver) {clear();// 绘制蛇for (int i = 0; i < snakeLength; i++) {mvprintw(snakeY[i], snakeX[i], "O");}// 绘制食物mvprintw(foodY, foodX, "*");// 显示分数mvprintw(0, 0, "Score: %d", score);// 移动蛇的位置int nextX = snakeX[0];int nextY = snakeY[0];switch (direction) {case KEY_UP:nextY--;break;case KEY_DOWN:nextY++;break;case KEY_LEFT:nextX--;break;case KEY_RIGHT:nextX++;break;}// 检查是否吃到食物if (nextX == foodX && nextY == foodY) {score++;snakeLength++;foodX = rand() % maxX;foodY = rand() % maxY;} // 移动蛇的身体for (int i = snakeLength - 1; i > 0; i--) { //后一节移动到前一节的位置snakeX[i] = snakeX[i - 1];snakeY[i] = snakeY[i - 1];}// 更新蛇头位置snakeX[0] = nextX;snakeY[0] = nextY;// 检查游戏结束条件//检查是否越界if (nextX < 0 || nextX >= maxX || nextY < 0 || nextY >= maxY) {gameOver = 1;}//检查是否撞到自己的身体for (int i = 1; i < snakeLength; i++) {if (snakeX[i] == nextX && snakeY[i] == nextY) {gameOver = 1;}}// 刷新屏幕refresh();// 延迟一段时间usleep(DELAY);// 获取用户输入int key = getch();switch (key) {case KEY_UP:case KEY_DOWN:case KEY_LEFT:case KEY_RIGHT:direction = key;break;case 'q':gameOver = 1;break;}}// 清理并退出ncurses库endwin();printf("Game Over! Your score: %d\n", score);return 0;
}

一个之前就遇到的报错,虽然我可能还是不知道为什么?

可能加上gnu之后支持的语法变多了?

gcc -Wall calc.c -o calc -lm

 -lm表示要链接libm.so或者libm.a库文件

可执行程序和地址空间

访问动静态库本质也是访问文件

动态库加载和静态库无关

动态库本质是文件,存在磁盘上

加载到内存后要通过页表映射到对应的mm_struct中的共享区

所以可以访问共享区的代码(使用动态库)

 

动态库不一定只用于一个进程

不需要再加载到系统当中

动态库在加载之后,要映射到当前进程的堆栈之间的共享区

我们的可执行程序,编译成功,没有加载运行,那二进制代码中有地址吗?

#include<stdio.h>int Sum(int top)
{int i = 1;int ret = 0;for (; i <= top; i++){ret += i;}return ret;
}int main()
{int top = 100;int result = Sum(top);printf("result:%d\n", result);return 0;
}

写一份代码就知道嘞

 转成反汇编:

objdump -S code > code.s

我们形成的可执行程序里面有地址

代码在编译完之后都有对应的地址

所以直接看源代码不用加载运行,可以在大脑中运行程序

在Linux中形成的可执行程序是ELF格式的

二进制有对应的固定格式

elf为可执行程序的头部,涵盖可执行程序的属性

 可执行车行徐编译后悔形成很多汇编语句,每条汇编语句会有对应的地址

如何对每条语句进行编址捏?

就是0000000.....FFFFFFFF(平坦模式)

我们认为这是虚拟地址

地址有对应的种类

相对编址=地址+偏移量

ELF+加载器就称为各个区域的起始和结束地址,main函数的入口地址

进程=内核数据结构+代码和数据

进程在创建时是先形成内核数据结构,再加载代码和数据

创建地址空间

mm_struct是结构体对象,有成员变量

在进行初始化的时候

初始值从哪里来捏?

从可执行程序来捏

虚拟地址空间是一套设计标准,OS,编译器,加载器都要支持

代码也是数据,加载到内存中要有自己的物理地址

故事从main函数入口地址开始

CPU内存在寄存器pc指针,pc指针保存的是正在执行的下一指令的地址(虚拟地址):pc指向哪里,CPU就去执行哪里的代码

虚拟地址在左侧,物理地址在右侧,构建相对的映射

永远不会凉的群,全是应声虫:

CPU开始运行咯

pc指针告诉CPU(指哪打哪)

call指令里面的也是虚拟地址

库的编址和可执行程序的方式也差不多

objdump -S libmyc.so > test.s

 

 库被映射到了什么位置捏?

一点都不影响哎

库原则上加载到堆上的任意位置都能工作

与地址无关码

只要映射完,虚拟地址随便变

改的只是虚拟地址,拿到偏移量还是能访问,来回跳转实现函数调用

库函数调用也是在地址空间内来回跳转

在操作系统中同时存在非常多的库

OS可以让进程知道库有没被加载

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Redis】缓存三大问题与缓存一致性问题

缓存三大问题 缓存穿透 缓存穿透是指用户查询的数据在缓存和数据库中都不存在&#xff0c;导致每次请求都会直接落到数据库上&#xff0c;增加数据库负载。 解决方案 1&#xff09;参数校验 一些不合法的参数请求直接抛出异常信息返回给客户端。比如查询的数据库 id 不能小于…

python3.10安装geopandans实战笔记

1.geopandans安装所需软件库版本 python3.10 GDAL-3.4.3-cp310-cp310-win_amd64.whl【手动下载】 Fiona-1.8.21-cp310-cp310-win_amd64.whl【手动下载】 shapely-2.0.2-cp310-cp310-win_amd64.whl【手动下载】 pyproj 手动下载地址&#xff1a;https://download.csdn.net/down…

Unity入门5——材质

创建材质 点击Assets → Create → Material&#xff0c;得到一个默认材质球的副本。 使用材质 直接把材质球拖拽到物体上&#xff0c;或设置mesh renderer组件下的Materials 数组中第一个元素

html+css网页设计公司网站模版3个页面 无js 静态页面

htmlcss网页设计公司网站模版3个页面 无js 静态页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源…

iOS弱引用

背景&#xff1a;在面试过程中被问到如果两个对象已经发生循环引用了&#xff0c;该如何将他们剪断&#xff0c;在运行态的时候。 由于这个场景比较抽象&#xff0c;我理解面试官是希望我通过运行时的方法和方式来解决循环引用。 解决方案一: 重写setter用关联对象来实现wea…

数据库规范化设计 5大基本原则

规范化设计原则是数据库设计的基本原则&#xff0c;有助于减少数据冗余&#xff0c;提高数据一致性和完整性&#xff0c;简化数据管理&#xff0c;增强数据安全性&#xff0c;对整个开发项目至关重要。而缺乏规范化设计会导致数据冗余&#xff0c;增加存储成本&#xff0c;引发…

java 如何查看jar版本冲突,如何查看哪个模块依赖冲突,idea查看jar包冲突

1. idea 下载插件&#xff1a; 2. 如上图所示&#xff0c;下载Maven Helper, 注意是maven helper 不是别的 3.重启idea 4.点击pom文件&#xff0c;然后点击如图所示&#xff1a; 5. 如此即可查到&#xff0c;某个jar包 都有哪个模块依赖&#xff0c;使用的什么版本&#xff0…

【JavaEE】定时器

目录 前言 什么是定时器 如何使用java中的定时器 实现计时器 实现MyTimeTask类 Time类中存储任务的数据结构 实现Timer中的schedule方法 实现MyTimer中的构造方法 处理构造方法中出现的线程安全问题 完整代码 考虑在限时等待wait中能否用sleep替换 能否用PriorityBlo…

RISC-V竞赛|第二届 RISC-V 软件移植及优化锦标赛报名正式开始!

目录 赛事背景 赛道方向 适配夺旗赛 优化竞速赛 比赛赛题&#xff08;总奖金池8万元&#xff01;&#xff09; &#x1f525;竞速赛 - OceanBase 移植与优化 比赛赛程&#xff08;暂定&#xff09; 赛事说明 「赛事背景」 为了推动 RISC-V 软件生态更快地发展&#xff0…

收银系统源码-连锁店版本

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 私有化独立部署/全开源源码&#xff0c;系统开发语言&#xff1a; 核心开发语言: PHP、HTML…

【vue3】【elementPlus】【黑暗模式】

从创建vue3项目到引入elementPlus组件并设置黑暗模式 1.创建vue3项目&#xff1a; npm init vuelatest1.1 根据需求定制项目插件&#xff1a; 2.引入elementPlus组件&#xff1a; npm install element-plus --save2.1 如图注册全局elementPlus组件&#xff1a; ------------…

SPSS、Python员工满意度问卷调查激励保健理论研究:决策树、随机森林和AdaBoost|附代码数据

全文链接&#xff1a;https://tecdat.cn/?p37293 原文出处&#xff1a;拓端数据部落公众号 在深入了解公司当前的实际情况和员工内心真实想法的基础上&#xff0c;我们旨在从专业视角出发&#xff0c;为企业在组织管理方面的不足进行诊断&#xff0c;并进行全面审视。 为了…

vue实现PC端图片放大缩小可鼠标拖动,鼠标滚轮控制放大缩小完整代码付效果图

vue实现图片放大缩小可鼠标拖动&#xff0c;鼠标滚轮控制放大缩小完整代码付效果图 效果图&#xff1a; 创建一个ImageViewer 组件&#xff0c;并且在当前页面引用完整代码如下&#xff1a; 代码引用&#xff1a; <template><view><image-viewer :imageUrl&q…

2024年必备技能:智联招聘岗位信息采集技巧全解析

随着大数据时代的发展&#xff0c;精准定位职业机会成为程序员求职的关键。本文将深入解析如何利用Python高效采集智联招聘上的岗位信息&#xff0c;助你在2024年的职场竞争中脱颖而出。通过实战代码示例&#xff0c;揭示网络爬虫背后的秘密&#xff0c;让你轻松掌握这一必备技…

苹果应用程序清理卸载工具:App Cleaner Uninstaller Pro for Mac

App Cleaner & Uninstaller Pro 是一款专为 Mac OS X 操作系统设计的应用程序清理和卸载工具。这款软件的主要功能是帮助用户彻底删除不需要的应用程序、插件和残留文件&#xff0c;从而释放磁盘空间并提高系统性能。 特点和优势&#xff1a; 彻底卸载应用程序&#xff1a;…

历代文学-技术生态-总体介绍

1. 历代文学简介 历代文学&#xff08;https://literature.sinhy.com/#/literature?__c1000&#xff0c;微信小程序可直接搜索“历代文学”&#xff09;是一个由两个人&#xff08;一个后端和一个前端&#xff09;开发的文学网站&#xff0c;是一个收录从古到今、以及古今中外…

几款设计师必备的AI抠图软件工具分享给你!

前言 在图像处理领域&#xff0c;抠图是一项基本而关键的技能。传统上&#xff0c;PS是作为抠图的首选工具&#xff0c;但其操作复杂性往往令初学者望而却步。幸运的是&#xff0c;随着AIGC技术的发展&#xff0c;现在有多款AI软件和在线网站能够以更简单、快捷的方式完成抠图…

VS+Qt+C++点云PCL三维显示编辑系统

程序示例精选 VSQtC点云PCL三维显示编辑系统 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《VSQtC点云PCL三维显示编辑系统》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易…

【wiki知识库】08.添加用户登录功能--后端SpringBoot部分

目录 一、今日目标 二、SpringBoot后端实现 2.1 新增UserLoginParam 2.2 修改UserController 2.3 UserServiceImpl代码 2.4 创建用户上下文工具类 2.5 通过token校验用户&#xff08;重要&#xff09; 2.6 创建WebMvcConfig 2.7 用户权限校验拦截器 一、今日目标 上篇…

【大模型】大模型指令微调的“Prompt”模板

文章目录 一、微调数据集格式二、常用的指令监督微调模板2.1 指令跟随格式&#xff08;Alpaca&#xff09;2.2 多轮对话格式&#xff08;ShareGPT&#xff09;2.3 其他形式2.4 常见模板 参考资料 一、微调数据集格式 在进行大模型微调的过程中&#xff0c;我们会发现“Prompt”…