目录
一.Linux项目自动化构建工具-make/Makefile
🎓打印出的makefile文件和make显示在显示器中的不一样?
一.Linux项目自动化构建工具-make/Makefile
- make:是一个指令
- makefile:是一个当前目录下的文件
-
🎓make是如何工作的?
make是如何工作的,在默认的方式下,也就是我们只输入make命令
make指令可以利用依赖关系,执行依赖方法中的内容,编译形成可执行文件
-
🎈依赖关系?
-
🎈依赖方法?
比如:你打电话给你爸要生活费,你不能和你室友的爸打电话要生活费,所以你和你爸是有依赖关系.
我要将mycode.c文件形成可执行程序文件mycode(mycode.c文件依赖的是mycode文件)
后者依赖前者,前者依赖于后者。
-
🎓打印出的makefile文件和make显示在显示器中的不一样?
make在扫描makefile 文件时,优先根据依赖关系表去找,后者在当前文件中存在,如果不存在就类似于递归式的先形成依赖文件,然后通过依赖关系,从上往下找到。mycode.c实际上是出口(栈的调用)
make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
make会自动推导makefile中的依赖关系,推导过程是栈式结构
-
🎓如何清理可执行程序?
make自上向下扫描makefile文件,一般都是将可执行程序放在前面,清理内容放在后面
-
🎓为什么只能make一次?
- 为什么不改自己的源代码,就不让你再次编译了?——【没有必要】
- 为什么不能再次编译?——【主要提高编译效率】
- 怎么做到的?——【一定是源文件形成可执行,先有源文件,才有可执行,一般而言,源文件的最近修改时间 比 可执行文件要老的】
如果我们更改了源文件,历史上曾经还有可执行,那么源文件的最近修改时间,一定要比可执行程序要新。只需要比较,可执行程序的最近修改时间,和 源文件的最近修改时间
- .exe 新于 .c 源文件是老的,不需要重新编译了
- .exe 老于 .c 源文件是新的,需要重新编译了
一般而言,.exe==.c??? 一般不会。
- 文件=文件内容+文件属性
- modify对文件内容进行修改
- change对文件属性进行修改
- Access只读不修改
- Access Modify Change(acm时间)
结论:make会根据源文件和目标文件的新旧,判定是否重新执行依赖关系进行编译(依赖关系不一定总是执行)
如果我让每一次可执行程序都是可以执行————.PHONY:伪目标
但是一般我们编译过的内容,就不需要再次重新编译了,所以一般不写
而清理目标文件,需要每次都编译
🎓特殊符号:
-
🚩显示依赖方法
-
🚩不显示依赖方法
二.倒计时小程序
[##> ][40%][\]
👩🏾💻回车换行
- \r表示回车,即将光标移动到当前行的起始位置
- \n表示换行,即将光标向下移动一行
但是我们平时用的比如C语言打印的时候加一个\n换行
他不仅进行了换行并且光标也移到了起始位置。但是其实这是两个步骤,先移到下一行,再移动到起始位置。不过呢,在常见的计算机系统中,换行通常会伴随回车操作。
- 我们看到这里就成功打印出来了hello world,并且进行了换行(且伴随了回车)。所以后面的命令提示符就打印到了下一行,并且在开头位置。
- 那其实就是跟最后的\r有关系,printf打印的时候,前面的hello world都没问题,但是最后遇到\r(回车),就把光标移到了最左边起始位置。所以后面打印命令提示符的时候就把hello world覆盖掉了
👩🏾💻缓冲区
- 缓冲区(Buffer)是计算机系统中用于临时存储数据的一块内存区域。它通常用于处理输入和输出操作,以提高效率和性能。
缓冲区相当于一个中间层,位于数据的来源和目的地之间。当进行输入或输出操作时,数据先暂时存储在缓冲区中,然后再批量地传输到目标位置或从源位置读取出来。这样可以减少对源位置或目标位置的直接读写次数,从而提高数据传输效率。
- sleep()函数
头文件#include<unistd.h>,sleep() 函数用于在程序中暂停执行一段时间,sleep() 函数的参数是以秒为单位的等待时间。它的作用是让程序进入休眠状态,停止执行指定的时间间隔,然后再继续执行后续的代码。
- 在Linux或UNIX系统中,可以包含<unistd.h> 头文件,使用 sleep() 函数。
- 在Windows系统中,可以包含<windows.h> 头文件,使用 Sleep() 函数。
以上俩种情况,是先执行1还是先执行2呢?
- 第一种带'\n',表示先打印,后进行休眠(因为我们使用了sleep)
- 第二种不带'\n',表示先休眠,后进行打印,而且新的命令行直接跟在hello world后面,因为我们没有换行。
带\n的时候是先打印hello world,后休眠;而不带\n是先休眠,后打印hello world。那这样的话,不带\n的时候,好像是先执行了sleep函数,然后才执行printf去打印。
当然不是的,我们知道程序默认是按照从上到下顺序执行的。所以肯定是先执行printf,再执行sleep,毋庸置疑。C语言是按照顺序执行的,(默认没有循环没有判断......)整个代码先执行printf再执行sleep所以顺序一定是1,2。
为什么我们看到的是两个程序打印的时机为什么不一样呢?
缓冲区相当于一个中间层,位于数据的来源和目的地之间。当进行输入或输出操作时,数据先暂时存储在缓冲区中,然后再批量地传输到目标位置或从源位置读取出来。不管我们有没有加\n,我们的hello world这个字符串都会被暂存到缓冲区里面。
原因其实是因为两个程序的缓冲区刷新的时机不同。
在大多数编程语言和操作系统中,缓冲区被用来暂时存储要输出或被读取的数据,直到达到一定条件后才会将其发送到目标位置(如屏幕、文件、网络等)。这个条件通常是缓冲区满了、遇到换行符、或者主动进行缓冲区刷新的操作。当程序结束时,通常会自动刷新输出缓冲区。这意味着在程序执行完成后,输出缓冲区中的所有数据将被写入到相应的输出设备(如终端或控制台)并在屏幕上显示出来。所以我们可以认为,遇到\n的时候就会触发缓冲区刷新操作。而程序结束也会刷新缓冲区。
- 第一个程序我们加了\n,所以执行printf时遇到\n就会刷新缓冲区,那么hello world就直接显示到了显示器上。所以是先打印,后休眠。
- 而第二个程序,没有\n,我们也没有手动刷新缓冲区,因为显示器是行刷新,\r也不能进行手动刷新,所以直到程序结束是刷新缓冲区,hello world 才会显示到显示器上。因此是先休眠,后打印。
👩🏾💻强制刷新
标准输入,标准输出(显示器,stdout),标准错误
fflush这个函数可以刷新缓冲区给,那这样就相当于我们提前刷新了一下缓冲区,这样休眠就在打印后面了,方便我们观察。
不加fflush(stdout)和加上fflush(stdout)打印一样,但是其实本质上面他们显示过程不一样。
- 不加fflush(stdout):调用了printf后,把0<x<10最后一次性进行了显示。
- 加了fflush(stdout):调用了printf后,把0<x<10放一个就输出一个,相当于着10个值从输出缓冲区一个一个蹦出来的。只是人眼看起来打印一样。
👩🏾💻\r \n %md
printf可以用格式控制串"%md"输出域宽为m的十进制整数(默认左对齐,-m则右对齐)
\r是回车,回车是返回一行的头位置。再原来所在的位置倒计时,而不是一个位置跳到下一个位置
我们需要的倒计时是可以跳到头位置进行变化。
\r 回车符 %2d 右对齐 -%2d 左对齐
三.Linux第一个小程序—进度条
[##> ][40%][\]
我们来写实现进度条的函数processbar
思路:一个大的【】,里面预留出来100个字符的空间,我们填充=,当然你也可以用其他的,1%就打印一个#,2%就两个,以此类推,后面可以显示一下具体是百分之几,随着#增加不断递增直到100%。
其实它大致的思路和上面的倒计时是一样的:就是不断的显示并覆盖之前的内容。
先创建这四个文件
makefile里面的内容:
💡基本思路及实现
- 首先我们可以先开一个数组,把进度条需要的100个字符的空间预留出来。那我们打印的时候可以直接打印=组成的字符串,那字符串的话就要再给\0开一个空间。
- 然后我们可以给bar数组全部初始化为\0,这样我们后续添加#就不用考虑\0的问题了。
3.然后我们循环打印并不断添加#就行了,当然我们这里还应该使用\r不断的回车,使每一次新打印的覆盖之前的,并且每次循环printf之后要使用fflush刷新缓冲区,这样才能每次循环都够打印出来内容,要不然程序结束之前一直留存在缓冲区。
但是打印的结果从右向左打印
系统默认从右向左开始打#符号,所以在此之前用“-”号来表示就可以实现从左向右打印
sleep usleep:
sleep(1)表示执行一个就是1s,如果执行到100%,那么就需要100s,那样是很慢的
sleep的参数是以秒为单位的,而usleep是以微秒为单位的。
我们可以设置成0.1秒休眠时间
- 两个“休息函数”,一个是sleep(),另外一个是usleep();那么两者有什么区别呢?
两个函数的功能是一样的,区别在于“休息”时间的精确度,对于sleep()来说,最小单位为秒,也就是说使用sleep()的话最少只能休息1秒;而usleep()的最小单位为微秒
(1秒=1000毫秒=1000000微秒),不难发现usleep()可以比sleep()“休息”更短的时间。
ps:usleep(100000)相当于sleep(0.1),所以完成100%,那么只需要10s即可完成。
注意在完成代码后,需要打印\n。
否则进度条这一行显示完毕,新出现的命令行会把进度条的一部分覆盖掉。
💡增加百分比显示
我们需要在[]右边加个百分比符号来表示进度
由于count是依次递增的,所以进度百分比显示可以利用count来计数
但这并没有显示%号,c语言后面加上%%号,就可以实现
💡增加旋转光标
可以通过循环显示这四个字符| / - \
来模拟一个旋转的过程(注意\
要用转义字符\\
)
💡给进度条配色
在C语言中,可以使用ANSI转义序列来输出不同的颜色。ANSI转义序列是一系列的字符组合,用于控制终端的文本样式和颜色。关于配色方案,网上可以找到很多相关的资料,大家有兴趣可以按照自己的喜好去配色,我这里简单演示一下:
💻优化
TOP表示最多元素100
主体符号是=,右侧符号是>
完整代码:
因为我喜欢的东西都很贵,我想去的地方都很远,我爱的人超完美。