当前位置: 首页 > news >正文

【Linux基础】基本开发工具的使用

目录

一、编译器——gcc/g++的使用

gcc/g++的安装

gcc的安装:

g++的安装:

gcc/g++的基本使用

gcc的使用

g++的使用

动态链接与静态链接

程序的翻译过程

1. 一个C/C++程序的构建过程,程序从源代码到可执行文件必须经历四个阶段

2. 理解选项的含义

第一步预处理:

第二步编译: 

第三步汇编: 

第四步链接: 

动静态链接的认识

验证我们所写的程序是动态链接还是静态链接

file 可执行文件

ldd 指令

静态库的安装

C语言安装静态库:

C++安装静态库:

静态链接

二、项目自动化构建工具——make/Makefile

make与Makefile的概念

Makefile的原理

Makefile的语法

依赖关系和依赖方法

项目清理

如何理解 .PHONY 修饰的是一个伪目标

我们可以知道被.PHONY修饰的对象总可以被执行

gcc 如何得知 mytest 是最新呢 

如何证明 gcc 根据修改的时间得知 mytest 是最新

Makefile的推导规则

三、版本控制器——git

git 是什么

git 的操作

1. 进入gitte官网,先新建一个仓库

2、Linux中提交代码操作

1. git clone拉取远端仓库克隆到本地(目录克隆到本地)

2. git add . 把需要提交的目录(项目)复制或剪切到本地仓库

3. git commit -m  ‘提交日志’  修改之后的代码添加进去提交本地库

4. git push 推送到远程仓库,这才是把本地仓库的代码推送至远程仓库

5. 如果在远端我们的代码修改了,git status 查看 git 的状态 

6. git log 查看提交历史记录

四、调试器——gdb

调试之前我们先创建文件以及准备调试代码

test.c 文件

编译成debug版本

gdb 的使用

gdb的安装

​编辑

基本使用

① l 查看代码

② b 打断点、info查看断点、d 删除断点

③ r 开始调试,调试起来

④ n 逐过程、s 逐语句

⑤ c 运行到下一个断点处

⑥ bt 查看调用堆栈

⑦ finish 运行完当前函数

⑧ p 查看变量值

⑨ display 常显示变量的值、undisplay取消常显示

⑩ until 跳出循环

⑪ info locals 查看特定区域的临时变量

五、Linux小程序——进度条的实现

基本概念

fflush的使用

回车换行的理解

倒计时程序的实现

进度条的实现

process.h

process.c

main.c

Makefile


一、编译器——gcc/g++的使用

gcc/g++的安装

gcc的安装:

yum install -y gcc

g++的安装:

yum install -y gcc-c++ libstdc++-devel

gcc/g++的基本使用

我们在使用 gcc/g++ 进行编译的时候一般都带选项: -o

gcc -o test test.c 这个命令中,gcc编译器会对test.c这个源文件进行编译和链接操作。正常情况下,如果没有-o选项,gcc会生成一个默认名称的可执行文件(在 Linux 等系统下通常是a.out)。

但是当使用-o test时,编译器会将生成的可执行文件命名为test,而不是默认的a.out

注意:gcc -o test test.cgcc test.c -o test 这两种写法都是正确的。在这两种情况下,gcc编译器都能够理解-o test是要将编译生成的可执行文件命名为test,而test.c是要编译的源文件。

gcc的使用

g++的使用

动态链接与静态链接

我们在学习动态链接与静态链接的时候需要对程序的翻译过程进行复习一下,这都是我们C语言阶段就学习过的内容。

程序的翻译过程

1. 一个C/C++程序的构建过程,程序从源代码到可执行文件必须经历四个阶段
  • 预处理:头文件的展开、宏替换、条件编译、去掉注释     
  • 编译:检查语法错误,将预处理后的源代码生成为汇编代码 
  • 汇编:汇编代码转换成二进制的机器码   
  • 链接:多个目标文件的文件链接成一个可执行文件
2. 理解选项的含义

当生成了一个可执行文件,但是我们并不想让他直接编译完成,编译的过程是一下就走完了,而接下来我们想看他的过程,就在编译的时候带上选项就可以查看每一个阶段的过程。

注意:C++同样是这种过程。

在测试之前我们重新在 test.c 中编写一个用于测试的代码 

#include <stdio.h>    
#define N 20    
int main()     
{    //测试去掉注释    printf("hello wolrd 1\n");    //printf("hello wolrd 2\n");    //printf("hello wolrd 3\n");    //printf("hello wolrd 4\n");    //printf("hello wolrd 5\n");    //printf("hello wolrd 6\n");    //printf("hello wolrd 7\n");    //printf("hello wolrd 8\n");    //printf("hello wolrd 9\n");    //printf("hello wolrd 10\n");    //测试条件编译    
#ifdef CONDITION    printf("condition\n");    
#else    printf("no condition\n");    
#endif       //测试宏替换    printf("宏:%d\n", N);    return 0;    
} 
第一步预处理:

选项 -E 从现在开始,进行程序的翻译,当你将预处理做完,就停下来。      

如果去掉 –o 预处理这么多内容打印到显示器上特别不好看,选项 -o: 指明形成的临时文件名称 .i, 使用 .i 作为预处理文件的扩展名是一种比较常见的约定,就像c语言文件名后缀是 .c一样。

观察下面的代码,我们可以看到多了800多行代码,这就是头文件的展开,把库中的代码拷贝过来了。

然后就进行了宏替换,预处理阶段就已经做了的。

最后只剩hello world 1,这就是去掉注释。

条件编译这里把这个没有的也裁掉了,这就是条件编译。

注意:我们要用的头文件、必须在C语言库中存在,平时在某个平台写代码的时候,头文件必须在该系统中存在 , Linux中库头文件在 /usr/include/stdio.h 目录下,平时我们安装VS2022,同时也会把头文件库文件安装到v2022所对应的目录下,这也就是我们为什么写代码可以自动补齐的原因

gcc -E test.c -o test.i

我们不定义CONDITION也可以通过传参来定义 

第二步编译: 

编译:把c语言代码变成汇编代码。

选项 -S:从现在开始,进行程序的翻译,做完编译工作,变成汇编之后,就停下来。

编译之后Linux下通常以 .s后缀结尾作为存储汇编代码的文件

gcc -S test.i -o test.s

第三步汇编: 

汇编语言不能被计算机直接执行,把汇编变成二进制目标文件

选项 -c:将汇编代码转成二进制目标文件就停下来,没有进行链接。

vim  test.o 进入该文件我们看不懂,但是可以 od test.o进行阅读该二进制文件。

test.o虽然是二进制文件,但是不能被执行,我们可以加上权限,发现还是不能被执行,原因在于少了一步链接,这三个步骤只在编译你写的代码,比如你在c语言上的printf的函数是你写吗,你只是调用了printf,printf的实现你没有写。

gcc -c test.s -o test.o

我们执行该目标文件发现不能被执行,原因是因为缺少一步链接

第四步链接: 

我们把前面三个步骤完成之后就可以进行链接操作了,链接是将多个目标文件以及所需的库文件整合在一起的关键过程。

把你写的代码和 C标准库中的代码合起来:这就是链接的过程,可以不带任何选项

gcc test.o –o mytest 

链接就形成了可执行程序,形成可执行的二进制程序(库+你的代码)。

gcc test.o -o mytest

动静态链接的认识

我们要明白自己编写的代码与库中的代码是不同的。像 C 标准库,是他人事先准备好以供我们直接使用的。比如我们在代码里写了像printf这类库函数的调用语句,实际上我们只是进行了调用,并没有去实现这些函数。只有在进行链接这一环节时,库函数对应的具体实现才会和我们写的代码关联起来。

 

而链接的本质,核心就是解决我们调用库函数时,如何与标准库(或其他相关库)建立关联的问题,这其中就涉及到选择动态链接还是静态链接的方式。动态链接是在程序运行时按需加载共享库来获取函数实现,而静态链接则是在链接阶段直接把库函数的代码复制到可执行文件当中。

  • 动态链接
    • 优点
      • 资源节省:可执行程序体积小,因为不包含库代码,运行时才加载共享库,节省内存、磁盘和网络资源。例如多个程序共享动态库内存实例。
      • 更新方便:库更新时,只要接口兼容,程序无需重新编译就能使用新功能。
    • 缺点
      • 运行依赖:依赖外部环境,缺少库或版本不匹配时程序无法运行。
      • 性能损耗:启动要加载库,运行中调用库函数有系统开销,影响性能和启动速度。
  • 静态链接
    • 优点
      • 独立稳定:不依赖外部库,库升级、删除或移动不影响程序运行,程序有很好的稳定性。
      • 行为可预测:运行行为由自身代码决定,便于在不同环境部署和调试。
    • 缺点
      • 资源占用:可执行程序体积大,占用更多磁盘和内存空间,多个程序用相同静态库会有代码冗余。
      • 更新不便:库更新时,程序要重新编译才能使用新功能,大型项目中耗时耗资源。

动静态库可以类比成摄影爱好者与照片滤镜库

假设你是一个摄影爱好者,你有一部相机(相当于程序本身),你平时会拍摄各种各样的照片(程序执行各种任务)。

动态库的情况

现在有一个非常流行的在线照片滤镜应用(相当于动态库)。当你拍完照片后,你想要给照片添加一些特殊的滤镜效果,但是你的相机本身没有这些滤镜功能(就像程序本身没有这个功能的实现)。

你打开相机中的一个连接功能(相当于程序中的函数调用接口),连接到这个在线滤镜应用。每次你想要使用一个滤镜的时候,相机就会通过网络(相当于运行时环境)向这个在线滤镜应用发送照片和滤镜请求(就像程序运行时请求动态库中的功能,这就是动态链接)。这个在线滤镜应用会处理你的照片,添加滤镜后再把处理后的照片发送回你的相机(就像动态库提供功能实现并返回结果)。

很多摄影爱好者都可以使用这个在线滤镜应用(多个程序共享动态库)。而且,如果这个滤镜应用更新了新的滤镜效果或者优化了滤镜算法(动态库更新),只要相机和滤镜应用之间的连接方式(接口)不变,你的相机依然可以使用这些新功能来处理照片。

静态库的情况

后来,你发现每次连接到在线滤镜应用很麻烦,而且有时候网络不好就没办法使用滤镜。于是你购买了一个带有大量滤镜功能的存储卡(相当于静态库),这个存储卡可以插入你的相机。

当你把存储卡插入相机后,相机就把存储卡里的滤镜功能(就像静态库中的代码)复制到了相机内部的可用功能列表中(就像静态链接把库代码复制到可执行文件,这就是静态链接)。现在你拍摄完照片后,想要添加滤镜,相机就可以直接使用存储卡里已经复制过来的滤镜功能来处理照片,不需要再连接到外部的在线滤镜应用(不依赖外部库运行)。即使这个在线滤镜应用因为某些原因停止服务(比如公司倒闭等情况,就像动态库不可用),你依然可以在相机里使用这些滤镜功能来处理照片。

验证我们所写的程序是动态链接还是静态链接
file 可执行文件

ldd 指令

ldd  可执行文件 用于查看程序(可执行文件或共享库)依赖的动态共享库的工具。当你运行ldd命令并跟上一个可执行文件的名称时,它会显示该可执行文件在运行时需要加载的动态库的路径和名称等相关信息。

静态库的安装

默认情况下都是动态链接的,如果我们想要静态链接需要怎么办呢?

ls  /lib64/libc.a   不一定存在静态库,静态库不存在需要自己安装。

C语言安装静态库:
yum install -y glibc-static
C++安装静态库:
yum install -y libstdc++-static

静态链接

在系统中,C 动态库(也称为共享库)是被多个使用该库的程序所共享的。尽管使用 C 动态库的程序众多,但通常系统中只存在一份该动态库的物理副本。这体现了动态库的共享特性,即多个程序在运行时可以同时访问并使用这同一个动态库,避免了库代码在内存中的重复存储,从而节省了系统的内存资源。例如,标准 C 库(如libc.so)被众多的 C 语言程序所依赖,在系统运行时,这些程序通过动态链接的方式引用libc.so,而无需各自拥有一份独立的libc.so代码副本。

静态链接并不是拷贝动态库内部的代码。静态链接是在程序编译阶段,将所需的库代码(通常是静态库,以.a结尾)直接复制到可执行文件中,使其成为可执行文件的一部分,从而在运行时不再依赖外部的库(包括动态库)。所以,静态链接与动态库的机制是相互独立的,静态链接不会直接操作动态库的代码。

Windows动静态链接的原理是一样的,动态库通常以.dll为后缀,静态库一般是以.lib为后缀

 我们也可以用C++进行静态链接


二、项目自动化构建工具——make/Makefile

make与Makefile的概念

make 是一个命令,Makefile是一个文件。

make与Makefile存在的意义:

Makefile 所带来的好处集中体现在自动化编译方面。这并不意味着完全无需人工干预,而是在初始阶段,开发人员需要根据项目的结构和需求编写 Makefile 文件,精心规划好源文件与目标文件的依赖关系以及相应的编译规则。一旦 Makefile 文件编写完成,后续使用 Make 命令时,它会自动读取 Makefile 中的内容,按照既定的规则和依赖关系,有条不紊地对程序或项目进行编译,无需开发人员再次手动调整编译过程。这使得在项目开发过程中,无论是对单个源文件进行修改后重新编译,还是对整个项目进行全新构建,都能够通过简单地执行 Make 命令快速、准确地完成,从而实现了高效、稳定的自动化构建过程,为软件开发的迭代和维护提供了有力支持。

注意: Makefile的 m 可以大写也可以小写。

我们可以来使用一下Makefile,下面会说明Makefile

就是不用再手写gcc了,直接make就可以了,看起有点弱,其实慢慢就会发现这个Makefile很强

Makefile的原理

Makefile 必须包含依赖关系和依赖方法这两个关键要素,其存在意义在于为构建项目提供自动化支持,使项目能够依据文件间的依赖关系和生成方法,有条不紊地完成编译、链接等构建流程,避免手动操作的繁琐与易错性,高效达成项目构建这一目标。

Makefile 的运行就如同生活中的一个场景。比如,当你打电话说 “爸,我是你儿子”,此时这仅仅建立了一种依赖关系,即你依赖于自己的父亲,但仅凭这一句,父亲并不清楚你到底想要做什么,事情自然无法推进,这是因为缺少依赖方法。再比如,你不可能去找室友的爸爸借钱,原因是你和室友的爸爸之间不存在任何依赖关系。只有当你既明确了依赖关系,像打电话跟自己的爸爸表明身份,又清晰地阐述依赖方法,例如接着说 “我没钱吃饭了,给我打点钱吧”,这样依赖于父亲打钱这件事情才能够完成。在 Makefile 中也是如此,只有同时具备依赖关系和依赖方法这两个关键要素,项目构建这件事情才能够顺利实现。

Makefile的语法

依赖关系和依赖方法

第一行整体我们称为:依赖关系。
mytest : test.c
目标文件(可执行程序/临时文件) :  依赖文件列表, 这里只有一个依赖文件
这里表示 mytest  依赖于test.c

第二行整体我们称为:依赖方法

写完了Makefile,我们make一下就会生成可执行文件,然后运行该文件就可以了

项目清理

随着项目的不断编译和构建,会产生许多可执行程序以及一些诸如目标文件(.o文件)、中间编译文件等临时文件。有时候,我们可能想要重新编译整个项目,或者不想保留这些已生成的可执行程序和临时文件了(比如它们占用了过多磁盘空间,或者之前的编译结果出现了一些未知问题想要重新开始等情况),这时候就需要一种方法来清理它们。

如何清理:

vim Makefile 进入Makefile之后接着往下输入

clean : 这里可以为空(依赖关系可以为空,也就说clean不依赖与任何文件)

在下来 tab 开头的就是依赖方法

我们再用 .PHONY 修改 clean

红色为伪目标 .PHONY 修饰的是一个伪目标

为什么make 和 make mytest 也是可以,而 clean 要 make clean

第一个遇到的可以省略名称,仅此而已,默认情况下只形成一个目标文件(可执行目标文件),不指名默认就是第一个。

如何理解 .PHONY 修饰的是一个伪目标

当我们不断 make 的时候,会发现不让你编译了,因为是最新的,没有修改没必要重新编译

可是当我们再不断调用 make clean 的时候总是能执行 rm –f  mytest

我们可以知道被.PHONY修饰的对象总可以被执行

但是我们一般不会这样做,将我们生成的可执行程序用.PHONY修饰, 但是这都不是重要的,

最重要的是 gcc 如何得知 mytest 是最新呢???

我们再改回原来的Makefile

gcc 如何得知 mytest 是最新呢 

肯定跟时间有关系,在我们学习指令的时候,就接触过一个指令 stat,stat命令是一个用于查看文件或文件系统状态信息的工具。

Access(访问时间):这是文件最后一次被访问(如查看内容)的时间。

Modify(修改时间):记录文件内容最后一次修改的时间。

Change(改变时间):是文件元数据(属性,如权限、所有者等)最后一次改变的时间。

为什么change会随着modify的改变而改变呢???

当我修改了文件内容,modify修改了,change也会随着修改,因为文件的大小变化了,也意味着文件的属性也跟着变化,所以change会改变。

Change 和 Modify 的时间变化能够理解,但是为什么Access是指我们cat访问/vim查看该文件的时间,为什么没有任何的变化???

访问文件不一定改内容,改内容一定访问,如果每次访问都修改时间,导致Access修改的频率太多了,就需要在磁盘进行多次的 IO(输入 / 输出)操作,别人设置文件让别人阅读,就不在过于关心访问时间,如果别人修改了文件时间立马更新Modify时间,所以操作系统采用的是你访问次数达到多少次就更新一次Access的时间,这种策略,没有什么规律,我们主要关注 Change 和 Modify。

我们现在知道了这么多时间,但是和 gcc 有什么关系??? 它怎么知道我们文件是最新的??? 

先有源文件 test.c,再有可执行程序 mytest

test.c Modify 的时间 一定比 mytest Modify 的时间要更早
如果 test.c 里面有bug改了一下里面的内容,然后就会更新源文件test.c 的 Modify的时间,这个时候,test.c 里面的时间就是新的,比 mytest 的时间新了,就是比较两个时间的新旧。

如何证明 gcc 根据修改的时间得知 mytest 是最新

我们知道一个指令touch,除了创建文件还可以修改时间

touch 可以更新文件的时间

综上所述:凡是用.PHONY修饰的就是不要拿时间作对比了,你每次都执行一下,不要遵守时间对比的规则,每次都要执行依赖方法,而没有使用 .PHONY修饰的就是对比源文件的时间和可执行的时间变化来确定是不是需要进行编译。

Makefile的推导规则

程序的翻译过程从预处理、编译、汇编、链接
文件从 test.i  -> test.s  -> test.o
我们的可执行文件 mytest 依赖于 test.o
而 test.o 依赖于 test.s
而 test.s 依赖于test.i

我们在日常写Makefile中我们直接一步到位,直接写依赖于源文件就可以了。


三、版本控制器——git

今天,就让我们一起来学习一下个人使用 git 提交代码的基本操作流程吧,后续更复杂的冲突处理、分支协作等内容我们可以再逐步深入学习。

git 是什么

git 就像是一个超级智能的代码 “时光机”。假设你在写代码,就好像在创作一幅复杂的画作。每次你对代码进行修改,无论是添加新功能、修复小错误还是优化性能,git 都能帮你记录下这个 “画作”(代码)的不同状态。

 

比如说你写一个 C++ 程序,最开始只有一个简单的打印 “Hello, World!” 的功能,这是你代码的最初版本,git 就像一个相册,把这个初始版本保存了下来。之后你添加了一个计算两个数字相加的函数,git 又会把这个有新功能的版本记录下来,就好像在相册里新增了一张带有新内容的照片,你还可以找到原来记录下的版本(可以回顾不同的版本)。

git 的操作

1. 进入gitte官网,先新建一个仓库

 gitte官网:Gitee - 基于 Git 的代码托管和研发协作平台

 进入官网之后我们先创建一个仓库

初始化仓库,设置仓库模板,选择分支,我们先这样进行创建,后续需要深入学习git

远端就会形成一个这个仓库 

2、Linux中提交代码操作

git 的安装:

sudo yum install -y git

准备我们要提交的代码文件

1. git clone拉取远端仓库克隆到本地(目录克隆到本地)

我们暂时先使用HTPS,因为比较简单如果用SSH,还需要进行配置

先复制好,然后进入Linux指令行中输入 git clone 粘贴刚刚复制的内容

git clone:把远端仓库克隆到本地

当我们克隆到本地的时候,有时候可能需要输入自己gitee的账号和密码

Linux中进入该仓库,而远端隐藏了.git文件

注意点: 当我们首次安装好了git之后系统会提示你进行配置 用户名 和 邮箱

要将码云(Gitee)的仓库与 Linux 系统关联起来

配置 Git 用户名和邮箱(如果还没配置的话)---我们在提交的过程中会出现提示

git config --global user.name "你的gitte用户名"git config --global user.email "你的邮箱"
2. git add把需要提交的目录(项目)复制或剪切到本地仓库

git add相当于添加到临时仓库(还没提交到本地库),相当于一个 "准备区"

3. git commit -m  ‘提交日志’  修改之后的代码添加进去提交本地库

git commit -m  ‘提交日志信息’ 这个日志必须写,也不要乱写。
这才是提交到了本地仓库 但是远端仓库还没没有提交,所以我们需要推送到远端仓库

4. git push 推送到远程仓库,这才是把本地仓库的代码推送至远程仓库

我们查看远端仓库发现多了一个我们提交的文件

5. 如果在远端我们的代码修改了,git status 查看 git 的状态 

如果远程库和本地库没有同步的话,我们就 git pull 先把远端的拉到本地,同步一下,然后再进行 push

pull 的本质就是强制我们每一个人必须和远端仓库保持一致,不一致了就pull一下。

git pull 同步远程仓库,本地库与远程仓库保持一致

如果你本地要删除这个文件都在前面加上 git 

6. git log 查看提交历史记录


四、调试器——gdb

  • 在调试思路上,无论是在 Windows 还是 Linux 系统下,目的都是为了找出代码中的错误。都需要关注变量的初始化、赋值、变化过程,检查函数的参数传递是否正确、函数内部逻辑是否正确,以及循环结构是否按照预期执行(如循环次数是否正确、循环体中的逻辑是否正确等)。
  • 比如,在检查一个计算数组元素总和的函数时,都需要考虑是否正确地遍历了数组,是否正确地累加了元素的值,思路都是从程序的输入、中间处理过程到输出,逐步验证代码的正确性。

调试之前我们先创建文件以及准备调试代码

test.c 文件

#include <stdio.h>// 函数用于统计给定范围内能被divisor整除的数的个数及它们的和
void countAndSum(int start, int end, int divisor, int *count, int *sum) {*count = 0;*sum = 0;int i = 0;for (i = start; i < end; i++) {  // 这里循环条件有错误,少包含了边界值end,应该是i <= end,导致可能少统计一些数if (i % divisor == 0) {(*count)++;*sum += i;}}
}int main() {    int start = 1;    int end = 18;int divisor = 3;    int count;    int sum;                                                                                                                       countAndSum(start, end, divisor, &count, &sum);    printf("在 %d 到 %d 范围内,能被 %d 整除的数有 %d 个,它们的和是 %d\n", start, end, divisor, count, sum);    return 0;    
}    

编译成debug版本

在学习C语言的时候我们就知道编译存在两种版本:一种是release发布版,目的:主要用于向用户发布最终产品,另一种是debug调试版,目的:专为开发人员在开发和调试阶段使用。

要用 gdb 调试,变成debug版本才可以调试,首先要进行给编译条件添加 -g,表示生成debug 版本

gdb 的使用

我们要调试,直接 gdb 可执行程序,发现我们还没有gdb,所以需要安装

gdb的安装

sudo yum install -y  gdb

基本使用

① l 查看代码

l 的全称是 list

l 0 从0行显示,想再往后显示不需要输指令了,直接回车可以继续往下显示代码。

② b 打断点、info查看断点、d 删除断点

打断点:b  全称 breakPoint  b 20    b 23都是打断点

查看断点: info b

去掉断点:d  全称 deletePoint     d 24这样删除不了断点,删除是删除断点编号,添加断点之后就有了断点编号。

③ r 开始调试,调试起来

程序跑起来,在断点处停下来,r  全称run

r 相当于 Visual Studio下的 F5开始调试,VS 下 F5开始调试:有断点就在断点处停下来,没有断点就直接跑完了,到另外一个断点还是F5。

④ n 逐过程、s 逐语句

启动调试之后下一步就可以逐过程 F10,这里是 n  全称next 一行一行往下走

想进入这个函数逐语句 F11,这里是 s  全称 step,可以进入某个函数

⑤ c 运行到下一个断点处

c  全称continue运行到下一个断点  可以一直c运行到下一个断点处

⑥ bt 查看调用堆栈

s进去一个函数后, bt 查看函数的调用堆栈,出了函数后还可以继续查看调用堆栈

⑦ finish 运行完当前函数

通过这个finish可以确定这个函数是否存在错误

⑧ p 查看变量值

p 只能临时查看,我们要边看边调试变量的值。

⑨ display 常显示变量的值、undisplay取消常显示

常显示可以显示变量值和地址,也可以取消变量值和地址,但是取消的时候也是取消编号。

取消常显示

until 跳出循环

如果问题不在循环里面我们要跳出这个循环,直接until,然后继续 n 往下走

info locals 查看特定区域的临时变量


五、Linux小程序——进度条的实现

基本概念

fflush的使用

这个代码会先出现 hello world,然后休眠 2 秒。

如果我们去掉\n就没有打印内容,两秒之后内容才打印出来,这里先执行的是printf,然后执行的是sleep,因为我们的代码是顺序结构。


先执行printf不等于数据先显示,printf已经执行完了,只不过数据在缓冲区里面,没有显示出来 ,缓冲区我们不知道是什么,我们目前只需要知道它是一块内存就够了,如果我们想要这个内容刷新出来,可以使用 fflush(stdout)。

而 \n 刷新的是行缓冲。

fflush(stdout)刷新缓冲区 

回车换行的理解

有一组概念回车换行,回车换行是两个概念,回车是回到当前行的开始,换行是换到下一行   \r  回车 

\n 换行 

\r\n 回车换行

注意:语言层面 \n 就是回车换行

倒计时程序的实现

有了这两个基础铺垫,我们就可以完成一个简单的倒计时了。

反斜杠n就是回车换行,我们不能使用回车换行,我们就用反斜杠 r

fflush(stdout)刷新缓冲区 

进度条的实现

有了这些基础之后,我们实现这个进度条就很容易上手了。

进度条一定是循环的,头文件不需要在Makefile中写,因为会在源文件中展开。

注意点:\是C语言中的特殊字符,如果我们要显示 \ 就需要\\

               模上4之后范围就在0-3

我们先把文件建立好,写好之后先简单的测试一下Makefile是否正确

process.h

#pragma once     
#include <stdio.h>    
#include <unistd.h>    
#include <string.h>    
#define NUM 101    
//#define STYLE '#'    
#define S_NUM 5      
//函数的声明                                                                                                              
extern void ProcessOn(); 

process.c

  #include "process.h"    //函数的实现void ProcessOn(){int cnt = 0;//字符数组char bar[NUM];//进度条样式 char STYLE[S_NUM] = {'+','#','@','*','&'};//初始化bar                                                                                                                   memset(bar,'\0',sizeof(bar));//旋转光标            const char* lable = "|/-\\";while(cnt <= 100)     {                     //控制格式        printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%4]);fflush(stdout);   
E>       bar[cnt++] = STYLE[N];                  usleep(50000); //1秒 = 10000毫秒,3秒跑完}                           printf("\n");               }                              

main.c

#include "process.h"                                                                                                               
int main()    
{    ProcessOn();    return  0;    
}    

Makefile

ProcessOn:main.c process.c    gcc main.c process.c -o ProcessOn -DN=1  #-D定义宏                                                                             
.PHONY:clean                                                           
clean:                                                                 rm -rf ProcessOn                                                                   

相关文章:

【Linux基础】基本开发工具的使用

目录 一、编译器——gcc/g的使用 gcc/g的安装 gcc的安装&#xff1a; g的安装&#xff1a; gcc/g的基本使用 gcc的使用 g的使用 动态链接与静态链接 程序的翻译过程 1. 一个C/C程序的构建过程&#xff0c;程序从源代码到可执行文件必须经历四个阶段 2. 理解选项的含…...

C++ 中面向对象编程如何实现动态绑定?

在 C 中&#xff0c;面向对象编程的一个重要特性就是动态绑定。动态绑定允许在程序运行时根据对象的实际类型来决定调用哪个函数&#xff0c;这为程序的灵活性和可扩展性提供了强大的支持。本文将详细介绍 C 中面向对象编程如何实现动态绑定。 一、静态绑定与动态绑定的概念 静…...

电源芯片的SYNC引脚

-----本文简介----- 主要内容包括&#xff1a; ① 电源芯片的SYNC引脚 ----- 正文 ----- 先赞↓后看&#xff0c;养成习惯&#xff01; 1. SYNC引脚是什么&#xff1f; 电源芯片里面的SYNC引脚是 Synchronization clock in&#xff0c;意思是同步时钟输入。 2. SYNC引脚的作用…...

安卓报错Switch Maven repository ‘maven‘....解决办法

例如&#xff1a;Switch Maven repository ‘maven(http://developer.huawei.com/repo/)’ to redirect to a secure protocol 在库链接上方添加配置代码&#xff1a;allowInsecureProtocol true...

935. 骑士拨号器

935. 骑士拨号器 题目链接&#xff1a;935. 骑士拨号器 代码如下&#xff1a; class Solution { public:int knightDialer(int n) {if (n 1){return 10;}long long res 0;for (int j 0; j < 10; j){res dfs(n - 1, j);}return res % MOD;}int dfs(int i, int j){if (…...

linux下的posix信号量

目录 引言 信号量背景知识 PV操作 信号量接口 基于环形队列的PC模型 代码实现 demo模型 具体实现 引言 在多线程编程领域&#xff0c;同步机制是确保数据一致性和避免竞态条件的关键技术。Linux操作系统作为开源软件的杰出代表&#xff0c;提供了多种同步原语&#xf…...

【JavaWeb后端学习笔记】Spring框架下的Bean管理

Bean 1、Bean的获取2、Bean的作用域3、第三方Bean 1、Bean的获取 默认情况下&#xff0c;Spring项目启动时&#xff0c;会把Bean创建好交给IOC容器管理。当需要使用时&#xff0c;通过Autowired注解注入或者通过构造方法注入即可。 除此之外还可以通过Spring提供的Applicatio…...

如何在 ASP.NET Core 3.1 应用程序中使用 Log4Net

介绍 日志记录是应用程序的核心。它对于调试和故障排除以及应用程序的流畅性非常重要。 借助日志记录&#xff0c;我们可以对本地系统进行端到端的可视性&#xff0c;而对于基于云的系统&#xff0c;我们只能提供一小部分可视性。您可以将日志写入磁盘或数据库中的文件&#xf…...

Photoshop提示错误弹窗dll缺失是什么原因?要怎么解决?

Photoshop提示错误弹窗“DLL缺失”&#xff1a;原因分析与解决方案 在创意设计与图像处理领域&#xff0c;Photoshop无疑是众多专业人士和爱好者的首选工具。然而&#xff0c;在使用Photoshop的过程中&#xff0c;有时会遇到一些令人头疼的问题&#xff0c;比如突然弹出的错误…...

mall-admin-web开源项目搭建教程(图文)

本章教程,介绍如何在本地部署运行mall-admin-web这个开源项目。 开源地址:https://gitee.com/macrozheng/mall-admin-web mall-admin-web是一个电商后台管理系统的前端项目,基于Vue+Element实现。主要包括商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计…...

nginx做为文件服务器

docker-compose 创建nginx version: 3services:nginx-web:image: nginx:1.23.4container_name: nginx-webenvironment:# 时区上海TZ: Asia/Shanghaiports:- "88:80"- "443:443"volumes:# 证书映射- /home/dockerdata/nginx/cert:/etc/nginx/cert# 配置文件…...

加速合并,音频与字幕的探讨

因上一节。合并时速度太慢了。显卡没用上。所以想快一点。1分钟的视频用了5分钟。 在合并视频时,进度条中的 now=None 通常表示当前处理的时间点没有被正确记录或显示。这可能是由于 moviepy 的内部实现细节或配置问题。为了加快视频合并速度并利用 GPU 加速,可以采取以下措…...

(3)spring security - 认识PasswordEncoder

目录 1.简介1.1.简单了解认证流程 2.密码验证3.PasswordEncoder的内置实现4.小结 目标&#xff1a; 简单了解认证的流程简单认识spring security中的Password Encoder 1.简介 还是以这幅图为基础&#xff0c;认识Password Encoder到底是什么&#xff1f; 1.1.简单了解认证流程…...

React 入门:JSX语法详解

简介 React是一个用于构建用户界面的JavaScript库&#xff0c;它引入了JSX语法&#xff0c;使得你可以在JavaScript代码中编写类似HTML的结构。JSX在编译后会被转换成合法的JavaScript对象。 JSX基础 JSX是一种看起来像HTML的JavaScript语法扩展。它并不直接被浏览器执行&am…...

Pandas常见函数

Pandas 是 Python 中用于数据分析和处理的强大工具库。以下是 Pandas 中一些常见的函数和方法&#xff0c;按用途分类总结&#xff1a; 1. 数据创建 pd.Series(data, index)&#xff1a;创建一维的序列对象。pd.DataFrame(data, index, columns)&#xff1a;创建二维的DataFra…...

【笔试】亚马逊

亚马逊的笔试题目有两道&#xff0c;一共70分钟 1.给一个数组代表每轮损失的血量power&#xff0c;另外一个变量是盾牌armor&#xff0c;可以选择任意一轮使用这个盾牌&#xff0c;可以抵挡min&#xff08;power[i],armor&#xff09;的攻击&#xff0c;请问最小血量是多少能够…...

【力扣算法】234.回文链表

快慢指针&#xff1a;一个指针走两步&#xff0c;一个指针走一步&#xff0c;当快指针走到链表末尾时&#xff0c;慢指针走到中间位置。 逆转链表&#xff1a;根据指针位置分成两个表&#xff0c;逆转第二个表。 按序判断就可以&#xff0c;如果是相同就是回文&#xff0c;反之…...

vue3-tp8-Element:对话框实现

效果 参考框架 Dialog 对话框 | Element Plus 具体实现 一、建立view页面 /src/views/TestView.vue 二、将路径写入路由 /src/router/index.js import { createRouter, createWebHistory } from vue-router import HomeView from ../views/HomeView.vueconst router create…...

35、Firefly_rk3399 同步互斥

文章目录 1、简述问题2、原子操作&#xff08;atomic_ops &#xff09;指令解析&#xff1a; 3、锁函数说明3.1、自旋锁API例子 3.2、信号量&#xff08;semaphore&#xff09;API例子 3.3、互斥量/锁API例子 3.4、信号量和互斥锁的区别 4、锁的内核实现4.1、自旋锁&#xff08…...

Docker-Dockerfile、registry

Dockerfile 一、概述 1、commit的局限 很容易制作简单的镜像&#xff0c;但碰到复杂的情况就十分不方便&#xff0c;例如碰到下面的情况&#xff1a; 需要设置默认的启动命令需要设置环境变量需要指定镜像开放某些特定的端口 2、Dockerfile是什么 Dockerfile是一种更强大的镜…...

chattts生成的音频与字幕修改完善,每段字幕对应不同颜色的视频,准备下一步插入视频。

上一节中&#xff0c;实现了先生成一个固定背景的与音频长度一致的视频&#xff0c;然后插入字幕。再合并成一个视频的方法。 但是&#xff1a;这样有点单了&#xff0c;所以&#xff1a; 1.根据字幕的长度先生成视频片断 2.在片段上加上字幕。 3.合并所有片断&#xff0c;…...

8、笔记本品牌分类介绍:LG - 计算机硬件品牌系列文章

LG笔记本品牌以其高性能和先进技术而闻名&#xff0c;‌提供多种型号以满足不同用户的需求。‌ LG笔记本产品线包括多种类型&#xff0c;‌以满足不同用户的需求。‌其中&#xff0c;‌LG Gram Pro系列以其超薄设计和高性能配置受到关注。‌该系列笔记本采用16:10的OLED显示屏&…...

在 Vue 2 中隐藏页面元素的方法

目录 在 Vue 2 中隐藏页面元素的方法 引言 1. 使用 v-if 指令 2. 使用 v-show 指令 3. 使用自定义类名与 v-bind:class 4. 使用内联样式与 v-bind:style 5. 使用组件的 keep-alive 和条件渲染 在 Vue 2 中隐藏页面元素的方法 引言 在开发 Web 应用时&#xff0c;我们经…...

基于springboot+vue的高校校园交友交流平台设计和实现

文章目录 系统功能部分实现截图 前台模块实现管理员模块实现 项目相关文件架构设计 MVC的设计模式基于B/S的架构技术栈 具体功能模块设计系统需求分析 可行性分析 系统测试为什么我&#xff1f; 关于我项目开发案例我自己的网站 源码获取&#xff1a; 系统功能 校园交友平台…...

Redis是什么?Redis和MongoDB的区别在那里?

Redis介绍 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、基于内存的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。以下是关于Redis的详细介绍&#xff1a; 一、数据结构支持 字符串&#xff08;String&#xff09; 这是Redis最…...

《开源时间序列数据:探索与应用》

《开源时间序列数据&#xff1a;探索与应用》 一、开源时间序列数据概述二、热门的开源时间序列数据库1. InfluxDB2. TimescaleDB3. Prometheus4. OpenTSDB5. Graphite6. Druid 三、开源时间序列数据的应用场景1. 物联网领域2. 金融领域3. 运维监控领域4. 能源领域 四、开源时间…...

Java后端面试场景题汇总

1.50 亿数据如何去重&排序? 如此大的数据集进行去重(例如50亿数据条目),我们需要考虑内存和存储空间的限制,同时还需要有一个高效的算法。一般来说,这样的数据量无法直接载入内存进行处理,因此需要采用磁盘存储和分布式处理的技术。主要有以下几种思路: 外部排序…...

方法引用和lambda表达式的奥妙

方法引用替代Lambda表达式 什么情况可以使用方法引用替代lambda表达式&#xff1f; 下面代码中两处使用了lambda表达式&#xff0c;一个是filter内&#xff0c;一个是forEach内。其中&#xff0c;forEach内的lambda表达式可以被方法引用替代&#xff0c;但是filter内的lambda…...

AI 智能名片 S2B2C 商城小程序在社群团购运营中的作用与价值

摘要&#xff1a;本文深入探讨了 AI 智能名片 S2B2C 商城小程序在社群团购运营中的重要作用。随着社群团购的兴起&#xff0c;如何有效运营成为关键问题。AI 智能名片 S2B2C 商城小程序凭借其独特功能&#xff0c;能够在促进消费者互动、提升产品传播效果、影响购买决策以及实现…...

设计模式の建造者适配器桥接模式

文章目录 前言一、建造者模式二、适配器模式2.1、对象适配器2.2、接口适配器 三、桥接模式 前言 本篇是关于设计模式中建造者模式、适配器模式&#xff08;3种&#xff09;、以及桥接模式的笔记。 一、建造者模式 建造者模式是属于创建型设计模式&#xff0c;通过一步步构建一个…...

.net framework手动升级到.net core注意点

因为项目原因&#xff0c;还使用着比较原始的 .NETFramework框架&#xff0c;但因为某种原因&#xff0c;暂时不让升级到.NET 6。为了能够解锁更多 VisualStudio2022的功能&#xff0c;尝试手动修改 csproj文件。 这个过程中&#xff0c;也会遇到不少坑&#xff0c;再次做个记…...

排队论、负载均衡和任务调度关系

目录 排队论、负载均衡和任务调度关系 一、排队论 二、负载均衡 三、任务调度 四、总结 排队论、负载均衡和任务调度关系 排队论为负载均衡和任务调度提供了数学理论和方法支持 排队论、负载均衡和任务调度是三个相关但不同的概念。以下是对这三个概念的详细解释和它们之…...

【C++图论】1042. 不邻接植花|1712

本文涉及知识点 C图论 LeetCode1042. 不邻接植花 有 n 个花园&#xff0c;按从 1 到 n 标记。另有数组 paths &#xff0c;其中 paths[i] [xi, yi] 描述了花园 xi 到花园 yi 的双向路径。在每个花园中&#xff0c;你打算种下四种花之一。 另外&#xff0c;所有花园 最多 有…...

AI开源南京分享会回顾录

AI 开源南京分享会&#xff0c;已于2024年11月30日下午在国浩律师&#xff08;南京&#xff09;事务所5楼会议厅成功举办。此次活动由 KCC南京、PowerData、RISC-Verse 联合主办&#xff0c;国浩律师&#xff08;南京&#xff09;事务所协办。 活动以“开源视角的 AI 对话”为主…...

Java版-图论-最短路-Floyd算法

实现描述 网络延迟时间示例 根据上面提示&#xff0c;可以计算出&#xff0c;最大有100个点&#xff0c;最大耗时为100*wi,即最大的耗时为10000&#xff0c;任何耗时计算出来超过这个值可以理解为不可达了&#xff1b;从而得出实现代码里面的&#xff1a; int maxTime 10005…...

ChatGPT大模型 创作高质量文案的使用教程和案例

引言 随着人工智能技术的飞速发展,大语言模型如 ChatGPT 在创作文案、生成内容方面展现出了强大的能力。无论是个人用户还是企业用户,都可以利用 ChatGPT 提高工作效率、激发创意、甚至解决实际问题。本文将详细介绍 ChatGPT 如何帮助创作各类高质量文案,并通过具体案例展示…...

SQL注入及解决

SQL注入是一种常见的网络攻击方式&#xff0c;攻击者通过在输入字段中插入恶意的SQL代码&#xff0c;诱使应用程序执行攻击者构造的SQL语句&#xff0c;从而达到非法获取数据、篡改数据或执行恶意操作的目的。 以下是SQL注入的主要原理总结&#xff1a; 1. 核心原理 SQL注入…...

uni-app多环境配置动态修改

前言 这篇文章主要介绍uniapp在Hbuilderx 中&#xff0c;通过工程化&#xff0c;区分不同环境、动态修改小程序appid以及自定义条件编译&#xff0c;解决代码发布和运行时手动切换问题。 背景 当我们使用uniapp开发同一个项目发布不同的环境二级路径不同时&#xff0c;这时候…...

EasyPlayer.js播放器如何在iOS上实现低延时直播?

随着流媒体技术的迅速发展&#xff0c;H5流媒体播放器已成为现代网络视频播放的重要工具。其中&#xff0c;EasyPlayer.js播放器作为一款功能强大的H5播放器&#xff0c;凭借其全面的协议支持、多种解码方式以及跨平台兼容性&#xff0c;赢得了广泛的关注和应用。 那么要在iOS上…...

mHand Pro动捕数据手套在人形机器人领域的具体运用

mHandPro是一款高精度的动作捕捉数据手套&#xff0c;可应用于动作捕捉与VR交互等领域&#xff0c;配套”mHand Studio“引擎&#xff0c;可实时捕捉真人手部位姿及运动轨迹数据&#xff0c;将数据导出还可以用于人形机器人的训练加速高精度机器人操作技能的培训进程。 高精度动…...

【css常用动画总结01】

一、效果如下&#xff1a; 屏幕录制2024-11-27 17.28.30 二、css常用动画代码&#xff1a; .flex-box{position: relative; } .animation-all {display: flex;p{margin:0;font-size: 12px;}.animate-test1 {width: 102.4px;height: 102.4px;background: url(../assets/images/…...

从入门到精通:系统化棋牌游戏开发全流程教程

棋牌游戏开发需要丰富的技术知识和全面的规划&#xff0c;从开发环境搭建到实际功能实现&#xff0c;步骤清晰且逻辑严谨。以下是完整教程&#xff0c;涵盖了每个关键环节&#xff0c;并提供相关软件的具体下载地址&#xff0c;助力开发者高效完成棋牌游戏项目。 一、开发环境准…...

MyBatis 框架学习与实践

引言 MyBatis 是一个流行的 Java 持久层框架&#xff0c;它提供了简单的方法来处理数据库中的数据。本文将结合笔记和图片内容&#xff0c;详细讲解 MyBatis 的使用&#xff0c;包括配置、注解、优化技巧以及如何处理特殊字符和参数。 1. MyBatis 基础 1.1 引入依赖 首先&a…...

数据可视化的Python实现

一、GDELT介绍 GDELT ( www.gdeltproject.org ) 每时每刻监控着每个国家的几乎每个角落的 100 多种语言的新闻媒体 -- 印刷的、广播的和web 形式的&#xff0c;识别人员、位置、组织、数量、主题、数据源、情绪、报价、图片和每秒都在推动全球社会的事件&#xff0c;GDELT 为全…...

微信小程序实现联动删除输入验证码框

以下是json代码 {"component": true,"usingComponents": {} }以下是wxml代码 <van-popup show"{{ show }}" bind:close"onClose" custom-class"extract"><image src"../../images/extract/icon1.png"…...

C语言程序设计P6-1【应用指针进行程序设计 | 第一节】——知识要点:指针的概念、定义和运算、指针变量作函数的参数

知识要点&#xff1a;指针的概念、定义和运算、指针变量作函数的参数 视频&#xff1a; 目录 一、任务分析 二、必备知识与理论 三、任务实施 一、任务分析 输入两个整数&#xff0c;按大小顺序输出&#xff0c;要求用函数处理&#xff0c;而且用指针类型的数据作函数参数…...

C++编程: 基于cpp-httplib和nlohmann/json实现简单的HTTP Server

文章目录 0. 引言1. 完整实例代码2. 关键实现3. 运行与测试 0. 引言 本文基于 cpp-httplib 和 nlohmann/json 实现简单的 HTTPS Server 实例代码&#xff0c;这两个库均是head-only的。 1. 完整实例代码 如下实例程序修改自example/server.cc #include <httplib.h>#i…...

多模态大模型(二)——用Transformer Encoder和Decoder的方法(BLIP、CoCa、BEiTv3)

文章目录 BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation 理解、生成我都要&#xff0c;一个很有效的、根据图片生成caption的工具1. BLIP的研究动机2. BLIP的模型结构3. CapFilt Model4. BLIP的训练过程 CoCa: C…...

SpringBoot快速入门

SpringBoot 文章目录 SpringBoot1. Spring Boot 概念2. Spring 使用痛点3. Spring Boot功能4. 快速搭建5. 起步依赖原理6. SpringBoot 配置6.1 配置文件6.2 YAML介绍6.3 YAML语法6.4 YAML数据6.5 YAML参数引用 7.配置数据读取7.1 Value("${}")7.2 Environment7.3 Con…...

Qt编写区位码gb2312、机内码、国标码————附带详细介绍和编码实现

文章目录 0 背景1 了解编码1.1 ASCII码1.2 机内码、国标码、区位码1.2.1 区位码1.2.2 国标码&#xff08;GB 2312-80&#xff09;1.2.3 汉字机内码&#xff08;GB 2312&#xff09; 1.3 GBK和GB2312的区别2 编码实现2.1 QString数据转QByteArray类型2.1.1 使用QTextCodec2.1.2 …...