十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux——基础开发工具(下)

Linux——基础开发工具(下) ‍♂️个人主页进击的荆棘作者其它专栏《数据结构与算法》《算法》《C起始之路》《Linux》目录1.软件包管理器2.编辑器Vim3.编译器gcc/g4.自动化构建--make/Makefile5.Linux 第一个系统程序--进度条6.版本控制器Git7.调试器-gdb/cgdb使用5.Linux 第一个系统程序--进度条5.1回车与换行●回车概念\r把字车推回本行最左侧起始位置只负责光标回到行首不向下换行●换行概念\n光标垂直下移一行水平位置保持不变不会回到行开头5.2行缓冲区代码#include stdio.h int main(){ printf(hello world\n); sleep(3); return 0; }现象先输出hello world并换行后等待3秒后程序结束代码#include stdio.h int main(){ printf(hello world); sleep(3); return 0; }现象等待3秒后输出hello world且不换行代码#include stdio.h int main(){ printf(hello world); fflush(stdout); sleep(3); return 0; }现象先输出hello world3秒后程序结束且不换行5.3倒计时程序#include stdio.h #include unistd.h int main(){ int i10; while(i10){ printf(%-2d\r,i); fflush(stdout); i--; sleep(1); } printf(\n); return 0; }5.4进度条代码process.c#include process.h #include string.h #include unistd.h #define NUM 101 #define STYLE void FlushProcess(double total,double current){ char buffer[NUM]; memset(buffer,0,sizeof(buffer)); char* label|/-\\; int lenstrlen(label); static int cnt0; //填充 int num(int)(current*100/total); int i; for(i0;inum;i){ buffer[i]STYLE; } double ratecurrent/total; cnt%len; printf([%-100s][%.1lf\%][%c]\r,buffer,rate*100,label[cnt]); cnt; fflush(stdout); }; //void process_v1(){ // char buffer[NUM]; // memset(buffer,0,sizeof(buffer)); // char* label|/-\\; // int cnt0; // int lenstrlen(label); // while(cnt100){ // //在原地输出 // printf([%-100s][%d\%][%c]\r,buffer,cnt,label[cnt%len]); // buffer[cnt]STYLE; // fflush(stdout); // // usleep(50000); // cnt; // } // printf(\n); //};process.h#pragma once #include stdio.h void process_v1(); void FlushProcess(double total,double current);main.c#include process.h #include stdio.h #define total 1024.0 #define speed 1.0 void Download(){ double current0; while(currenttotal){ FlushProcess(total,current); //模拟下载数据 usleep(3000); currentspeed; } printf(\nDownload %.2lfMB Done\n,current); } int main(){ // process_v1(); Download(); return 0; }MakefileBINprocessbar SRC$(wildcard *.c) OBJ$(SRC:.c.o) $(BIN):$(OBJ) gcc -o $ $^ %.o:%.c gcc -c $ .PHONY:clean clean: rm -f *.o processbar6.版本控制器Git在我们编写各种文档时为防止文档丢失更改失误为了失误后能恢复到原来的版本不得不复制出一个副本比如“报告-v1”“报告-v2”“报告-v3”“报告-确定版”“报告-最终版”……每个版本有各自的内容但最终只有一份报告需要被我们使用。但在此之前的工作都需要这些不同版本的报告于是每次都是复制粘贴副本产出的文件就越来越多文件多不是问题问题是随着版本数量的不断增多我们很难记得各版本都修改了什么。文档如此写项目代码时也是如此。6.1版本控制器为了能够更方便我们管理这些不同版本的文件便有了版本控制器。版本控制器就是能让我们了解到一个文件的历史以及它的发展过程的系统。通俗的讲就是一个可以记录工程的每一次改动和版本迭代的管理系统同时也方便多人协作。目前最主流的版本控制器就是Git。Git可以控制电脑上所有格式的文件例如doc、excel、dwg、dgn、rvt等等。对于开发人员来说Git最重要的就是可以帮助我们管理软件开发项目中的原代码文件。6.2git简史同生活中的许多伟大事物一样Git诞生于一个极具创新的时代。Linux内核开源项目有着为数众多的参与者。绝大多数的Linux内核维护工作都花在了提交补丁和保存归档的繁琐事务上1991-2002。到2002年整个项目组开始启用一个专有的分布式版本控制系统BitKeeper来管理和维护代码。到了2005年开发BitKeeper的商业公司同Linux内核开源社区的合作关系结束他们回收了Linux内核社区免费使用BitKeeper的权力。这就迫使Linux开源社区特别是Linux的创造者Linus Torvalds基于使用BitKeeper时的经验教训开发处自己的版本系统。他们对新的系统制订了若干目标●速度●简单的设计●对非线性开发模式的强力支持允许成千上万个并行开发的分支●完全分布式●有能力高效管理类似Linux内核一样大的超大规模项目速度和数据量自诞生于2005年以来Git日臻成熟在高度易用的同时仍保留着初期设定的目标。它的速度飞快极其适合管理大项目有着令人难以置信的非线性分支管理系统。6.3安装gityum install git[sjxVM-0-6-centos ~]$ git --versiongit version 1.8.3.16.4在Github创建项目注册账户参考官网提示即可需要进行邮箱验证。创建项目1.登录成功后进入个人主页点击右上角号里的New repository按钮新建项目。2.然后跳转到的新页面中输入项目名称注意名称不能重复系统会自动校验校验过程可能会花费几分钟。校验完毕后点击下方的Create repository按钮确认创建。3.在创建好的项目页面中复制项目的链接以备接下来进行下载。下载项目到本地创建好一个放置代码的目录git clone [url]这个url就是刚刚建立好的项目的链接6.5三板斧1.git add讲代码放到刚才下载好的目录中git add [文件名]将需要用git管理的文件告知git注意git add .表示将当前目录所有新增/修改文件加入暂存区2.git commit提交改动到本地git commit -m XXX最后的XXX表示改动的备注信息提交的时候应注明提交日志描述改动的详细内容3.git push同步到远端服务器上git push需要填入用户名密码。同步成功后刷新Github页面就能看到代码改动了。配置免密码提交git本地免密码和账号pull、push_没有git账号怎么拉代码-CSDN博客4.其它●git log/status/pull●.ignore●首次使用问题7.调试器-gdb/cgdb使用7.1样例代码1 #include stdio.h 2 3 int sum(int s,int e){ 4 int result0; 5 int i0; 6 for(is;ie;i){ 7 resulti; 8 } 9 return result; 10 } 11 int main(){ 12 int start1; 13 int end100; 14 printf(I will begin\n); 15 int nsum(start,end); 16 printf(running done,result is:[%d-%d]%d\n,start,end,n); 17 return 0; 18 }7.2预备知识●程序的发布方式有两种debug模式和release模式Linux gcc/g出来的二进制程序默认是release模式●要使用gdb调试必须在源代码生成二进制程序的时候加上-g选项若没有添加程序无法被编译//默认模式不支持调试 [sjxVM-0-6-centos ~]$ gcc myproc.c -o myproc [sjxVM-0-6-centos ~]$ file myproc myproc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]1820d336c26f5af9a1c39d185c1b7e9fd8b8775d, not stripped //debug模式 [sjxVM-0-6-centos ~]$ gcc myproc.c -o myproc -g [sjxVM-0-6-centos ~]$ file myproc myproc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]86156357b20aafbe138879a46b580f5f4a82e9ef, not stripped7.3常见使用●开始gdb binfile文件的可执行程序●退出ctrl d或quit调试命令命令作用样例list/l显示源代码从上次位置开始每次列出10行list/l 10list/l 函数名列出指定函数的源代码list/l mainlist/l 文件名行号列出指定文件的源代码list/l myproc.c1r/run从程序开始连续执行r/runn/next单步执行不进入函数内部逐过程n/nexts/step单步执行进入函数内部逐语句F11s/stepbreak/b [文件名]行号在指定行号设置断点break 10break test.c 10break/b 函数名在函数开头设置断点break maininfo break/b查看当前所有断点的信息info breakfinish执行到当前函数返回然后停止finishprint/p 表达式打印指定变量的只print/p startendp/print 变量打印指定变量的值p/print xset var 变量值修改变量的值set var i10continue/c从当前位置开始连续执行程序continue/cdelete/d breakpoints删除所有断点delete breakpointsdelete/d breakpoints ndelete/d n删除序号为n的断点delete/d breakpoints 1delete/d 1disable breakpoints禁用所有断点disable breakpointsenable breakpoints启用所有断点enable breakpointsinfo/i breakpointsinfo/i b查看当前设置的断点列表info breakpointsinfo bdisplay 变量名跟踪显示指定变量的值每次停止时display xundisplay 编号取消对指定编号的变量的跟着显示undisplay 1until X行号执行到指定行号until 20backtrace/bt查看当前执行栈的各级函数调用及参数backtrace/btinfo/i locals查看当前栈帧的局部变量值info localsquit退出GDB调试器quit7.4cgdb安装cgdb●上面的基本调试还是麻烦虽然是黑屏但还是想看到代码调试●Ubuntusudo apt-get install -y cgdb●Centossudo yum install -y cgdb7.4.1watch执行时监视一个表达式如变量的值。若监视的表达式在程序运行期间的值发生变化GDB会暂停程序的执行并通知使用者。(gdb) l main 11 12 return result; 13 } 14 15 int main() 16 { 17 int start 1; 18 int end 100; 19 printf(I will begin\n); 20 int n Sum(start, end); (gdb) b 20 Breakpoint 1 at 0x11c3: file mycmd.c, line 20. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000000011c3 in main at mycmd.c:20 (gdb) r Starting program: /home/whb/test/test/mycmd I will begin Breakpoint 1, main () at mycmd.c:20 20 int n Sum(start, end); (gdb) s Sum (s32767, e-7136) at mycmd.c:5 5 { (gdb) n 6 int result 0; (gdb) watch result ///////////////// Hardware watchpoint 2: result (gdb) c Continuing. Hardware watchpoint 2: result Old value -6896 New value 0 Sum (s1, e100) at mycmd.c:7 7 for(int i s; i e; i) (gdb) c Continuing. Hardware watchpoint 2: result Old value 0 New value 1 Sum (s1, e100) at mycmd.c:7 7 for(int i s; i e; i) (gdb) c Continuing. Hardware watchpoint 2: result Old value 1 New value 3 Sum (s1, e100) at mycmd.c:7 7 for(int i s; i e; i) (gdb) c Continuing. Hardware watchpoint 2: result Old value 3 New value 6 Sum (s1, e100) at mycmd.c:7 7 for(int i s; i e; i) (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20 breakpoint already hit 1 time 2 hw watchpoint keep y result breakpoint already hit 4 times (gdb) d 2 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20 breakpoint already hit 1 time (gdb) finish Run till exit from #0 Sum (s1, e100) at mycmd.c:7 0x00005555555551d2 in main () at mycmd.c:20 20 int n Sum(start, end); Value returned is $1 5050注意●若有一些变量不应该修改但是我们怀疑它修改导致了问题可以watch它若变化了就会通知我们●监视变量的变化7.4.2 set var确定问题原因更改标志位假设我们想得到-result/ mycmd.c #include stdio.h int flag 0; // 故意错误 //int flag -1; //int flag 1; int Sum(int s, int e) { int result 0; for(int i s; i e; i) { result i; } return result*flag; } 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; } (gdb) l main 15 16 return result*flag; 17 } 18 19 int main() 20 { 21 int start 1; 22 int end 100; 23 printf(I will begin\n); 24 int n Sum(start, end); (gdb) b 24 Breakpoint 1 at 0x11ca: file mycmd.c, line 24. (gdb) r Starting program: /home/whb/test/test/mycmd I will begin Breakpoint 1, main () at mycmd.c:24 24 int n Sum(start, end); (gdb) n 25 printf(running done, result is: [%d-%d]%d\n, start, end, n); (gdb) n running done, result is: [1-100]0 # 这⾥结果为什么是0 26 return 0; (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/whb/test/test/mycmd I will begin Breakpoint 1, main () at mycmd.c:24 24 int n Sum(start, end); (gdb) s Sum (s32767, e-7136) at mycmd.c:9 9 { (gdb) n 10 int result 0; (gdb) n 11 for(int i s; i e; i) (gdb) 13 result i; (gdb) 11 for(int i s; i e; i) (gdb) 13 result i; (gdb) until 14 Sum (s1, e100) at mycmd.c:16 16 return result*flag; (gdb) p result $1 5050 (gdb) p flag $2 0 (gdb) set var flag1 # 更改flag的值确认是否是它的原因 (gdb) p flag $3 1 (gdb) n 17 } (gdb) n main () at mycmd.c:25 25 printf(running done, result is: [%d-%d]%d\n, start, end, n); (gdb) n running done, result is: [1-100]5050 # 是它的原因 26 return 0;7.4.3条件断点7.4.3.1添加条件断点(gdb) l main 11 12 return result; 13 } 14 15 int main() 16 { 17 int start 1; 18 int end 100; 19 printf(I will begin\n); 20 int n Sum(start, end); (gdb) b 20 Breakpoint 1 at 0x11c3: file mycmd.c, line 20. (gdb) r Starting program: /home/whb/test/test/mycmd I will begin Breakpoint 1, main () at mycmd.c:20 20 int n Sum(start, end); (gdb) s Sum (s32767, e-7136) at mycmd.c:5 5 { (gdb) n 6 int result 0; (gdb) n 7 for(int i s; i e; i) (gdb) n 9 result i; (gdb) display i 1: i 1 (gdb) n 7 for(int i s; i e; i) 1: i 1 (gdb) n 9 result i; 1: i 2 (gdb) n 7 for(int i s; i e; i) 1: i 2 (gdb) n 9 result i; 1: i 3 (gdb) 7 for(int i s; i e; i) 1: i 3 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20 breakpoint already hit 1 time (gdb) b 9 if i 30 # 9是⾏号表⽰新增断点的位置 /////////////////////// Breakpoint 2 at 0x555555555186: file mycmd.c, line 9. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20 breakpoint already hit 1 time 2 breakpoint keep y 0x0000555555555186 in Sum at mycmd.c:9 stop only if i 30 (gdb) finish Run till exit from #0 Sum (s1, e100) at mycmd.c:7 Breakpoint 2, Sum (s1, e100) at mycmd.c:9 9 result i; 1: i 30 (gdb) finish Run till exit from #0 Sum (s1, e100) at mycmd.c:9 0x00005555555551d2 in main () at mycmd.c:20 20 int n Sum(start, end); Value returned is $1 50507.4.3.2给已经存在的断点新增条件(gdb) l main 11 12 return result; 13 } 14 15 int main() 16 { 17 int start 1; 18 int end 100; 19 printf(I will begin\n); 20 int n Sum(start, end); (gdb) b 20 Breakpoint 1 at 0x11c3: file mycmd.c, line 20. (gdb) r Starting program: /home/whb/test/test/mycmd I will begin Breakpoint 1, main () at mycmd.c:20 20 int n Sum(start, end); (gdb) s Sum (s32767, e-7136) at mycmd.c:5 5 { (gdb) n 6 int result 0; (gdb) n 7 for(int i s; i e; i) (gdb) n 9 result i; (gdb) 7 for(int i s; i e; i) (gdb) 9 result i; (gdb) 7 for(int i s; i e; i) (gdb) 9 result i; (gdb) 7 for(int i s; i e; i) (gdb) b 9 # 我们在第9⾏新增⼀个断点⽤来开始测试 Breakpoint 2 at 0x555555555186: file mycmd.c, line 9. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20 breakpoint already hit 1 time 2 breakpoint keep y 0x0000555555555186 in Sum at mycmd.c:9 (gdb) n Breakpoint 2, Sum (s1, e100) at mycmd.c:9 9 result i; (gdb) n 7 for(int i s; i e; i) (gdb) n Breakpoint 2, Sum (s1, e100) at mycmd.c:9 9 result i; (gdb) condition 2 i30 #给2号断点新增条件i30 ////////////////// (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20 breakpoint already hit 1 time 2 breakpoint keep y 0x0000555555555186 in Sum at mycmd.c:9 stop only if i30 breakpoint already hit 2 times (gdb) n 7 for(int i s; i e; i) (gdb) n 9 result i; (gdb) c Continuing. Breakpoint 2, Sum (s1, e100) at mycmd.c:9 9 result i; (gdb) p i $1 30 (gdb) p result $2 435注意●条件断点添加常见两种方式1.新增 2.给已有断点追加●两者语法有区别●新增b 行号/文件名行号/函数名 if i 30条件●给已有断点追加condition 2 i 30其中2是已有断点编号没有if●cgdb分屏操作ESC进入代码屏i回到gdb屏
返回列表