目录
[那么在我们休眠3秒期间hello world!在哪里?](#那么在我们休眠3秒期间hello world!在哪里?)
[程序会默认打开三个输入输出流 FILE*类型](#程序会默认打开三个输入输出流 FILE*类型)
继上节的make/Makefile篇,我们这节来完成一个命令行版的简易的进度条
1.回车换行
回车 \r 换行 \n
回车换行 \r\n
一般\n被自动解析成\r\n
回车
\r:将光标移动到当前行的开头(水平移动)。换行
\n:将光标移动到下一行的同一列(垂直移动)。
2.缓冲区问题
今天先简单讲一下缓冲区,先理解为一段内存块
myproc.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 printf("hello world!\n");
7 sleep(3);
8 return 0;
9 }
sleep


先等3秒之后退出。
然后把myproc.c的\n去掉
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 //printf("hello world!\n");
7 printf("hello world!");
8 sleep(3);
9 return 0;
10 }

发现是先休眠3秒在打印hello world!
不要以为第二个是先执行sleep再printf。
程序执行永远是从前往后执行的,先执行printf再执行printf
一定把printf执行完了!但是显示器上没有显示,
那么在我们休眠3秒期间hello world!在哪里?
在缓冲区里面
我们往显示器上打印称为行刷新
如果没有\n就不会刷新**,那么为什么最终还是有打印出来呢?**
是因为程序退出,会自动刷新缓冲区!
小知识点fprintf
1 #include<stdio.h> 2 #include<unistd.h> 3 4 int main() 5 { 6 //printf("hello world!\n"); 7 fprintf(stdout,"hello world!\n"); 8 sleep(3); 9 return 0; 10 }这里两个一样
如果想让它立马刷新呢?

可以使用fflush
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 printf("hello world!");
7 fflush(stdout);
8 //printf("hello world!\n");
9 //fprintf(stdout,"hello world!\n");
10 sleep(3);
11 return 0;
12 }

程序会默认打开三个输入输出流 FILE*类型
extern FILE *stdin; 键盘
extern FILE *stdout; 显示器
extern FILE *stderr; 显示器
printf实际上是往stdout上打
3.倒计时程序
1.初版
myproc.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 int i = 9;
7 while (i >= 0)
8 {
9
10 printf("%d\n", i);
11 i--;
12 }
13 return 0;
14 }

我们想要让9876543210在同一个位置打印
2.第二版
myproc.c
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 int i = 9;
6 while (i >= 0)
7 {
8
9 printf("%d\r", i);
10 i--;
11 sleep(1);
12 }
13 return 0;
14 }
\r是回车符(Carriage Return),其作用是将光标移动到当前行的开头,不换行

结果我们发现,因为没有\n没有刷新缓冲区。
所以对应的信息没有显示出来
3.终版
myproc.c
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 int i = 9;
6 while (i >= 0)
7 {
8
9 printf("%d\r", i);
10 fflush(stdout);
11 i--;
12 sleep(1);
13 }
14 printf("\n");
15 return 0;
16 }
显示效果成功(因为是动态不好演示,可以自行尝试)

理解显示
但如果这里给10
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 int i = 10;
7 while (i >= 0)
8 {
9
10 printf("%d\r", i);
11 fflush(stdout);
12 i--;
13 sleep(1);
14 }
15 printf("\n");
16 return 0;
17 }
会发现是两位,并不会从两位变成一位的

显示器只认字符!---字符设备
因此改成
myproc.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 int i = 10;
7 while (i >= 0)
8 {
9
10 printf("%-2d\r", i);
11 fflush(stdout);
12 i--;
13 sleep(1);
14 }
15 printf("\n");
16 return 0;
17 }
第十行,改成 printf("%-2d\r", i);
2d两个字符,"-"向左对齐。
从而实现成功

4.进度条
接下来,我们就开始进度条的操作
想实现的进度条
## \]\[53%\]\[/
每过一个百分点多一个#号,53%那个会动,/处会旋转。
ctrl+ww,可以使光标移动到另一端 切换
1.第一版
前置准备
[user1@iZ5waahoxw3q2bZ 26-4-15.2]$ mkdir processbar
[user1@iZ5waahoxw3q2bZ 26-4-15.2]$ cd processbar
[user1@iZ5waahoxw3q2bZ processbar]$ touch process.h
[user1@iZ5waahoxw3q2bZ processbar]$ touch process.c
[user1@iZ5waahoxw3q2bZ processbar]$ touch main.c
[user1@iZ5waahoxw3q2bZ processbar]$ ll
total 0
-rw-rw-r-- 1 user1 user1 0 Apr 15 22:16 main.c
-rw-rw-r-- 1 user1 user1 0 Apr 15 22:16 process.c
-rw-rw-r-- 1 user1 user1 0 Apr 15 22:16 process.h
Makefile
1 SRC=$(wildcard *.c)
2 OBJ=$(SRC:.c=.o)
3 BIN=processbar
4
5 $(BIN):$(OBJ)
6 gcc -o $@ $^
7 %.o:%.c
8 gcc -c $<
9
10 .PHONY:
11 clean:
12 rm -f $(OBJ) $(BIN)
1.初步
process.h
1 #pragma once
2
3 #include<stdio.h>
4
5 void process_v1();
process.c
1 #include"process.h"
2
3 void process_v1()
4 {
5 printf("hello world!\n");
6 }
main.c
1 #include"process.h"
2
3 int main()
4 {
5 process_v1();
6 return 0;
7 }
make
[user1@iZ5waahoxw3q2bZ processbar]$ make
gcc -c process.c
gcc -o processbar main.o process.o
[user1@iZ5waahoxw3q2bZ processbar]$ ll
total 36
-rw-rw-r-- 1 user1 user1 68 Apr 15 22:33 main.c
-rw-rw-r-- 1 user1 user1 1368 Apr 15 22:36 main.o
-rw-rw-r-- 1 user1 user1 137 Apr 15 22:21 Makefile
-rwxrwxr-x 1 user1 user1 8512 Apr 15 22:38 processbar
-rw-rw-r-- 1 user1 user1 73 Apr 15 22:38 process.c
-rw-rw-r-- 1 user1 user1 211 Apr 15 22:36 process.h
-rw-rw-r-- 1 user1 user1 1504 Apr 15 22:38 process.o
[user1@iZ5waahoxw3q2bZ processbar]$ ./processbar
hello world!
2.process.c
#include "process.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define NUM 101
#define STYLE '#'
void process_v1()
{
char buffer[NUM];
memset(buffer, 0, sizeof(buffer));
const char* lable = "|/-\\";
int len = strlen(lable);
int cnt = 0;
while (cnt <= 100)
{
printf("[%-100s][%d%%][%c]\r", buffer, cnt, lable[cnt % len]);
fflush(stdout);
buffer[cnt] = STYLE;
cnt++;
usleep(50000); // 50ms
}
printf("\n");
}

2.第二版
process.c
#include "process.h"
#include <stdio.h>
#include <unistd.h>
#define BAR_WIDTH 50
void FlushProcess(double total, double current)
{
double percent = (current / total) * 100;
int bar_len = (int)((current / total) * BAR_WIDTH);
// 保证不超出范围
if (bar_len > BAR_WIDTH) bar_len = BAR_WIDTH;
printf("\r[");
for (int i = 0; i < BAR_WIDTH; ++i) {
if (i < bar_len)
printf("#");
else
printf(" ");
}
printf("] %.2lf%%", percent);
fflush(stdout);
}
typedef void (*callback_t)(double total, double current);
double total = 1024.0;
double speed = 1.0;
void DownLoad(callback_t cb)
{
double current = 0;
while (current <= total) {
cb(total, current);
usleep(3000); // 模拟下载数据
current += speed;
}
printf("\ndownload %.2lfMB Done\n", current);
}
void UpLoad(callback_t cb)
{
double current = 0;
while (current <= total) {
cb(total, current);
usleep(3000); // 模拟上传数据
current += speed;
}
printf("\nupload %.2lfMB Done\n", current);
}
int main()
{
DownLoad(FlushProcess);
UpLoad(FlushProcess);
return 0;
}
今天我们的学习就到此结束,期待我们下次再见!!!
