wex5网站开发,wordpress浏览器跳转,opkg 安装wordpress,北京想象力网站建设公司前言#xff1a;
本篇我们将开始尝试构建我们的第一个LINUX的小程序----进度条作为一个十分常见的程序#xff0c;在我们之后的工程实践中也是需要多次运用#xff0c;但是介于我们目前还没有去学习网络等方面的知识#xff0c;没法独立的去利用程序去下载一个真正的程序
本篇我们将开始尝试构建我们的第一个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.ogcc code.o -o mybin
code.o:code.sgcc -c code.s -o code.o
code.s:code.i gcc -S code.i -o code.s
code.i:code.cgcc -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不仅仅是会写代码同时要对整个生态系统的一些很多知识有更多的理解和新的感受这才是最关键的。