网站的版面设计,智慧团建网站官网电脑版,网站设计视频,wordpress安装第二步目录
1. Linux软件包管理器yum
1.1 什么是软件包
1.2 Linux软件生态
1.3 关于rzsz
1.4 注意事项
1.5 查看软件包
2. Linux编辑器-vim使用
2.1 vim的基本概念
2.2 vim的基本操作
2.3 简单vim配置
3. 编译器gcc/g
3.1 背景知识
3.2 gcc编译选项
3.2.1 预处理…目录
1. Linux软件包管理器yum
1.1 什么是软件包
1.2 Linux软件生态
1.3 关于rzsz
1.4 注意事项
1.5 查看软件包
2. Linux编辑器-vim使用
2.1 vim的基本概念
2.2 vim的基本操作
2.3 简单vim配置
3. 编译器gcc/g
3.1 背景知识
3.2 gcc编译选项
3.2.1 预处理(进行宏替换)
3.2.2 编译(生成汇编)
3.2.3 汇编(生成机器可识别的代码)
3.2.4 连接(生成可执行文件或库文件)
3.2.5 补充(sudo无法执行问题) 3.3 动态链接和静态链接
3.4 静态库和动态库
3.5 gcc其他常用选项
4. 自动化构建-make/makefile 4.1 背景
4.2 基本使用
4.3 推导过程
4.4 适度语法扩展
5. Linux第一个系统程序 — 进度条
5.1 补充 - 回车与换行
5.2 行缓冲区
5.3 倒计时程序
5.4 进度条代码
6. 版本控制器Git
6.1 版本控制器
6.2 git简史
6.3 安装git
6.4 Git的使用
7. 调试器-gdb.cgdb使用
7.1 gbd的下载
7.2 样例代码
7.3 预备
7.4 常见使用
7.5 常见技巧
7.4.1 watch
7.4.2 set var确定问题原因
7.4.3 条件断点 1. Linux软件包管理器yum
1.1 什么是软件包 在Linux下安装软件,一个通常的办法是下载到程序的源代码,并进行编译,得到可执行程序。但是这样太麻烦了,于是有些人把一些常用的软件提前边缘好,做成软件包(可以理解成windows上的安装程序)放在一个服务器上,通过包管理器可以很方便的回去到这个编译好的软件包,直接进行安装。软件包和软件包管理器,就好比App和应用商店这样的关系。yum(Yellow aog Updater,Modified)是Linux下非常常用的一种包管理器,主要应用在Fedora,RedHat,Centos等发行版上。Ubuntu主要使用apt(Advanced Package Tool)作为其包管理器,apt同样提供了自动解决依赖关系,下载和安装软件包的功能。 1.2 Linux软件生态
Linux下载软件的过程(Ubuntu,Centos,other) 操作系统的好坏评估---生态问题 为什么会有人免费特定社区提供软件,还发布,还提供云服务器下载? 软件包依赖的问题 国内镜像源 以下是⼀些国内Linux软件安装源的官方链接 1. 阿⾥云官方镜像站 ◦ 官方链接https://developer.aliyun.com/mirror/ ◦ 阿里云提供了丰富的Linux发行版镜像包括CentOS、Ubuntu、Debian等用户可 以通过该镜像站快速下载和更新软件包。 2. 清华⼤学开源软件镜像站 ◦ 官⽅链接https://mirrors.tuna.tsinghua.edu.cn/ ◦ 清华⼤学镜像站提供了多种Linux发⾏版的镜像以及Python、Perl、Ruby等编程语 ⾔的扩展包。该镜像站还提供了丰富的⽂档和教程帮助⽤⼾更好地使⽤这些软件 包。 3. 中国科学技术⼤学开源镜像站 ◦ 官方链接http://mirrors.ustc.edu.cn/ ◦ 中科⼤镜像站提供了多种Linux发⾏版的镜像以及常⽤的编程语⾔和开发⼯具。⽤⼾ 可以通过该镜像站⽅便地获取所需的软件包和⼯具。 4. 北京交通⼤学⾃由与开源软件镜像站 ◦ 官⽅链接https://mirror.bjtu.edu.cn/ ◦ 北交⼤镜像站提供了多种Linux发⾏版的镜像以及相关的软件仓库和⼯具。该镜像站 还提供了详细的⽂档和指南帮助⽤⼾配置和使⽤这些软件源。 5. 中国科学院软件研究所镜像站ISCAS ◦ 官⽅链接http://mirror.iscas.ac.cn/ ◦ ISCAS镜像站提供了多种Linux发⾏版、编程语⾔和开发⼯具的镜像。⽤⼾可以通过该 镜像站快速获取所需的软件包和更新。 6. 上海交通⼤学开源镜像站 ◦ 官⽅链接https://ftp.sjtu.edu.cn/ ◦ 上海交⼤镜像站提供了丰富的Linux软件资源包括多种发⾏版的镜像和软件仓库。⽤ ⼾可以通过该镜像站⽅便地下载和安装所需的软件包。 7. ⽹易开源镜像站 ◦ 官⽅链接http://mirrors.163.com/ ◦ ⽹易镜像站提供了多种Linux发⾏版的镜像以及相关的软件仓库和⼯具。该镜像站还 提供了便捷的搜索功能帮助⽤⼾快速找到所需的软件包。 此外还有⼀些其他的国内镜像源如搜狐开源镜像站等但可能由于时间变化或政策调 整部分镜像站的链接或状态可能有所变动。因此建议⽤⼾在使⽤前访问官⽅⽹站或咨询 相关社区以获取最新的信息和帮助。 1.3 关于rzsz 这个工具用于windows机器和远端的Linux机器通过xshell传输文件。 安装完毕之后可以通过拖拽的方式将文件上传上去。 1.4 注意事项 关于yum的所有操作必须保证主机(虚拟机)网络畅通!!! 可以通过ping指令验证。 ping www.baidu.com 1.5 查看软件包 通过yum list命令可以罗列出当前一共有那些软件包,由于包的数目可能非常之多,这里我们需要使用grep命令只筛选出我们关注的包:例如: yum list | grep lrzsz 结果如下: lrzsz.x86_64 0.12.20-36.el7 ba 注意事项: 软件包名称:主版本号.次版本号,源程序发行号-软件包的发行号.主机平台.cpu架构x86_64后缀表示64位系统的安装包,i686后缀表示32位系统安装包.选择包时要和系统匹配el7表示操作系统发行版的版本,el7表示ide是centos7/redhat7.el6表示centos6/redhat6.最后一列.base表示的是软件源的名称,类似于小米应用商店,华为应用商店这样的概念 Linux下软件安装一次,所有人都能用。 yum只能同时安装一个软件,不能既安装软件A,又安装软件B。 安装: (-y不需要问,直接安装) 卸载: (-y不需要问,直接卸载) 2. Linux编辑器-vim使用 vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于xwindows、mac os、windows。 2.1 vim的基本概念 其实vim有好多种模式,目前掌握三种即可,分别是命令模式(command mode)、插入模式(insert mode)和底行模式(last line mode)、各模式的功能区别如下: 正常/普通/命令模式(Normal mode) 控制屏幕光标的移动、字符、字或行的删除,移动复制某区段及进入insert mode下,或者到last line mode 插入模式(insert mode) 只有在insert mode下,才可以做文字输入,按[ESC]键可回到命令行模式,该模式是我们后面用的最频繁的编辑模式。 末行模式(last line mode) 文件保存或退出,也可以进行文本替换,找字符串,列出行号等操作,在命令模式下,shift;即可进入该模式。要查看你所有的模:打开vim底行模式直接输入。 :help vim-modes 这里一共有12种模式:six BASIC modes和six ADDITIONAL modes 2.2 vim的基本操作 1. 进入vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面 $ vim test.c 不过有一点要特别注意,就是你进入vim之后,是处于[正常模式],你要切换到[插入模式]才能够输入文字。 2. [正常模式]切换[插入模式] 输入a输入i输入o 3. [插入模式]切换至[正常模式] 目前处于[插入模式],就只能一直输入文字,如果发现输错了字,想用光标键往回挪动,将该字删除,可以先按一下[ESC]键转到[正常模式]再删除文字,当然,也可以直接删除。 4. [正常模式]切换至[末行模式] [shift;],其实就是输入[:] 5. 退出vim及保存文件,在[正常模式]下,按一下[:]冒号键进入[Last line mode],例如: :w(保存当前文件):wq(输入 [wq]),存盘并退出vim):q!(输入q!,不存盘强制退出vim) 在命令模式下提供那么多的命令是为了提高编辑效率。 命令模式下set nu调出行号,set nonu去掉行号。 底行到插入,插入到底行是不支持的。 更加实用的操作: 2.3 简单vim配置 配置文件的位置 在目录/etc/下面,有个名为vimrc的文件,这是系统种公共的vim配置文件,对所有用户都有效。而在每个用户的主目录下,都有字节建立私有的配置文件,命名为:.vimrc。例如,/root目录下,通常已经存在一个.vimrc文件,如果不存在,则创建之。切换用户称为字节执行su,进入自己的主工作目录,执行cd ~打开自己目录下的.vimrc文件,执行vim .vimrc 常用配置选项,用来测试 设置语法高亮:syntax on显示行号:set nu设置缩进的空格数为4:set shiftwidth4 本质最简单的就是去修改它当前家目录下的.vimrc的文件,往里面加配置项就可以,而且自己配置的只能自己实用,别人实用不了。
一键化配置 参考链接:gitee搜索vimforcpp VimForCpp: 快速将vim打造成c IDEhttps://gitee.com/HGtz2222/VimForCpp 配置命令: curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh bash ./install.sh 卸载命令:bash ~/.VimForCpp/uninstall.sh 注意: 首先不能是root必须在自己当前的工作路径下 要配置Ubuntu的话 可以在gitee上搜vimplus 链接: vimplus: vim/Neovim configure for C/C on(MAC/Ubuntu/Deepin/Raspbian/UOS/LinuxMint/elementaryOS/Debian/Kali/Parrot/CentOS/fedora/openSUSE/ArchLinux/ManjaroLinux/Gentoo)https://gitee.com/keeferwu/vimplus 使用插件: 要配置好看的vim,原生的配置可能功能不全,可以选择安装插件来完成配置,保证用户是你要配置的用户,接下来: 安装TagList插件,下载taglist_xx.zip,解压完成,将解压出来的doc的内容放到~/.vim/doc,将解压出来的plugin下的内容拷贝到~/.vim.plugin。在~/.vimrc中添加:let Tlist_Show_One_File1 let Tlist_Exit_OnlyWindow1 let Tlist_Use_Right_Window1安装文件浏览器和窗口管理器插件:WinManager下载Winmanager.zip,2.X版本以上的解压winmanager.zip,将解压出来的doc的内容放到~/.vim/doc,将加压出来的plugin下的内容拷贝到~/.vim/plugin在〜/.vimrc中添加 let g:winManagerWindowLayout‘FileExplorer|TagList nmap wm :WMToggle然后重启vim,打开~/XXX.c或〜/XXX.cpp,在normal状态下输⼊wm,你将看到上图的效果。更具 体移步点我,其他⼿册请执⾏ vimtutor 命令。 参考资料: GitHub - wsdjeg/vim-galore-zh_cn: Vim 从入门到精通https://github.com/wsdjeg/vim-galore-zh_cn 3. 编译器gcc/g
3.1 背景知识 预处理(进行宏替换.去注释/条件编译/头文件展开等)编译(生成汇编)汇编(生成机器可识别代码)链接(生成可执行文件或库文件) 3.2 gcc编译选项 格式 gcc [选项] 要编译的文件 [选项] [目标文件] 3.2.1 预处理(进行宏替换) 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。预处理指令是以#号开头的代码行实例:gcc -E main.c -o main.i选项-E,该选项的作用是让gcc在预处理结果后停止编译过程。选项-o 是指目标文件,.i文件为已经过预处理的C原始程序。 3.2.2 编译(生成汇编) 在这个阶段中,gcc首选要检查代码的规范性,是否有语法错误等,以为确定代码的实际要左做的工作,在检查无误后,gcc把代码翻译成汇编语言。用户可以使用-S选项来进行检查,该选项只进行编译而不进行汇编,生成汇编代码。实例: gcc -S main.c -o main.s 3.2.3 汇编(生成机器可识别的代码) 汇编阶段是把编译阶段生成的.s文件转成目标文件读者在此可使用选项-c就可以看到汇编代码已转化为.o的二进制目标代码了实例: gcc -c -o main.c 3.2.4 连接(生成可执行文件或库文件) 在成功编译之后,就进入了链接阶段。实例: gcc main.c -o main 3.2.5 补充(sudo无法执行问题)
ls -l /etc/sudoers //要修改这个文件只能超级管理员修改,别的用户打开时看不到的,
这个与用户有关,与用什么工具打开没有关系 xshell下查看是Centos还是Ubuntu Centos: cat /etc/redhat-releaseUbuntu: cat /etc/lsb-release 3.3 动态链接和静态链接 在我们的实际开发中,不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每个*.c文件会形成一个*.o文件,为了满足前面说的依赖关系,则需要将这些源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个链接的过程就是静态链接,静态链接的缺点很明显。 浪费空间:因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,如多个程序中都调用了printf()函数,则这多个程序中都含有printf.o,所以同一个目标文件都在内存存在多个副本。更新比较困难:因为每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。但是静态链接的优点就是,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的是运行速度快。 动态链接的出现解决了静态链接中提到的问题。动态链接的基本思想是把程序按照模板拆分成各个相对独立部分,在程序运行时才将他们链接在以前形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。 动态链接起始远比静态链接要常用的多。比如我们查看下main这个可执行程序依赖的动态库,会发现它就用到了一个c动态链接库: ldd mainlinux-vdso.so.1 (0x00007fffac6ed000)libc.so.6 /lib64/libc.so.6 (0x00007f4d19ae5000)/lib64/ld-linux-x86-64.so.2 (0x00007f4d19eb3000)
//ldd命令用于打印程序或者库文件所依赖的共享库列表 在这里涉及到一个重要的概念:库 我们的C程序中,并没有定义printf的函数实现,且在预编译中包含的stdio.h中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现printf函数的呢?最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径/usr/lib下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数printf了,而这也就是链接的作用。 3.4 静态库和动态库 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但是在运行时就不再需要库文件了。其后缀名一般为.a。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为.so,如前面所述的libc.so.6就是动态库gcc在编译时默认使用动态库。完成了链接后.gcc就可以生成可执行文件,如下所示。gcc main.o -o hellogcc默认生成的二进制程序,就是动态链接,这点可以通过file命令验证。 注意1: Linux下,动态库XXX.so,静态库XXX.aWindows下,动态库XXX.dll,静态库XXX.lib 一般我们的云服务器,C/C的静态库并没有安装,可以采用如下方法安装。
//Centos
yum install glibc-static libstdc-static -y 3.5 gcc其他常用选项 -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面。-S 编译到汇编语言不进行汇编和链接-c 编译到目标文件-o 文件输出到文件-static 此选项对生成的文件采用静态链接-g 生成调试信息。GNU调式器可利用该信息-shared此选项讲尽量使用动态库,所以生成文件比较小,但是需要系统由动态库-O0-O1-O2-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值-O3优先级别最高-w 不生成任何告警信息。-Wall 生成所有告警信息。 4. 自动化构建-make/makefile 4.1 背景 会不会写makefile,从一个侧面说明了一个人是否基本完成大型工程的能力一个工程的源文件不计数,其按类型,功能,模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译, 哪些文件需要重新编译,甚至于进行更复杂的功能操作。makefile带来的好吃就是 —— 自动化构建,一旦写好,只需要一个make命令,整个工程完成自动编译,极大提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi和make,Visual C的nmake,Linux下的GUN和make。可见,makefile都成为了一种在工程方面的编译方法。make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。 makefile/Makefile首字母可以大写,也可以小写。 4.2 基本使用
实例代码
include stdio.h
int main()
{printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);printf(hello world!!\n);return 0;
}
Makefile文件
main:myproc.cgcc -o main main.c || gcc main.c -o main.PHONY:clean
clean:rm -f main
依赖关系 上面的文件main它依赖main.c 依赖方法 gcc -o main main.c就是与之对应的依赖关系 项目清理 工程是需要被清理的像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——make clean,以此来清除所有的目标文件,以便重编译。但是一般我们这种clean的目标文件,我们将它设置为伪目标,用.PHONY修饰,伪目标的特性是,总是被执行的。可以将我们的main目标文件声明成伪目标,测试一下。 什么叫做总是被执行?
$ stat XXXFile: ‘XXX’Size: 987 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 1321125 Links: 1
Access: (0666/-rw-rw-rw-) Uid: ( 1000/ wanghao) Gid: ( 1000/ wanghao)
Access: 2024-11-15 00:41:45.915034571 0800
Modify: 2024-11-15 00:41:45.915034571 0800
Change: 2024-11-15 00:41:45.915034571 0800
⽂件 内容 属性
Modify: 内容变更时间更新
Change属性变更时间更新
Access常指的是⽂件最近⼀次被访问的时间。在
Linux的早期版本中每当⽂件被访问时其atime都会更新。但这种机制会导致⼤量的
IO操作。结论: .PHONY:让make忽略源文件和可执行目标文件的M时间对比。 4.3 推导过程
myproc:myproc.o gcc myproc.o -o myproc
myproc.o:myproc.s gcc -c myproc.s -o myproc.o
myproc.s:myproc.i gcc -S myproc.i -o myproc.s
myproc.i:myproc.cgcc -E myproc.c -o myproc.i
.PHONY:clean
clean: rm -f *.i *.s *.o myproc
编译: $ makegcc -E myproc.c -o myproc.igcc -S myproc.i -o myproc.sgcc -c myproc.s -o myproc.ogcc myproc.o -o myproc make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么: make会在当前目录下找名字叫Makefile或makefile的文件。如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到myproc这个文件,并把这个文件作为最终的目标文件。如果myproc文件不存在,或是myproc所依赖的后面的myproc.o文件的文件修改时间要比myproc这个文件新(可以用touch测试) ,那么,他就会执行后面所定义的命令来生成myproc这个文件。如果myproc所依赖的myproc.o文件不存在,那么make会在当前文件中找目标为myproc.o文件的依赖性,如果找到则再根据那一个规则生成myproc.o文件。(这有点像一个堆栈的过程)当然,你的C文件和H文件是存在的,于是make会生成myproc.o文件,然后再用myproc.o文件声明make的终极任务,也就是执行文件hello了。这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作了。 4.4 适度语法扩展
BINproc.exe #定义变量
CCgcc
#SRC$(shell ls *.c) #采⽤shell命令⾏⽅式获取当前所有.c⽂件名
SRC$(wildcard *.c) #或者使⽤wildcard 函数获取当前所有.c⽂件名
OBJ$(SRC:.c.o) #将SRC的所有同名.c 替换成为.o形成⽬标⽂件列表
LFLAGS-o #链接选项
FLAGS-c #编译选项
RMrm -f #引⼊命令$(BIN):$(OBJ)$(CC) $(LFLAGS) $ $^ # $:代表⽬标⽂件名。$^: 代表依赖⽂件列表echo linking ... $^ to $
%.o:%.c # %.c 展开当前⽬录下所有的.c。%.o: 同时展开同名.o$(CC) $(FLAGS) $ # %: 对展开的依赖.c⽂件⼀个⼀个的交给gcc。echo compling ... $ to $ # 不回显命令
.PHONY:clean
clean:$(RM) $(OBJ) $(BIN) # $(RM): 替换⽤变量内容替换它.PHONY:test
test:echo $(SRC)echo $(OBJ)#makefile的注释是用#注释 5. Linux第一个系统程序 — 进度条
5.1 补充 - 回车与换行 回车:将光标回到行首 \r换行:换到下一行 \n回车换行是两个动作,C语言中的\n表示的就是\r\n,回车换行,先是回到当前行的行首,然后换到下一行。 5.2 行缓冲区
#include stdio.h
int main()
{printf(hello hello world!!\n);sleep(3);return 0;
} #include stdio.h
int main()
{printf(hello world!!);sleep(3);return 0;
} 第二种情况,当我没有加\n的时候现现象就是它先执行睡眠三秒,然后打印出hello world,那么在睡眠期间它打印的hello wrold是在输入缓冲区的,但是第一种情况,带\n的先是一定在缓冲区的,只不过这个缓冲区是给显示器提供的,所以只要有缓冲区就必要要存在刷新策略,其中显示器的刷新策略叫做行刷新,也就是说碰到了打印的字符串包换了\n,那么该消息就会立即显示到显示器上,如果不包含\n,该字符串不做刷新,要么程序结束自动刷新,要么强制刷新,所以这就是为什么带\n的字符串立即现在,不带\n的消息不立即显示的原因。 如果想让不带\n的立即刷新应该怎么办?而且不想让他行刷新。 除了程序退出,我们还可以强制刷新。 man fflush #include stdio.h
int main()
{printf(hello world!!);fflush(stdout);//刷新 sleep(3); return 0;
}
5.3 倒计时程序
#include stdio.h
#include unistd.h
int main()
{int cnt 9;while(cnt 0){printf(%d\r,cnt);fflush(stdout);//刷新刷入缓冲区cnt--;sleep(1);}printf(\n); return 0;
} 这样的代码确实可以现实的倒计时程序,但是如果我将cnt的初始值9改成10的话,该程序就会出问题,当我在向显示器上打印1234的时候显示器上的是字符1,字符2,字符3,字符4,其实显示器只认字符,所以显示器才叫做字符设备,只不过显示器把字符1234写在了一起,看起来是1234,实则是1234这四个字符,所以c语言中的%d格式化是把整数转字符。 #include stdio.h
#include unistd.h
int main()
{int cnt 15;while(cnt 0){printf(%-2d\r,cnt);//格式控制,默认是右对齐,想让左对齐就用-2d fflush(stdout);//刷新刷入缓冲区cnt--;sleep(1);}printf(\n);return 0;
}5.4 进度条代码
//MakeFile
BINprocess
#动态获取当前目录下所有的.c文件有两种做法
#SRC$(shell ls *.c) #1.动态获取当前目录下所有的.c文件
SRC$(wildcard *.c) #2.makefile自己的语法,把当前目录下的.c罗列出来
OBJ$(SRC:.c.o) #把所有的.c换成.o形成形成OBJ
CCgcc #用到的编译器是gcc
RMrm -f #删除命令$(BIN):$(OBJ)#$(CC) $(OBJ) -o $(BIN)$(CC) $^ -o $echo 链接 $^ 成 $
%.o:%.c #%是通配符的意思,匹配任意内容,.c是任意以.c结尾的文件$(CC) -c $ #$是把一批文件一个一个的拿过来,通过gcc加工成.oecho 编译 ... $ 成 $.PHONY:clean
clean:$(RM) $(OBJ) $(BIN).PHONY:mymain
mymain:echo $(BIN) #不想让echo命令回显,那么前面就加上符号,不显示命令执行的过程,只显示结果echo $(SRC)echo $(OBJ)
//process.h
#pragma once
#include stdio.h
#include unistd.h
#include string.h
#include time.h
#include stdlib.h
#define SIZE 101
#define STYLE
//v1
void process();
//v2
void FlushProcess(const char* tips,double total,double current);
//process.c
#include process.h//#define SIZE 100
//v2:根据进度,动态刷新一次进度条
void FlushProcess(const char* tips ,double total,double current)
{const char* table |/-\\;int len strlen(table);static int index 0;int i 0;char buffer[SIZE];memset(buffer,0,sizeof(buffer));double rate current*100/total;int num (int)rate;for(;i num;i){buffer[i] STYLE;}printf(%s...[%-100s][%.1lf%%][%c]\r,tips,buffer,rate,table[index]);fflush(stdout);index % len;if(num 100) printf(\n);
}
//v1版本:展示进度条基本功能
void process()
{int rate 0;char buffer[SIZE];memset(buffer,0,sizeof(buffer));const char* lable |/-\\;int len strlen(lable);while(rate 100){printf([%-100s][%d%%][%c]\r,buffer,rate,lable[rate%len]);//%100s默认是右对齐,前面加上-就是左对齐buffer[rate] STYLE;fflush(stdout);//刷新输出缓冲器rate;usleep(50000);//usleep可以在man 3 usleep中查看,1000000表示1s}printf(\n);
}
//main.c
#include process.h
//函数指针
typedef void (*call_t)(const char*,double,double);
double total 1024.0;//目标的总量
//double speed 1.0;//网速
double speed[] {20.0,0.05,0.03,0.02,0.01,0.001};
//回调函数
void download(int total,call_t cb)
{srand(time(NULL));double current 0;//下载量,刚开始我为0while(current total){//更新进度cb(下载中,total,current);//进行回调if(current total) break;int random rand() % 6;//下载代码usleep(50000);current speed[random];if(current total) current total;}
}void upload(int total,call_t cb)
{srand(time(NULL));double current 0;//下载量,刚开始我为0while(current total){cb(上传中,total,current);//进行回调if(current total) break;int random rand() % 6;usleep(50000);current speed[random];if(current total) current total;}
}
int main()
{download(1024.0,FlushProcess);printf(dowmload 1024.0MB done\n);download(10240.0,FlushProcess);printf(dowmload 10240.0MB done\n);download(512.0,FlushProcess);printf(dowmload 512.0MB done\n);download(1024.0,FlushProcess);printf(dowmload 1024.0MB done\n);download(770.0,FlushProcess);printf(dowmload 777.0MB done\n);download(111.0,FlushProcess);printf(dowmload 111.0MB done\n);upload(1024.0,FlushProcess);printf(upload 111.0MB upload\n);//process();return 0;
} 6. 版本控制器Git 不知道你工作或者学习的时候,有没有遇到这样的情况:我们再编写各种文档时,为了仿真文档丢失,失误,失误后能恢复到原来的版本,不得不复制出一个副本,比如: 报告-v1 报告-v2 “报告-v3” 报告-确定版 报告-最终版 报告-究极进化版 ..... 每个版本有各自的内容,但最终只会有一份报告需要被我们使用。 但在此之前的工作都需要这些不同版本的报告,于是每次都是复制粘贴副本,产出的文件就越来越多,文件多不是问题,问题是:随着版本数量的不断增多,你还记得这些版本各自都是修改了什么吗? 文档如此,我们写的项目代码,也是存在这个问题的!! 6.1 版本控制器 为了能够更方便我们管理这些不同版本的文件,便有了版本控制器。所谓的版本控制器,就是能让你了解到一个文件的历史,以及它的发展过程的系统。通俗的讲就是一个可以记录工程的每一次改动和版本迭代的一个管理系统,同时也方便多人协同作业。目前最主流的版本控制就是Git,Git可以控制电脑上所有格式的文件,例如doc,excel,dwg,dgn,rvt等等。对于我们开发人员来说,Git最重要的就是可以帮助我们管理开发项目中的源代码文件。 6.2 git简史 同生活中的许多伟大事物,Git诞生于一个极富纷争大举创新的时代。 Linux内核开源项目有着为数众多的参与者。绝大多数的Linux内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991 - 2002年间)。到2002年,整个项目组开始启用一个专有的分布式版本控制系统BitKeeper来管理和维护代码。 到了2005年,开发BitKeeper的商业公司同Linux内核开源社区的合作关系结束,他们回收了Linux内核社区免费使用BitKeeper的权力。这就迫使Linux开源社区(特别是Linux的缔造者Linus Torvalds)基于使用BitKeeper时的经验教训,开发出自己的版本系统。他们对新的系统制定了若干目标: 速度简单的设计对非线性开发模式的强力支持(允许成千上万个并行开发的分支)完全分布式有能力高效管理类似Linux内核一样的超大规模项目(速度和数据量) 自诞生于2005年以来,Git日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统。 6.3 安装git
//Centos
sudo yum install git
//Ubuntu
sudo apt install -y git
//查看版本信息
git --version
//同步远端的数据
git pull
6.4 Git的使用
Git的安装和使用-CSDN博客文章浏览阅读824次点赞12次收藏8次。第一次上传需要填写用户名和密码,如果密码填错,需要在凭证管理器中删除,如果第二次再次上传的话还弹出这个框的话就不用去凭证管理器中删除,不弹的话就得去凭证管理器中删除。注意:这个软件是依赖前一个软件的在安装的过程中需要选择第一个软件的路径这里我就不做更改了,默认就行。右击鼠标,选择Git Clone,然后讲自己复制的仓库链接粘贴进去,然后点击ok。首先文件夹中要放我们要上传的文件或者文件夹,我这里就放了一个C语言的代码。点进仓库里面,我们发现里面的文件和我们云端上的文件是一样的。https://blog.csdn.net/m0_74271757/article/details/144035465?spm1001.2014.3001.5502
7. 调试器-gdb.cgdb使用
7.1 gbd的下载
//CentOscurl -sLf https://gitee.com/lpsdz-ybhdsg-jk/yum-source-update/raw/master/install.sh -o ./install.sh bash ./install.shsudo yum install gdb -y
7.2 样例代码
//main.c
#include stdio.h
int sum(int begin,int end)
{int index 0; for(int i begin;i end;i){index i;}return index;
}int main()
{int start 1;int end 100;printf(I will begin\n);int n sum(start,end);printf(running done, result is: [%d-%d]%d\n, start, end, n);return 0;
}
7.3 预备 程序的发布方式有两种,Debug模式和release模式,Linux gcc/g出来的二进制程序,默认是release模式。要使用gbd调式,必须在源代码生成二进制程序的时候,加上-g选项,如果没有添加,程序无法被编译。 $ gcc mycmd.c -o mycmd # 默认模式不⽀持调试
$ file mycmd
mycmd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]82f5cbaada10a9987d9f325384861a88d278b160, for GNU/Linux
3.2.0, not stripped$ gcc mycmd.c -o mycmd -g # debug模式
$ file mycmd
mycmd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]3d5a2317809ef86c7827e9199cfefa622e3c187f, for GNU/Linux
3.2.0, with debug_info, not stripped
7.4 常见使用 开始:gdb binFile退出:ctrl d 或quit调试命令 命令作用样例list/l显示源代码,从上次位置开始,每次列出10行list/l 10list/l 函数名列出指定函数的源代码list/l mainlist/l 文件名:行号列出指定文件的源代码list/l mycmd.c:1r/run从程序开始连续执行runn/next单步执行,不进入函数内部nexts/step单步执行,进入函数内部stepbreak/b [文件名:]行号在指定行号设置断点 break 10 break test.c:10 break/b 函数名在函数开头设置断点break maininfo break/b查看当前所有断点信息info breakfinish执行到当前函数返回,然后停止finishprint/p打印表达式的值print startendp 变量打印指定变量的值p xset var 变量 值修改变量的值set var i 10continue/c从当前位置开始连续执行程序continue deletc/d breakpoints 删除所有断点delete breakpoints delete/d breakpoints n 删除序号为n的断点delete breakpoints 1disable breakpoints禁用所有断点disable breakpointsenable breakpoints启用所有断点enable breakpointsinfo/i breakpoints查看当前设置的断点列表info breakpointsdisplay 变量名跟踪显示指定变量的值(每次停止时)display xundisplay 编号取消对指定编号的变量的跟踪显示undisplay 1until x行号执行到指定行号until 20backtrace/bt查看当前执行栈的各级函数调用及参数backtraceinfo/i locals查看当前栈帧的局部变量值info localsquit退出GDB调试器quit 7.5 常见技巧 安装cgdb: 上面的基本调试还是麻烦,虽然是黑屏,但是还是想看到代码调试推荐安装cgdbUbuntu:sudo apt-get install -y cgdbCentos:sudo yum install -y cgdb 7.4.1 watch 执行时监视一个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发生变化,GDB会暂停程序的执行,并通知使用者。 注意: 如果你有一些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你。 7.4.2 set var确定问题原因 更改一下标志位,假设我们想得到-index 7.4.3 条件断点 添加条件断点 注意: 条件断点添加常见两种方式:1.新增 2.给已有断点追加注意两者的语法区别,不要写错了。新增:b/行号/文件名:行号/函数名 if i 20(条件)给已有断点追加:condition 2 i 20,其中2是已有断点编号,没有ifcgdb分屏操作,Esc进入代码屏,i回到gdb屏