LINUX入门篇【6】----第一个LINUX小程序---进度条及相关知识讲解

news2024/11/23 9:18:20

前言:

本篇我们将开始尝试构建我们的第一个LINUX的小程序----进度条作为一个十分常见的程序,在我们之后的工程实践中也是需要多次运用,但是介于我们目前还没有去学习网络等方面的知识,没法独立的去利用程序去下载一个真正的程序,自然没法根据程序去进行一个真实的下载环境,但是我们依旧可以拿出一个模拟下载的进度条程序。

1.前期预备知识讲解:

1.自动化构建代码:

让我们先想想我们在使用VS的时候的一些细节:我们只需要点击重新生成解决方案就可以直接直接重新编译我们当前的代码,而且是多个文件一起编译,但是在vim中我们对于多个文件,必须一个一个去gcc/g++,这就非常麻烦和繁琐,所以我们要寻找一种方法让我们的vim编译器也可以做到只需要一次指令就可以同时将多个文件一起编译,在这里,我便要引入我们的make和makefile.
首先,make是指令,而makefile是我们需要创建的一个不能改变名字的一个文件,你可以这样理解makefile:它是一个在当前目录下存在的一个具有特定格式的文本文件。
我们首先要创建一个makefile文件,注意,我们创建的时候名字必须是Makefile/makefile这两个,大小写没影响,但是名字不能变,如下:
在这里插入图片描述
有了这个文件,我们就可以使用make指令来自动执行makefile文件里面的命令了。

依赖方法与依赖关系:

我们的makefile文件里面命令的本质实际上就是两个:依赖方法和依赖关系,我们代码之间主要是依靠一个一个文件来封存,所以本质上文件之间的关系就反映着代码之间的关系,如下:
在这里插入图片描述
在这里,我写好了main.c process.c process.h三个文件,其中两个源文件,一个头文件,我们在书写C语言的程序的时候就知道,我们都是直接将源文件进行编译成可执行程序的,又根据我们前面程序的翻译中知道,我们的头文件是以链接的形式直接拷贝或者地址链接到程序中的,所以我们不需要对其进行编译展开,由上述的逻辑,我们大致构建出了一个文件之间的依赖关系:
main.c process.c两个文件要被编译成一个可执行程序文件,而头文件是链接进行的,由此,我们的可执行程序文件与两个源文件就是依赖关系,而他们的依赖方法就是将这两个源文件编译成一个可执行程序,头文件自己链接,由此,我们可以这样去写我们的Makefile的指令:
在这里插入图片描述
第一行是依赖关系,指的是我们的关系是process可执行程序和我们的两个源文件之间的关系,第二行需要先TAB空格后开始写,主要写依赖方法:在这里我们的$^代表的是冒号之后的依赖的对象,而 $@代表的是冒号之前的依赖对象,当然你直接写名字也是可以的,主要是这样写更加简便,然后这条指令我不多说,就是上篇文章我们说过的编译指令,后面的@ echo(注意这里@和echo之间要留有空格,否则这条指令执行会全是乱码,不简洁),这条指令就是将双引号里面的内容呈现到屏幕上,这个指令我们之前也学到过,它同样可以将对应的字符输入到文件中。
由此,我们的编译指令便构建了出来,现在只需要我们输入make,就可以自动编译代码成为可执行程序,如下:
在这里插入图片描述
这样当我们去查看我们的目录,一个process可执行程序便出现在了列表中,这便是我们的可执行程序。
但是,一个程序光可以编译是不够的,我们还需要它进行程序的清理,也就是要自动删除我们的全部程序文件,跟gcc/g++一样,倘若一个一个删就会太麻烦,所以我们同样使用利用程序将其一次清理指令全部执行的命令,即我们需要使用.PHONY伪代码来进行,这是由于我们的删除文件是没有依赖对象的,删除不需要跟其他文件搭建关系,但是我们的依赖关系如果不建立,依赖方法又是没法执行的,故我们通过使用伪代码来解决这个问题,.PHONY的特点在于:
.PHONY没有依赖关系这么一说,它会直接执行对应的依赖方法,即无论目标对象是否存在都会重新生成,不会在于文件新旧的问题,这是因为目标对象与其同名文件之间没有一定必要的相互关系。
故在这里我们可以这样总结:
.PHONY修饰的文件本身是和普通文件没有明显去别的,它只是总是被执行它对应的依赖方法,并且这种执行是强制性的。
由此,我们可以这样接着编译指令构建我们的删除指令,如下:
在这里插入图片描述

在这里,我们的clean即我们的对象,我们执行的指令当输入这个对象的时候,即当我们输入make clean的时候,我们就会去执行清理可执行程序process的指令rm -f,这样,我们就可以自动去清理多个程序文件,而不需要一个一个去清理了,如下:
在这里插入图片描述

make/makefile的自主推导性:

对于下面的代码:

mybin:code.o
 gcc code.o -o mybin
code.o:code.s
 gcc -c code.s -o code.o
code.s:code.i 
 gcc -S code.i -o code.s
code.i:code.c
 gcc -E code.c -o code.i  

此代码是可以执行的,虽然扫描文件的时候从上到下执行,但是由于makefile的自主推导性,它是这样去分析这些代码的:
从尾部向上依次按照文件的编译过程去找是否存在对应的文件,知道形成可执行程序,所以,我们的文件是不怕顺序问题的,主要是该有的逻辑我们是不能有缺失的,否则会影响程序的编译。
在这里插入图片描述

2.ACM时间与通过时间对文件新旧的判断:

我们倘若已经生成了一个process可执行文件,我们要是再次对其编译可以么?
倘若我们这样去执行,就会跳出这样的回应:
在这里插入图片描述
这条指令的意思就是说,文件已经更新到最新版本时间,不支持再次编译了,也就是说,此时文件是旧的,LINUX是可以分辨出来并且拒绝重复编译的,那么,LINUX是如何去区分一个文件是否被修改从而确定其是否可以重新编译的呢?
这就不得不提到我们的ACM时间了。
何为ACM时间呢?让我们stat任意一个文件来查看文件的详细信息,如下:
在这里插入图片描述
你会发现,有三个时间:
Access:读写访问时间,当我们打开文件读取内容时,就会修改这个时间
Modify:文件内容修改时间,当我们进入文件并修改文件内容时,就会修改这个时间
Change:文件属性修改时间,文件的属性基本随着内容的修改也在不断的被修改着

根据他们三个之间的特点,他们相应的关系如下:
ACM分别对应着三个时间的首字母,当C时间被修改时(比如文件的三个读写权限)它只会影响自己,另外两个时间不被修改,当我们去修改M时间时,则A时间和C时间都会由此而被改变,而修改A时间时,对应的C文件的属性也会被修改。
那,文件访问的本质是什么呢?
首先文件是被存储在磁盘上的,也就是说,访问文件本质上就是访问磁盘,这个过程的效率是很低的,很耗费时间,会影响我们程序的执行。由此,在LINUX中,我们是不会重复去编译文件的,因为LINUX有着庞大的文件,倘若依次修改磁盘,会导致出现大量的磁盘的IO操作,这严重影响了系统的效率给,故LINUX会尽可能的减少文件的修改次数。
所以回过来,我们的文件的新旧是如何被系统分辨出来的呢?
它主要依靠的实际上就是文件的修改时间,但是时间并非本质,通过时间对比出来的新旧才为本质,源文件通过与可执行文件的修改时间进行对比:
首先第一次的时候,我们一定是先有源文件,然后通过编译得到可执行程序,此时我们会得出结论,源文件的修改时间一定是小于可执行程序文件的修改时间的,然后从第二次开始,到后面之后的很多次修改,我们修改文件的时候,先去修改源文件,此时当我们再去编译的时候,此时的源文件的修改时间反而大于可执行程序的修改时间了,故此时两者的大小关系发生了变化,LINUX系统识别到了这种变化,意识到文件做出了修改,故此时认为文件为新,执行重新编译的指令,但旧文件就不会执行这个指令,由此,便通过源文件和可执行文件的修改时间的大小关系的变化去分辨新旧文件。
但是,这条规律在大部分情况下都没问题,问题的产生不仅仅是修改新文件就能解决的,有些历史问题,需要重新清理项目才可以解决。
那如何修改文件的时间呢?
我们有时对代码已经足够完美了,没必要修改的情况下,我们还想让其重新编译,这时我们就需要去更新我们的3个时间去让文件变成新的,这里我们就需要我们的touch指令来修改文件的时间戳:
touch -a/-c/-m:分别对应更新a,c,m三个时间,倘若不加,就是对整体的文件的三个时间进行更新。
在这里要补充一下:对于.PHONY的伪目标,它是无视时间的,只要调用就必定执行,没有新旧判断这一说。

好了,现在我们已经掌握了vim编译器软件,gcc/g++编译代码,自动化构建代码,我们接下来就开始正式进行我们的进度条小程序的书写。

2.进度条程序:

说到进度条,我在这里以LOL的进度条举例子,在我们进入LOL游戏之前的10人英雄界面,我们就有一个进度条和一个不断旋转的小圆圈,入下:
在这里插入图片描述

由于实在找不到旋转的图标了,但是我们大致看到右下角的这个进度数字标识,再加上我们的进度条和一个360度旋转的小光标,这便是我们整个进度条程序的全部组成部分,如下:
在这里插入图片描述
好了,大致的铺垫都完事了,现在让我们开始正式书写程序。

1.缓冲区:

在LINUX中提供了一个接口头文件<unistd.h>,通过它可以让我们使用sleep函数,让程序休眠一段时间(秒数),首先我们要明白,在C/C++语言中,针对标准输出,给我们提供了默认的缓冲区,主要是输出缓冲区,在stdout开启的同时stdin,stdeer也会随着stdout一同开启。
所以,本质上我们打印的本质是先将要打印的内容放到stdout的输出缓冲区中,然后立刻刷新输出缓冲区打印出内容,倘若我们延时sleep前刷新stdout,我们就会立刻打印出内容,而不是等了几秒才打印,而我们平时使用的换行符\n实际上也是一种强制刷新的方式,所以我们回车每次都可以强制刷新缓冲区。
C/C++为我们提供了fflush()函数来强制刷新缓冲区,利用它我们就可以不断刷新缓冲区从而实现动态进行程序的效果

2.回车换行:

注意,回车和换行是两个完全不同的概念,你可以去看我们的键盘。我们所谓的回车键是这样的:
在这里插入图片描述
注意一个细节,这里的回车键先向下再向左,但我们实际上的回车就是直接回到最左边,所以我们键盘上实际的回车键是先向下再回车而不是单纯回车的意思,这个不要理解错了。所以,为什么我们在程序输入的时候Enter会直接跳到下一行的最开始而不是直接下一行,这正是因为这个键位是回车加换行的意思,两个命令同时触发了,**在C语言中,换行就是‘\n’,而回车就是’\r’.**故倘若我们向让我们的光标一直停在一个位置开头,就每一次都回车一次让光标一直在最左边的开头位置即可。
同时注意,我们其实每一个向屏幕输入的数字也好,字母也好,各种符号也好,他们的本质都是以字符形式被识别和存储的,而根据我们占位符的不同去识别和理解这个字符对应的数据到底是什么,所以这才有ASCII表的存在,就是为了转化字符的。

程序代码如下:

有了上面的知识的铺垫,我们的进度条自然而然就出来了,代码如下:
process.c文件(函数文件)
本来是想给源码的,但是太麻烦了,就直接上图片了,抱歉~~~~~!!!
在这里插入图片描述
这个就是我们的函数代码,我称之为进度条最终版本,在这个版本里,我们主要要实现一个进度条配合程序实时的跟进,而不是进度条只是自己向后运行而不考虑实际的下载情况,所以我在这里采取的是传入比率的方式带入程序进行运算,我在这里定义了一个静态数组和一个静态的整型,其中静态数组是保证进度条一直向前进行的,由于我们的进度条是函数形式,出了函数进度条的数组就会被销毁(当然,倘若你定义一个全局变量的数组也可以),同时,为了保证我们的进度条加载卡住的时候我们的小光标依旧在选旋转,我们的这个整型变量配合上一个字符数组来保证我们小光标的实时更新,以告诉用户我们还在加载而不是卡住了,打印的过程中的那个\033[31;44是我加上的输出的字符的颜色和背景色,这个上网就能查到,注意看我fflush的位置,我是先让打印结果进入缓存区后,再刷新,这样就起到了在我主函数的延时之前先刷新字符串打印出我们的进度条。
在最后加载完成的时候,补上加载完成的提示语句,此时rate为100%,即为进度条加载完毕。
process.h文件(头文件)
在这里插入图片描述
main.c文件(主函数文件)
在这里插入图片描述
我们在这里配合着我们的头文件一起看主函数文件,头文件不多说,其实主函数文件也没什么说的,基本的代码大家都能看懂,但是在这里我想说一说,我们的进度条一般是作为回调函数来调用使用的,而不是直接放入程序内部,因为这个进度条可能需要实时更新,所以我们定义了一个函数指针并将其类型重定义为callback_t ,传入我们的加载download函数中为cb,配合着cb,这样,我们只需要传入我们每次想要使用的任意版本的进度条即可,这种方法效率很高,同时也很节省时间。usleep保证了时间的进一步缩小为毫秒为单位,更加接近真实的时间而不是sleep的慢速,同时我们还模拟了一个进度条卡住的情况,当rate大于百分之50的时候,由于total被限制为target的一半,故我们的rate也被限制在百分之50,从而就模拟了进度条卡住的情况。
通过这样写,我们的最终效果如下:
在这里插入图片描述
虽然很简陋,但是你依旧可以通过一些方式进一步优化这个建议的进度条**,不过在我看来,最重要的是一些我们缓冲区,延时函数,如何操作LINUX熟练的写程序,进度条为何利用回调函数来进行等等这些重要的知识才最为关键**

总结:

无论如何,我们的进度条代码算是完成了,这是我们的第一个LINUX的小程序,但不会是最后一个,写下了这个小程序,让我们更加熟练的使用LINUX去写代码,这才是我们的关键所在,学习LINUX不仅仅是会写代码,同时要对整个生态,系统的一些很多知识有更多的理解和新的感受,这才是最关键的。

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

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

相关文章

【Proteus仿真】【Arduino单片机】LM35温度计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用PCF8574、LCD1602液晶、LM35传感器等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示传感器检测温度。 二、软件设计 /* 作者&a…

场景交互与场景漫游-路径漫游(7)

路径漫游 按照指定的路径进行漫游对一个演示是非常重要的。在osgViewer中&#xff0c;当第一次按下小写字母“z”时&#xff0c;开始记录动画路径;待动画录制完毕&#xff0c;按下大写字母“Z”&#xff0c;保存动画路径文件;使用osgViewer读取该动画路径文件时&#xff0c;会回…

Cadence virtuoso drc lvs pex 无法输入

问题描述&#xff1a;在PEX中的PEX options中 Ground node name 无法输入内容。 在save runset的时候也出现无法输入名称的情况 解决办法&#xff1a; copy一个.bashrc文件到自己的工作目录下 打开.bashrc文件 在.bashrc中加一行代码&#xff1a;unset XMODIFIERS 在终端sour…

java使用 TCP 的 Socket API 实现客户端服务器通信

一&#xff1a;什么是 Socket(套接字) Socket 套接字是由系统提供于网络通信的技术, 是基于 TCP/IP 协议的网络通信的基本操作&#xff0c;要进行网络通信, 需要有一个 socket 对象, 一个 socket 对象对应着一个 socket 文件, 这个文件在 网卡上而不是硬盘上, 所以有了 sokcet…

模块一、任务一.数据分析概述

一、module1 预测未来-总统大选 样本偏差 二、module2 优化现状-化妆品销售 1、数据分析师从业务类型上划分 2、目标&#xff1a;总销量 达到 目标销量 3、固定基本流程 &#xff08;1&#xff09;确定 一、目标值节节升高&#xff0c;是否合理&#xff1f;根据什么定的&…

【火炬之光-魔灵装备】

文章目录 装备天赋追忆石板技能魂烛刷图策略 装备 头部胸甲手套鞋子武器盾牌项链戒指腰带神格备注盾牌其余的装备要么是召唤物生命&#xff0c;要么是技能等级&#xff0c;鞋子的闪电技能等级加2不是核心&#xff0c;腰带的话主要是要冷却有冷却暗影的技能是不会断的&#xff…

“腾易视连”构建汽车生态新格局 星选计划赋能创作者价值提升

11月16日&#xff0c;在2023年广州国际车展前夕&#xff0c;以“腾易视连&#xff0c;入局视频号抓住增长新机会”为主题的腾易创作者大会在广州隆重举办。此次大会&#xff0c;邀请行业嘉宾、媒体伙伴、生态伙伴、视频号汽车领域原生达人等共济一堂&#xff0c;结合汽车行业数…

多聚焦图像融合算法

# @File : PerfectFusion.py # @Author : ShawnWang # @Desc : 多焦点图像融合 # Time : 2023/9/24 08:25 import cv2 import matplotlib.pyplot as plt import numpy as np import pywt from PIL import Image# 基于小波变换的多聚焦图像融…

视频怎么做成二维码?在线教学视频码的制作技巧

视频是怎么制作成二维码的呢&#xff1f;现在经常会发现扫描很多的二维码会观看视频内容的情况&#xff0c;这种方式简化视频传递的过程&#xff0c;能够更加简单快捷的在线获取视频内容。对于想要了解视频二维码制作方法的小伙伴&#xff0c;小编通过本篇文章来教大家一招&…

网站优化工具Google Optimize

Google Optimize 是一款由Google提供的网站优化工具。Google Optimize旨在帮助网站管理员通过对网页内容、设计和布局进行测试和优化&#xff0c;来提升用户体验和网站的转化率。 Google Optimize 提供了 A/B 测试和多变量测试功能&#xff0c;使网站管理员能够比较和评估不同…

【左程云算法全讲13】暴力递归

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于左程云算法课程进行的&#xff0c;每个知识点的修正和深入主要参考…

掌握PyQt6/Pyside6如何用QTreeView QFileSystemModel 展示指定目录结构

文章目录 📖 介绍 📖🏡 环境 🏡📄 源码📖 介绍 📖 有时候我们需要给用户展示一个指定目录下的所有文件树结构,这里使用 PyQt6/Pyside6的QTreeView就可以轻松实现,本文将与大家分享实现源码 🏡 环境 🏡 本文代码运行的环境如下 Windows11Python3.11.5PySide…

【bigo前端】egret中的对象池浅谈

本文首发于&#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 egret是一款小游戏开发引擎&#xff0c;支持跨平台开发&#xff0c;之前使用这款引擎开发了一款捕鱼游戏&#xff0c;在这里简单聊下再egret中关于对象池的使用&#xff0c;虽然该引擎已经停止…

zabbix告警 邮件告警 钉钉告警

邮件告警添加主机组添加模板添加主机在模板中添加监控项在模板中添加触发器添加动作&#xff0c;远程执行命令给用户绑定告警媒介类型 钉钉告警安装python依赖模块python-requests配置钉钉告警配置脚本zabbix_ding.conf在目录/var/log/zabbix中创建钉钉告警日志文件zabbix_ding…

小命令,大世界

Linux是一个大系统&#xff0c;功能丰富&#xff0c;好比是一台巨型机器&#xff0c;而命令&#xff0c;就是这台机器的操作台。要想控制好这台机器&#xff0c;用好这台机器&#xff0c;就得会看仪表&#xff0c;会操作各种按钮。《Linux常用命令自学手册》就是介绍如何操作这…

Dart笔记:glob 文件系统遍历

Dart笔记 文件系统遍历工具&#xff1a;glob 模块 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/13442…

IIs部署发布vue项目测试环境

打开【控制面板 > 程序>启用或关闭Windows功能 】 1、安装IIS: 把这些勾选上&#xff0c;点击确定下载。 2、安装.net: 把这些勾选上&#xff0c;点击确定下载。 3、搜索IIs打开&#xff1a; 4、右击【网站>添加网站 】进行配置&#xff0c;点击确定。 4、右击[项目le…

【一周安全资讯1118】北京高院发布《侵犯公民个人信息犯罪审判白皮书》;工银金融勒索案的事件响应服务商MoxFive是谁?

要闻速览 1、工信部等四部门部署开展智能网联汽车准入和上路通行试点工作 2、北京高院发布《侵犯公民个人信息犯罪审判白皮书》 3、丰田公司确认遭遇美杜莎勒索软件攻击 4、家中设备把数据信息泄露到国外&#xff0c;浙江一男子被罚5000元 5、工银金融勒索案的事件响应服务商M…

信道编码---RS编码与译码原理

本文介绍了RS编码以及译码的原理。 本文的内容基本上都来自刘梦欣的《基于FPGA的RS编译码研究与设计》&#xff0c;大家可以通过知网找到这篇文章&#xff0c;链接在下面。对RS码的原理讲解非常清楚&#xff0c;如果要看的话可以结合第2和第3部分一起看更好懂。我的整理也是比较…