要想做一个动态增长的进度条程序,我们需要了解一下Linux下的屏幕刷新策略
执行下面一行代码我们可以看到程序在每间隔1秒的时候会换行打印从10到1的数字,但是进度条程序可不能进行换行打印,需要在同一行上打印,这时候就需要了解一下回车和换行的区别了。
#include
#include
int main()
{
int count=10;
while(count)
{
printf("%2d\n",count);
count--;
sleep(1);
}
return 0;
}
很多人认为回车和换行是一个意思,其实不然,换行是从当前位置换到下一行,列不变,而回车则是回到当前行的最开始。我们在C语言中常用的\n代表的意思是回车换行,而回车则是使用\r选项 那让我们看看代码效果如何:
#include
#include
int main()
{
int count=10;
while(count)
{
printf("%2d\r",count);//进行回车操作
count--;
sleep(1);
}
return 0;
}
上面的测试用例我们可以看到使用\r进行回车,但是printf打印的值并没有显示到显示器上,这个原因就在于在Linux系统下虽然printf已经执行,但是数据没有被立即刷新到显示器上,没有\n字符串会先在用户缓冲区暂时保存起来,显示器刷新策略是行刷新即遇到\n立刻进行刷新。
fflush:这个函数的意思是立即刷新到输出流,我们可以看一下他的数据手册
使用fflush函数后我们就可以将数据直接刷新到显示器上,测试代码如下:
#include
#include
int main()
{
int count=10;
while(count)
{
printf("%2d\r",count);
fflush(stdout);
count--;
sleep(1);
}
return 0;
}
实现一个进度条小程序,代码还是比较简单的。
首先我们需要知道进度条的长度大小,一般是100,因此我们需要定义一个char类型的数组用来显示进度。
char bar[NUM+1];//开辟进度条空间大小
memset(bar,'\0',sizeof(bar));//将其都设置为\0打印时直接用%s即可按当前长度进行打印
然后我们使用一个循环加上sleep暂停函数来实现进度条的动态增长,这里printf需要使用的是\r回车操作
while(i<=100)
{
printf("[%-100s][%-3d%%]\r",bar,i);//这里为了美观需要进行格式控制
fflush(stdout);//立即刷新到显示器上
bar[i]='*';//进度条用*代替 也可以使用#等字符
i++;
usleep(100000);//微秒 sleep的单位是s 因此在这里使用usleep使进度条刷新不至于过慢
}
这样一来我们的大致的进度条程序就差不多完成了,但是想要更加美观一些我们可以在进度条最后加上一个选择的光标显示当前正在运行
想要实现这个光标还是比较简单的,我们可以定义一个字符串在里面输入光标种类,然后通过循环来控制光标的旋转
const char* arr="|/-\\";
while(i<=100)
{
printf("[%c]\r",arr[i%4]);//4种光标于是可以通过%4的方式来控制打印不同光标
fflush(stdout);
i++;
usleep(100000);//微秒
}
这样一来我们的光标旋转也完成了。
这边我们看一下完成后的代码样例
#include
#include
#include
#define NUM 100
int main()
{
char bar[NUM+1];//开辟进度条空间大小
memset(bar,'\0',sizeof(bar));//将其都设置为\0
int i=0;
const char* arr="|/-\\";
while(i<=100)
{
printf("\033[31m[%-100s][%-3d%%][%c]\r",bar,i,arr[i%4]);
fflush(stdout);
bar[i]='*';
i++;
usleep(100000);//微秒
}
printf("\n");
return 0;
}
运行结果:
在Linux系统下,如果想要编译代码每次都需要使用
gcc -o myprobar myprobar.c
这一类的命令时会显得比较麻烦,而且不方便进行大型项目的编译,因此在Linux系统下我们有make这个功能
这里介绍一下make的简单用法,对于进度条程序,我们只需要进行项目的编译和清理即可,例如:
myprobar:myprobar.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f myprocbar
这里需要注意的是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY修饰,伪目标的特性是,总是被执行的。