• 【Linux】一些工具的简单使用,vim/gcc/gdb/make


    本篇博客将介绍linux下面一些简单工具的使用

    1.vim编辑器

    1.1安装vim

    sudo apt-get install vim
    
    • 1

    需要注意的是,vim编辑器下不能使用CTRL+S来保存文件,因为在linux中这个快捷键的作用是暂停该终端,整个系统都会卡住,这时候使用CTRL+Q取消暂停就可以了。

    1.2文本操作

    以下是命令模式下的一些文本批量化操作

    yy 复制当前行,nyy复制n行
    p  粘贴再当前行的后面,np粘贴n次剪贴板的内容
    dd 剪切(删除)当前行,ndd操作n行
    u  撤销
    ctrl+r  重做
    shift+g 光标快速定位到文本末尾
    gg 光标快速移动到文本头
    n+shift+g 光标定位到文本的第n行
    shift+4 光标定位到该行末尾
    shift+6 光标定位到该行开头
    w,b   以单词为单位进行移动光标
    h,j,k,l  左、下、上、右
    shift+`  大小写快速切换
    r   替换光标所在处的字符,支持nr
    shift+r  批量化替换
    x  删除光标所在处的字符,nx删除n个
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    vim进入插入模式的快捷键有a i o,分别对应不同的功能

    1.3底行模式的操作

    vim编辑器中底行模式的一些操作如下。在其他模式下按esc即退出到底行模式

    :w   "只保存
    :q   "不保存退出
    :wq  "保存并退出
    :reg "打开vim的寄存器面板
    :syntax on "开启语法高亮
    :set nu    "显示行号
    :set nonu  "取消行号显示
    :set tabstop=4 "设置tab的缩进,默认为8
    :set softtabstop=4 "softtabstop是“逢8空格进1制表符”,前提是你tabstop=8
    :set shiftwidth=4 "设置程序自动缩进所使用的空格长度
    :set autoindent "自动对齐上一行(这个选项会导致复制的时候代码排版混乱,可以考虑关闭,或者开启粘贴模式)
    :set paste "开启粘贴模式
    :set mouse=a "设置鼠标模式,默认是a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上面的一些配置,写入.vimrc配置文件即可长时生效。

    如果需要写入.vimrc配置文件,需要先把:注释都去掉

    2.gcc/g++编译器

    g++操作和gcc是一样的,这里我们使用gcc作为演示

    2.1linux下使用不同命令执行程序的几个阶段

    第一步是预处理,只做文本操作

    gcc -E test.c -o tset.i
    
    • 1

    在这个阶段会

    • 展开头文件
    • 对define等等操作进行替换
    • 处理条件编译指令
    • 同时删除所有注释

    编译操作

    gcc -S test.i -o test.s
    
    • 1

    汇编操作

    gcc -c test.s -o test.o
    
    • 1

    形成可执行程序

    gcc test.o -o mytest
    
    • 1

    这三个命令的顺序就是ESc其中只有-c选项是小写的

    正好就是键盘左上角esc按键的顺序

    2.2代码和库

    这里我们操作/编译的都是自己的代码。比如printf我是调用的c语言库中的函数,并没有自己完成一个打印的实现。

    这时候就需要和系统的c语言库产生关联

    c标准库的位置
    ls /lib64/libc*
    
    • 1
    • 2

    上面的最后一步形成可执行程序mytest时,系统会自动帮我们把这里的代码和库里面的方法连接起来,形成一个最终的可执行程序,并使用./mytest来执行输出结果

    所以我们平时说的装环境就是需要安装语言的静态和动态库,这样才能正常利用库里面的函数进行代码的编译处理

    同时我们在编译器里面写代码时的代码补全功能也是通过在库函数的头文件里面搜索来完成的。


    2.3动态/静态链接&库

    • 动态:linux(.so) windows(.dll)
    • 静态:linux(.a) windows(.lib)

    网吧是全校所有同学共享的,你在网吧开的机子是和别人一起用的。
    从学校去网吧(库),然后获得一台机子(库函数),打游戏(执行方法).
    这就是一个动态的编译链接的过程,即为动态库

    如果学校允许带电脑,当你想打游戏的时候用的是自己的电脑,用的是自己的方法,这种情况就是用的静态库。每一个人拥有自己的电脑,这个电脑的功能和网吧里面的功能是一样的,当我们把库中的相关代码直接拷贝到自己的可执行程序中,即为静态链接

    • 动态链接:所有人共享同一个资源
      • 优点:可以节省资源;
      • 缺点:一旦库丢失,会导致所有程序失效
    • 静态链接:都用的是自己的方法,将库里面的代码拷贝到自己的文件中
      • 优点:不依赖任何库,程序可以独立运行
      • 缺点:浪费资源

    查看链接状态,默认是动态链接

    [muxue@bt-7274:~/GIT/raspi/code/TestProgram]$ ldd mytest
        linux-vdso.so.1 =>  (0x00007ffc0dd8b000)
        /$LIB/libonion.so => /lib64/libonion.so (0x00007f89bd66c000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f89bd185000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f89bcf81000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f89bd553000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    查看可执行程序的构成

    [muxue@bt-7274:~/GIT/raspi/code/TestProgram]$ file mytest
    mytest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=7cf0ffacfdaeadf8de9b4c0fea379b2a15c37e4c, not stripped
    
    • 1
    • 2

    2.3.1手动指定进行静态链接

    gcc test.c -o mytest1 -static
    
    • 1

    静态链接生成的可执行程序大小很大,动态链接的默认是8040左右的体积。

    -rwxrwxr-x 1 muxue muxue   8416 Aug  7 07:34 mytest
    -rwxrwxr-x 1 muxue muxue 861288 Aug  7 07:44 hello
    
    • 1
    • 2

    所以一般情况下我们都推荐使用动态链接,避免占用太大的空间


    当我首次尝试这种方式的时候,出现了下面的报错

    [muxue@bt-7274:~/GIT/raspi/code/TestProgram]$ gcc hello.c -o hello -static
    /usr/bin/ld: cannot find -lc
    collect2: error: ld returned 1 exit status
    
    • 1
    • 2
    • 3

    因为系统里面默认不会带.a的静态库,所以会报错。这时候需要我们手动安装一下。

    sudo yum install -y glibc-static
    sudo yum install -y libstdc++-static
    
    • 1
    • 2

    安装成功!

    Installed:
      glibc-static.x86_64 0:2.17-326.el7_9                                                          
    Complete!
    
    • 1
    • 2
    • 3

    这时候执行就不会报错了!

    [muxue@bt-7274:~/GIT/raspi/code/TestProgram]$ gcc hello.c -o hello -static
    [muxue@bt-7274:~/GIT/raspi/code/TestProgram]$ 
    
    • 1
    • 2

    3.gdb调试

    默认生成的可执行程序是无法调试的!在linux里面发布的可执行程序默认是release版本的,无法debug

    需要添加一个-g选项进行编译

     gcc test.c -o test_g -g
    
    • 1

    同时debug版本的可执行文件也会比release版本大一些,这大的空间里面存放的就是调试信息

    -rwxrwxr-x 1 muxue muxue 8360 Aug  7 07:50 test
    -rwxrwxr-x 1 muxue muxue 9376 Aug  7 07:53 test_g
    
    • 1
    • 2

    利用下面这个语句可以查看可执行程序的调试信息

    readelf -S test | grep debug
    
    • 1

    可以看到debug版本包含了很多调试信息,而release版本里面没有

    [muxue@bt-7274:~/GIT/raspi/vim/TestGdb]$ readelf -S test | grep debug
    [muxue@bt-7274:~/GIT/raspi/vim/TestGdb]$ readelf -S test_g | grep debug
      [27] .debug_aranges    PROGBITS         0000000000000000  00001061
      [28] .debug_info       PROGBITS         0000000000000000  00001091
      [29] .debug_abbrev     PROGBITS         0000000000000000  00001122
      [30] .debug_line       PROGBITS         0000000000000000  00001164
      [31] .debug_str        PROGBITS         0000000000000000  0000119f
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.1尝试调试一个简单的代码

    以下是一些简单的gdb操作

    b 行号:打断点
    info b:查看断点
    d 断点编号: 取消断点
    l 行号:显示代码
    l main:显示包含main的那一行
    r:run,开始运行程序,跳到第一个断点
    s:step,逐语句,对应vs的F11(进入函数)
    n:next,逐过程,对应vs的F10
    c:continue,跳转道下一个断点
    p:查看变量
    display / undisplay:常显示 或 取消常显示
    until 行号:跳转到指定行
    finish:执行完一个函数后停下
    bt:查看函数调用堆栈
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    提醒:编译的时候记得加上-g选项指定debug版本

    下面是一个用于演式的示例代码

    #include 
    
    int Add(int a,int b)
    {
        printf("Add(a,b)\n");
        return a+b;
    }
    
    int main()
    {
        printf("hello wolrd!\n");
        int ret=Add(1,20);
        printf("ret: %d\n",ret);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    演示如下

    [muxue@bt-7274:~/GIT/raspi/vim/TestGdb]$ gdb test_g
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
    Copyright (C) 2013 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later 
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-redhat-linux-gnu".
    For bug reporting instructions, please see:
    ...
    Reading symbols from /home/muxue/GIT/raspi/vim/TestGdb/test_g...done.
    (gdb) l
    2
    3       int Add(int a,int b)
    4       {
    5           printf("Add(a,b)\n");
    6           return a+b;
    7       }
    8
    9       int main()
    10      {
    11          printf("hello wolrd!\n");
    (gdb) b 11
    Breakpoint 1 at 0x4005a7: file test.c, line 11.
    (gdb) ll
    Undefined command: "ll".  Try "help".
    (gdb) l 10
    5           printf("Add(a,b)\n");
    6           return a+b;
    7       }
    8
    9       int main()
    10      {
    11          printf("hello wolrd!\n");
    12          int ret=Add(1,20);
    13          printf("ret: %d\n",ret);
    14          return 0;
    (gdb) b 13
    Breakpoint 2 at 0x4005c3: file test.c, line 13.
    (gdb) r
    Starting program: /home/muxue/GIT/raspi/vim/TestGdb/test_g 
    
    Breakpoint 1, main () at test.c:11
    11          printf("hello wolrd!\n");
    Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64
    (gdb) s
    hello wolrd!
    12          int ret=Add(1,20);
    (gdb) s
    Add (a=1, b=20) at test.c:5
    5           printf("Add(a,b)\n");
    (gdb) p ret
    No symbol "ret" in current context.
    (gdb) finish
    Run till exit from #0  Add (a=1, b=20) at test.c:5
    Add(a,b)
    0x00000000004005c0 in main () at test.c:12
    12          int ret=Add(1,20);
    Value returned is $1 = 21
    (gdb) s
    
    Breakpoint 2, main () at test.c:13
    13          printf("ret: %d\n",ret);
    (gdb) p ret
    $2 = 21
    (gdb) p &ret
    $3 = (int *) 0x7fffffffdf3c
    (gdb) s
    ret: 21
    14          return 0;
    (gdb) s
    15      }(gdb) q
    A debugging session is active.
    
            Inferior 1 [process 5932] will be killed.
    
    Quit anyway? (y or n) y
    [muxue@bt-7274:~/GIT/raspi/vim/TestGdb]$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    整体的操作并不是特别复杂,大家可以自己尝试一番,有问题可以评论提出


    4.make/makefile

    这是一个批量处理工具,我们可以通过make来批量编译一些代码,避免手动敲打命令行的出错问题。这在大型项目中非常重要。

    makefile是当前路径下的一个普通文件,存放了如下内容:

    • 依赖关系
    • 依赖方法

    假设我们需要形成一个c语言的可执行文件

    依赖关系:test -> test.c
    依赖方法:gcc test.c -o test
    
    • 1
    • 2

    其对应的makefile如下

    test:test.c
        gcc test.c -o mytest
    
    • 1
    • 2

    注意,第二行的依赖方法必须tab缩进,不然无法正常调用!

    编写好makefile后,直接在当前路径下执行make。系统会自动查找名称为makefile/Makefile的文件执行

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ls
    makefile  test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ make
    gcc test.c -o test
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ls
    makefile  test  test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ./test
    hello wolrd!
    Add(a,b)
    ret: 21
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们还可以写一个清除指令,用于在编译后删除大量临时出现的可执行程序

    .PHONY:clean
    clean:
        rm -f test
    
    • 1
    • 2
    • 3

    在原本的makefile后追加这部分内容即可

    通过make clean来清理文件

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ls
    makefile  test  test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ make clean
    rm -f test
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ls
    makefile  test.c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.1出现missing separator解决方案

    当我执行make clean的时候出现了这个报错

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ make clean
    makefile:4: *** missing separator.  Stop.
    
    • 1
    • 2

    这是因为在我的makefile中,依赖方法前面的缩进是4个空格,而不是1个tab

    注意需要使用tab进行缩进,而不能手动打空格!

    4.2make如何判断需不需要重新生成?

    当我们在一个文件夹内执行过make之后,再次make,系统会提示当前的可执行程序test已经是最新版本,无需更新。

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ls
    makefile  test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ make
    gcc test.c -o test
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ ls
    makefile  test  test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ make
    make: `test' is up to date.
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    那么系统是如何实别出来我们的原代码是否有过更改的呢?

    4.2.1 stat时间戳

    我们可以使用stat命令查看一个文件的时间戳

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ stat test
      File: ‘test’
      Size: 8440            Blocks: 24         IO Block: 4096   regular file
    Device: fd01h/64769d    Inode: 1450818     Links: 1
    Access: (0775/-rwxrwxr-x)  Uid: ( 1001/   muxue)   Gid: ( 1001/   muxue)
    Access: 2022-08-07 17:18:40.463120772 +0800
    Modify: 2022-08-07 17:18:40.463120772 +0800
    Change: 2022-08-07 17:18:40.463120772 +0800
     Birth: -
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ stat test.c
      File: ‘test.c’
      Size: 201             Blocks: 8          IO Block: 4096   regular file
    Device: fd01h/64769d    Inode: 1450788     Links: 1
    Access: (0664/-rw-rw-r--)  Uid: ( 1001/   muxue)   Gid: ( 1001/   muxue)
    Access: 2022-08-07 09:30:39.043992599 +0800
    Modify: 2022-08-07 09:30:38.544992699 +0800
    Change: 2022-08-07 09:30:38.544992699 +0800
     Birth: -
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里可以看到,一个文件的时间戳分为3个,分别是Access查看、modify修改,Change更改

    第一个查看很好理解,那么modify和change有什么区别呢?

    我们可以手动修改一个程序看看情况

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ vim test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ stat test.c
      File: ‘test.c’
      Size: 207             Blocks: 8          IO Block: 4096   regular file
    Device: fd01h/64769d    Inode: 1450788     Links: 1
    Access: (0664/-rw-rw-r--)  Uid: ( 1001/   muxue)   Gid: ( 1001/   muxue)
    Access: 2022-08-07 17:25:12.958082845 +0800
    Modify: 2022-08-07 17:25:12.808082859 +0800
    Change: 2022-08-07 17:25:12.808082859 +0800
     Birth: -
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这里我通过vim进入该文件,添加了一行注释,可以看到,相比于之前的时间,3个时间戳都被修改成了最新的时间。这是因为我们修改文件的时候一定会查看,也有modify和change

    而如果我只是修改这个文件的权限,并不修改它的内容,会发生什么?

    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ chmod o-r test.c
    [muxue@bt-7274:~/GIT/raspi/vim/TestMake]$ stat test.c
      File: ‘test.c’
      Size: 207             Blocks: 8          IO Block: 4096   regular file
    Device: fd01h/64769d    Inode: 1450788     Links: 1
    Access: (0660/-rw-rw----)  Uid: ( 1001/   muxue)   Gid: ( 1001/   muxue)
    Access: 2022-08-07 17:25:12.958082845 +0800
    Modify: 2022-08-07 17:25:12.808082859 +0800
    Change: 2022-08-07 17:27:34.378068762 +0800
     Birth: -
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以看到,只有change发生了变化。

    文件=内容+属性,在这里的modify对应的就是内容修改,而change对应的是属性修改。而当我们修改文件内容的时候,会引起文件大小的变化,也是属性变化,所以修改内容也可能会引起change的变化!


    了解了这个时间戳,那么系统是怎么判断是否需要重新生成就很简单了:比较依赖关系中左边的目标文件和右边源文件的modify时间,如果源文件的modify时间早于目标文件,那么说明目标文件生成之后,源文件并没有发生更改,那么也无需再次生成

    4.2.2 PHONY关键字的作用

    在前面提到的clean代码中,我们使用了.PHONY关键字来修饰clean。

    这个关键字让clean作为一个伪目标,且总是被执行

    • 怎么理解这个总是被执行?

    当我们的源文件没有发生更改的时候,make不会重新生成,这个叫做总是不被执行

    • PHONY关键字的作用就是屏蔽系统对于modify时间的检查,每一次都会强制执行该语句的依赖方法。

    一般情况下我们只有在clean的时候才会使用.PHONY关键字来修饰


    5.尝试编写一个简单的linux进图条

    当我们在linux系统上下载一些软件的时候,总是可以看到用文字组成的进度条,这些进图条是怎么做出来的呢?

    下面我们可以尝试用C语言写出一个简单的进度条。在这之前,我们需要了解一些概念

    5.1 缓冲区

    在我之前的C语言文件操作博客中,提到了一个缓冲区的概念。简单来说,当我们printf一道字符串的时候,系统是先把这个字符串写入缓冲区,再把缓冲区的内容输出到屏幕上

    比如下面这个代码,再linux环境中,\n会自动刷新缓冲区。

    #include 
    #include 
    int main()
    {
    	while (1)
    	{
    		printf("hehe\n");
    		//在linux环境中,不带'\n'的时候,并不会打印(没有刷新缓存区)
    		//而在VS环境中,带不带都会正常打印
    		sleep(1);//linux环境中,sleep函数的参数,单位是秒(VS是毫秒)
            //             linux环境下,sleep函数需要小写,VS下是Sleep
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果我们去掉\n,系统则不会立即打印内容。

    image-20220807174345248

    这时候需要我们手动用fflush(stdout)刷新一下缓冲区,现在程序会在一行中打印了

    fflush(stdout);//手动刷新缓冲区
    
    • 1

    image-20220807174517362

    5.2 回车和换行

    在我们日常生活中提到的换行一般指的是回车+换行

    实际上,回车和换行是有区别的:

    • 回车:光标回到该行的最前面
    • 换行:光标去到下一行,但是位置不变

    在C语言中,\n执行的就是回车+换行,而\r是回车

    那么我们就可以利用这个特性,来实现一个简单的倒计时

    #include 
    #include 
    int main()
    {
        int i=9;
    	while (i>=0)
    	{
    		printf("%d\r",i);
    		//在linux环境中,不带'\n'的时候,并不会打印(没有刷新缓存区)
    		//而在VS环境中,带不带都会正常打印
             fflush(stdout);//手动刷新缓冲区
    		sleep(1);//linux环境中,sleep函数的参数,单位是秒(VS是毫秒)
            //             linux环境下,sleep函数需要小写,VS下是Sleep
            i--;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    GIF


    5.3 进度条

    做好前面的准备工作后,现在我们就可以来打印一个简单的进度条了!

    #include 
    #include 
    #include 
    
    #define NUM 102
    #define STYLE '#'
    
    void process()
    {
        char bar[NUM];
        memset(bar, '\0', sizeof(bar));
    
        const char *lable = "|/-\\";//在末尾打印一个转动的“小圆圈”
    
        int cnt = 0;
        while(cnt <= 100)
        {
            //默认是右对齐,使用-改位左对齐
            printf("加载中:%-100s[%d\%][%c]\r", bar, cnt, lable[cnt%4]);
            fflush(stdout);
            bar[cnt++] = STYLE;//打印预定义的符号
            usleep(200000);
        }
        printf("\n");
    }
    
    int main()
    {
        process();
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    GIF

    这样一个简单的进图条就搞定辣!

    后记

    linux中一些工具的使用可能不会有windows的编译器那么方便,比如GDB调试。但是在后续编写一些只有linux平台才能运行的代码的时候,我们必须学会使用这些工具,否则操作起来会非常麻烦!

    感谢你看到最后,有任何问题都欢迎在评论区提出哦!

  • 相关阅读:
    小白也可以玩转CMake之常用必备
    使用fastapi和pulumi搭建基于Azure云的IAC Restful API服务 — 对外发布
    spring的学习【1】
    如何在 🤗 Space 上托管 Unity 游戏
    LeetCode 每日一题 2022/11/14-2022/11/20
    线性规划在多种问题形式下的应用
    手机端侧文字识别:挑战与解决方案
    全栈性能测试工具:RunnerGo
    Yolov5斜框检测tensorrt部署(C++)从入门到入坟
    ROS基础
  • 原文地址:https://blog.csdn.net/muxuen/article/details/126206777