进度条
进度条的前置准备
sleep (秒)& usleep(微秒)
sleep加\n和不加\n的区别
创建Makefile文件和mytest.c文件
//Makefile
mytest:mytest.c
gcc mytest.c -o mytest
.PHONY:clean
clean:
rm -f mytest
//mytest.c
#include<stdio.h>
#include<unistd.h>
int main(){
printf("hello sleep \n");
sleep(1);
return 0;
}
编译并运行,如下图,程序等1秒自动结束,并没有什么问题
当我们将mytest.c里面的 \n 去掉之后,重新编译运行
结果是等了一秒,没有反应,一秒后才变成上图的样子
为何会如此?
IO函数的缓冲区
在这一秒内,其实printf已经跑完了,我们没有看到printf及时显示出来的原因是,它输出的字符串被保存起来了。在我们退出的时候它才显示出来
那它保存在了哪里呢?
printf输出的内容是保存在了IO函数提供的缓冲区内
回车&换行
回车就是退回到这一行的最开始的地方,回车符为 '\r'
换行就是从这一行垂直到下一行,才叫换行,不回到最开始的地方
所以回车+换行,就是到下一行的最开始的地方
10秒倒计时
fflush的作用就是清空缓存区,把它搬到stdout上,stdout可以认为它是屏幕
#include<stdio.h>
#include<unistd.h>
int main(){
int ret = 10;
while(ret!=0)
{ -的意思就是左对齐,2就是占两个字符
printf("%-2d\r",ret); -2组合起来就是,向左对齐,留两个位,一个位时,站左边
fflush(stdout);
ret--;
sleep(1);
}
return 0;
}
进度条编写
1 #include"processbar.h"
2
3 const char* lable = "|/-\\";
4 void process()
5 {
6 char buffer[NUM];
7 memset(buffer,'\0',sizeof(buffer));
8 int cnt = 0;
9 buffer[0] = Head;
10 // int n = strlen()
11 while(cnt<=100) //它会循环101次
12 {
13 printf("[%-100s][%3d%%][%c]\r",buffer,cnt,lable[cnt%4]);
14 fflush(stdout);
15 buffer[cnt]=Body;
16 cnt++; //因为到最后cnt是100也能进,所以有效字符会变成101,给\0加一个,所以给102
17 if(cnt<100)
18 buffer[cnt]=Head;
19 usleep(50000);
20 }
21 printf("\n");
22 }
但是我们此刻写的进度条并不是我们熟悉的进度条,这个进度条是死的,不受其他程序约束的
因为进度是多少,进度条并不知道,进度条不应该是一个独立的程序,而是应该依附于其它应用的,比如下载
因此,我们先模拟一个网络的下载过程
1 #pragma once
2
3 #include<stdio.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<stdlib.h>
7 #include<time.h>
8
9 #define NUM 103
10 #define Body '='
11 #define Head '>'
12
13 typedef void (*callback_t)(double);
14 //函数指针类型
15 //version 2
16 void process_flush(double rate);
3 #define FILESIZE 1024*1024*1024
4
5 //模拟一种场景,表示一种下载任务
6 void download(callback_t cb){ //参数为函数指针
7 srand(time(NULL)^1023); //只是让时间变得更随机一些,先种下随机数的种子
8
9 int total = FILESIZE; //文件总大小
10 while(total)
11 {
12 usleep(5000);//下载动作
13 int one = rand()%(1024*1024); //单次下载量,最慢网速是0,最快网速是1兆
14 total-=one; //剩余的量
15
16 if(total<0) total = 0; //怕减为负数,直接归0
17
18 int download = FILESIZE - total;//已经下载的量
19 double rate = (download*1.0 / (FILESIZE)) * 100.0; //下载比例
20 cb(rate);
21 }
22 }
#include"processbar.h"
const char* lable = "|/-\\";
char buffer[NUM] = {0};
void process_flush(double rate){
static int cnt = 0;
if(rate <= 1.0) buffer[0] = Head;
printf("[%-100s][%5.1f%%][%c]\r",buffer,rate,lable[cnt%4]);
fflush(stdout);
buffer[(int)rate]=Body;
if((int)rate+1 < 100) //+1 very improtant
buffer[(int)rate+1]=Head;
if(rate>=100.0) printf("\n");
cnt++;
cnt = cnt % 4;
}
git的使用
为什么要有git(git版本控制器)
开发的时候,也许会遇到项目经理或者上面的佬提出各种粗略的任务,到验收的时候却说这里不合,那里不好。需要重复的改,改着改着忘记了以前的版本,有时改了之后甚至没有以前的好,但却回不去了。
所以为了能够回去找到以前心仪的code,就有了git
git的主要功能
Git 能够记录每次文件的修改,包括修改的内容、修改者、修改时间等信息。这使得开发者可以追踪文件的历史变化,理解项目的发展过程。
Git 支持强大的分支管理功能。开发者可以轻松地创建、合并和删除分支,从而实现并行开发和功能测试。
后来为了方便给予不同人共同管理它们远程或者本地存放他们项目的仓库,基于git的基础上,创建出来网页版的管理,如,GitHub,gitee,gitlab等
Linux下载git的指令
sudo yum install -y git
git的创建
下面以gitee码云为例
展示创建远端仓库,并拉取到本地作为本地仓库操作
首先要创建一个仓库,给予操作系统
- 进入Gitee官网(登录注册),点击右上角头像处,找到我的仓库,点击,新建
2,设置仓库属性
3,复制文件相关地址,到Linux终端,并在Linux终端下执行
处理完之后,我们会发现我们多了一个目录
**.git **文件夹里就是我们的本地仓库
我们进 .gitignore看看
凡是出现在这个文件里的后缀以后都不会被添加进仓库,git 不会对二进制文件进行管理 ,不想对非源代码进行管理,所以会在.gitignore 文件里标注不会鸟的文件后缀
修改.gitignore是即时生效的,在添加新后缀否认成员时,不要忘了*
git pull 本地仓库和远端仓库同步
git的传输本地仓库
如图所示,将目标文件导入仓库中共三个阶段
1,将目标文件复制粘贴到gitee的路径下
2,将目标文件添加到暂存区里
[lhl@VM-20-2-centos linux_git_try]$ git add .
3,将目标文件添加到历史记录里,即提交到本地仓库
语法: git commit -m "提交日志"
提交日志需要我们好好写,不要随便写
[lhl@VM-20-2-centos linux_git_try]$ git commit -m "第一次提交进度条代码,测试已经通过"
如果还需提交到远端的话
**[lhl@VM-20-2-centos linux_git_try]$**git push
输入账号密码后
则成功到达远端,本质就是本地仓库跟远端仓库同步
git出现错误
当我们第一次使用git,或者其他情况下
比如:我第一次使用
[lhl@VM-20-2-centos linux_git_try]$ git commit -m "第一次提交进度条代码,测试已经通过"
会出现
也就是说git不认识你,不知道你是谁,此刻你告诉git你是谁就可以了
语句
**git config --global user.name '你的昵称'
git config --global user.email '你的邮箱' **
当然,我们一开始复制的地方也有
配置用户名和昵称的原因是:保证每段被提交的代码,可被溯源
git status
可以查看git的状态
创建一个文件后的状态
放进缓存区后的状态
放到本地仓库后的状态
远程提交完后的状态
回到啥也没有的状态
git rm file_name
删除也是一次提交,也必须通过相应的步骤
进行远端同步后,远端的网站也没有了test.c文件
查看一下日志
gdb调试
测试代码
1 #include <stdio.h>
2
3 int sum(int n){
4 int i =1;
5 int sum = 0;
6 for(;i<=n;i++){
7 sum+=i;
8 }
9 return sum;
10 }
11
12 int main(){
13 printf("\n");
14 printf("--------------------------------------------\n");
15 printf("开始执行\n");
16 int result = sum(100);
17 printf("result is %d\n",result);
18 printf("--------------------------------------------\n");
19 printf("\n");
20 return 0;
21 }
gcc/g++调试前提
我们尝试对其进行调试一下
可以发现我们是调试不了的
究其原因就是gcc/g++写出来的代码默认是release版本,就跟编译的时候默认是动态链接一样
debug 和 release 区别
debug形成的可执行程序会给我们添加调试信息
release形成的可执行程序会给我们去掉调试信息
那我们要如何才能使gcc/g++编译的时候编译的是debug版本呢
在编译语句添加 -g 选项
1 mytest_d:test.c
2 gcc -o $@ $^ -g
debug环境下的编译语句
1 mytest_d:test.c
2 gcc -o $@ $^
release版本下编译语句
在大小上,debug是大于release
多出来的便是调试信息
如果想看更为详细的信息,则使用readelf,来看可程序程序的格式
而release是找不到debug信息的
所以将makefile里的编译信息增加条件 -g 即可
调试工具使用
查看代码
使用list,也可以使用list的缩写l,来查看我们的代码
我们一开始可能会因为上次退出光标所在位置的原因,让所展示的代码不是最开始处开始
因此,我们用 l 1
我们就可以看到从第一行开始的代码,但是其依旧无法展示出我们全部的代码
所以Enter,直至展示出所有的代码
运行代码
使用run ,或者用缩写r,是指让程序跑起来,是直接跑完
打断点
使用b number,比如 b 2 在第二行打断点,从而达到一个打断点
或者**b 函数名 **,比如b sum ,在函数的入口处打断点
使用info b来显示断点,查看断点
使用 d 断点编号(非行号)来删除断点
这是因为我们要删除断点,只能通过断点编号来去删除,不能通过打断点的代码行数来删除
使用disable 断点编号 来关闭断点
使用enable 断点编号,来开启断点
逐语句和逐过程
逐语句进入函数:s
然后一直回车
逐过程: n
查看数据
p 变量 :查看变量的值
display 变量:常显示变量的地址和内容
undisplay 编号 : 取消常显示
bt:调用堆栈
范围跳跃
c: continue 从一个断点运行到下一个断点(范围查找)
finish:将一个函数运行结束,就停下来(范围查找)
until:在一个范围内,直接运行到指定行
以上便是本次博文的学习内容,如有错误,还望各位大佬指点,谢谢阅读
版权归原作者 Ljubim.te 所有, 如有侵权,请联系我们删除。