Linux学习记录——칠 git、gdb部分基础知识以及进度条小程序


一、/r/n

在写小程序之前,我们先看一下/r和/n的区别。
/n我们遇到过,它叫做换行符。/r并不知道是什么符号。实际应用中,/n可以起到我们俗称的回车作用,来到下一行的头处。但是呢,我们要注意到一个问题,/n为什么叫换行符,而不是回车符呢?实际上这两个词不是一个意思,/n意为换行,/r意为回车。换行顾名思义就是换行,但是到了下一行光标不一定在最开头,可能上一行光标直接移到了下一行;来到下一行后,回车就会让光标来到最开头;一般写代码时,/n的作用就是整合了这两个,所以就是我们平常所见到的效果。

实际写代码看看

/r/n都加上

在这里插入图片描述

只用/n

在这里插入图片描述
效果其实一样

只用/r

在这里插入图片描述

什么都没打印,是因为程序运行到/r时,光标又回到了最开头,所以整个程序也就没打印出什么。

我们可以让程序暂时休眠一下来看到实际操作。

#include <unistd.h>
#include <stdio.h>

int main()
{
    printf("hello world\r");
    sleep(1);
    fflush(stdout);
    return 0;
}

二、简单理解缓冲区概念

延用上面的代码。

#include <unistd.h>
#include <stdio.h>

int main()
{
    printf("hello world\n");
    sleep(3);
    return 0;
}

把\n去掉,就会发现实际执行时,光标会先闪烁一会才打印出hello world,如果加上\n,就是先打印出hello world再闪烁一会。不加符号也是一个正常的程序,为什么printf不先执行,而是sleep先执行?

其实并不是这样,程序运行时还是printf先执行,执行完后sleep期间字符串没有显示出来,但最后hello world还是打印出来了;最后能输出说明字符串还是有的,在这之前它已经被刷新了出来,然后被打印。既然这样,刷新之后再到打印出来这段时间,字符串一定没有丢失,肯定也存在了某个地方,这个存储地就是缓冲区。我们加上\n后,程序就按照我们的意愿打印了出来,这是因为缓冲区有它自己的缓冲策略,这里简单写一个行缓冲。只要遇到换行符,就会把符号之前的内容全部刷新出来。程序结束之前,系统会自动刷新出来缓冲区的内容,也可以用函数来手动刷新。

继续看,我们加上一个\r

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     printf("hello world\r");                                                                                                                                                                                  
  7     sleep(1);
  8     return 0;
  9 }

这样执行后,会发现什么都没有打印出来。

在这里插入图片描述

执行程序的时候,程序识别到hello world每个字符,打印的时候光标会一个个往后移动,直到遇到/r,光标回到了最开头,但是这时候hello world存在了缓冲区,并没有丢失,然后执行sleep,最后程序结束时,系统还需要打印自己的提示符,也就是图中的[zyd@ecs…],这时候光标在最开头,所以一打印就把hello world给覆盖了。

现在在hello world和sleep之间放上fflush,用来刷新缓冲区。

fflush(stdout)
sleep(3)

在这里插入图片描述

在这里插入图片描述

光标移到了最开头,然后刷新出来内容,再全部覆盖。去掉\r:

在这里插入图片描述

在这里插入图片描述

这时候光标就在末尾处。

了解这些后,我们做一个倒计时小程序

    int i = 9;
    for (; i >= 0; i--)
    {
        printf("%d\n", i);
        sleep(1);
    }

在这里插入图片描述

我们把/n换成/r,那么可以预想得到屏幕不打印东西。

在这里插入图片描述
光标停留在开头一段时间后,系统提示符就打印了出来,程序结束,在sleep之前加上fflush就可以正常打印,不过就是在原地打印,光标一直在数字上。

如果把9换成10,打印从10到0的数字,看起来可行,实际上却有差距。

只要是往显示器上打印的内容,都认为是字符。我们输入的123对于系统来说都是’1’ ‘2’ ‘3’。而printf函数的功能实现是把输入的转换成字符串,然后遍历字符串打印出来。

现在我们改成10,打印一下。

在这里插入图片描述

打印出10后,后面的每个数字都在覆盖的第1个数,而不是覆盖0,为了解决这个问题,我们可以使用“%2d”格式

在这里插入图片描述
即使不是两位数,但%2d也会有一个预留位,用来覆盖其他数字。

三、进度条

我们先写两个源文件和一个头文件,以及一个makefile。

proc.h
#pragma once
#include <stdio.h>

extern void process();
proc.c
#include "proc.h"

void process()
{
    printf("asdasdasd\n");
}
main.c
#include "proc.h"
int main()
{
    process();
    return 0;
}
Makefile
file:main.c proc.c
        gcc -o file main.c proc.c
.PHONY:clean
clean:
        rm -f file

开始写代码。我们要做的进度条是什么样子?要有一些符号用来从左覆盖到右,形象化地展示出来,这里就可以用到缓冲区来显示这块区域;要有一个百分比数字来表示进度。

我们先摆出最终写成的代码

#include "proc.h"
#include <string.h>
#include <unistd.h>

#define Size 102
#define Style '-'
#define Str '>'

void process()
{
    char a[Size];
    memset(a, '\0', sizeof(a));
    int i = 0;
    while (i <= 100)
    {
        printf("[%-100s][%d%%]\r", a, i);
        fflush(stdout);
        a[i++] = Style;
        if (i != 100) a[i] = Str;
        usleep(10000);
    }
    printf("\n");
}

其实本来是要一点点分析一点点写出代码的,但那样很浪费空间,篇幅长,不如看这样的文字分析。

我们所想象的进度条是一个矩形在一个框中不断往右走,直到这个框被填满。回到代码中,我们首先就需要一个数组,然后在里面不断打印更多的某个符号(这里颜色块先不说),我们先用’=‘。所以前两行建立了一个数组,并初始化,’\0’也可以换成0。

接下来进入循环,先忽略掉[%d]和%-100,我们只是打印’[%s]\r’,if判断也先不要,usleep相对于sleep可以使用更小的单位,这里的10万其实就是0.1秒,为的是更快地运行程序。如果这样打印,我们可以看到一个方括号逐渐扩大,里面符号逐渐增多的现象。这可不是我们平常所见到的进度条,方括号应当是一开始就固定好的,只是里面的符号在逐渐增多。这里我们就用左对齐或右对齐,%100s, 只不过这样从右到左打印,不符合日常印象,改成-100。符号的样式可以随便改,比如上面用的-和>。

实际效果就是这样

在这里插入图片描述
在这里插入图片描述
i为0的时候,打出 - ,i++,此时i为1,输出> ,继续循环,i为1,输出 - 覆盖了 > 。这里要考虑的问题就是越界问题,i = 100时,i ++后i为101,所以初始数组大小应为102。

这些问题解决了,还有显示进度的数字问题,[%d]即可,如果加上后面的%,%这样写其实不太行,%%即可。

不过生活中是以颜色块来显示进度的,C语言其实也可以这样。有一些C语言输出颜色的格式,可以去搜一搜。

四、了解git

git是一个管理工具,相信大多数程序员都有gitee或者github账号,本篇要写的是一些基础指令,用来在云服务器上远程管理自己的代码。

我们先创建一个新目录gitzyd,把在gitee官网自己仓库的地址给克隆过来,这样就可以在这个目录里上传代码了。

关于在gitee创建仓库,看图:

在这里插入图片描述
你可以搜索到很多开源协议的区别,这里我选择MIT,比较方便,只是自己学习代码,也不涉及版权,专利等等。一般模板选为Readme。
在这里插入图片描述
分支部分,生产/开发模型比较常用,可以共享给其他人一起使用,不过我这里是一个学习用的仓库,就只自己一个人用就行。

克隆时的代码:git clone 地址。地址可在点开仓库,代码里的克隆/下载处复制地址。
在这里插入图片描述
进入beginner,里面就有这些文件

在这里插入图片描述

把之前写的代码拷贝过来

在这里插入图片描述

现在还没有添加进仓库,只是拷贝了过来,要想添加,输入git add。意为把当前目录所有没添加的都添加进去。

添加进去后,我们要提交代码,git commit -m “日志”,这里的提交是把代码提交到本地仓库,也就是云服务器的本地仓库。初次使用git的时候,会让用户输入自己在gitee的名字以及邮箱,两条输入后,再次提交就可以了。

在这里插入图片描述

提交完自然还是不够的,我们还需要push,推送到远端。git push。会把不一样的代码放进gitee仓库里。

在这里插入图片描述

这时候你就可以看到自己的仓库有新代码了。

在这里插入图片描述

以上出现错误不要紧,指令正确的情况下,可能是需要验证。

进入gitee后,如果想看自己仓库的信息,git log。

删除文件可以用git rm 文件

查看本地和远端的同步关系,git status。

删除仓库, rm .git -rf

五、初步学会使用gdb

1、背景知识

创建一个新目录ggdb, 拷贝过来Makefile文件,创建一个新文件test.c,然后写一些代码。

在这里插入图片描述

由于int i在for循环里面,需要支持c99,如果系统出错,那就这样make。

file:test.c
        gcc -o file test.c -std=c99
.PHONY:clean
clean:
        rm -f file

在vs上调试的时候,监视,内存,打断点等等都是常有的操作,那么如何在Linux上实现?

如果我们直接gdb 可执行文件,确实会出一堆字母,但是实际上不能调试。

在这里插入图片描述
倒数第二行有个括号,里面写着 no debugging…,意思是不能调试。这是因为gcc/g++默认形成的文件为release模式,我们要换成debug模式才可以调试,在编译程序时加上-g即可。

file:test.c
        gcc -o file test.c -g -std=c99
.PHONY:clean
clean:
        rm -f file

在这里插入图片描述

想要查看debug模式和release模式下文件有什么不同,我们可以用到readelf这个指令,文件在Linux中形成时遵守的二进制排布规则就是elf。如果想要只查看dubug调试信息,readelf -S 文件 | grep -i debug。

2、部分简单指令

gdb 文件名后,l 会随机哪一行展示出来代码,l 后面跟数字就是从哪一行开始访问,0和1都是第一行。

打断点

r会自动执行完整个程序,等价于vs上的F5键;b 行号就会在那一行打上断点,想要查看断点的话info b 就可以看到打过的断点,并打印出打过几次断点,如果0次就不显示。打上断点后再次r,就会停在断点处,并给你打印出断点行的代码。想要删除断点的话, d 后面跟断点的编号,在info b时我们可以看到断点的编号。删除之后我们再次打断点,会发现断点的编号增加了,因为还没有退出gdb。

打了断点后,我们还可以让断点无效,而不是删除它,和vs功能也一样。

在这里插入图片描述

我们让它无效,然后再次让它有效

在这里插入图片描述

本篇就写到这里。下一篇继续写gdb。

结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值