目录前言一、git中的常见命令git常见命令gitignore介绍二、gdb预备知识编译与模式2.1 gdb常见命令2.2 断点之用途2.3 程序的运行与暂停2.4 堆栈跟踪三、gdb中的三种调试技巧3.1 变量监测watch3.2 set var3.3 条件断点本文系统介绍了Git版本控制与GDB调试的核心知识。Git部分涵盖常用命令git add、commit、push、.gitignore文件作用及冲突解决策略GDB部分重点讲解编译调试模式-g选项、断点设置、单步执行、堆栈跟踪及变量监控技巧。结合实例演示了watch监测变量、setvar动态修改变量值、条件断点等高级调试方法助力高效定位代码问题。前言理解版本控制也就是对历史版本进行备份Git 是分布式版本管理工具帮你保存代码的每一次快照随时回退、对比、分支开发不会因为改代码把旧版本搞丢。git不仅具有版本控制功能还具有网络同步功能用来在多个仓库之间互相传输版本快照。git可以在本地使用而gitee则可以建立一个本地仓库用于协同合作那么首先我们需要在本地安装一个git命令如下[rootVM-0-4-centos ~]# yum install -y git那么上面我们说了在gitee中可以建立一个远端仓库那么远端仓库怎么下载到本地呢这里我们首先找到克隆点击后选择这个栏目下的链接即可这里为了保密我没有展示将链接复制后打开XShell使用该命令即可实现远端仓库下载到本地[rootVM-0-4-centos ~]# git clone https://gitee.com/-----//后面的详细信息被我省略了此外在使用cgdb时我们会有一个小问题就是有时光标会消失按什么键都没有反应这一般时因为误触了滚轮方向键等导致光标切换到代码区了这时只需要按下 i 即可恢复再按ESC又可切换一、git中的常见命令git常见命令git add把修改信息添加到暂存区git commit -m 描述把暂存区打包成本地版本快照存在本地.git 仓库双引号中为日志git push把本地所有新提交的版本上传到远程仓库对于上述命令我们需要注意的是执行这三条命令如果想同步到远端仓库的话需要先进入git clone所生成的那个文件夹否则会报错[rootVM-0-4-centos kks-paradise]# ls -al total 24 drwxr-xr-x 3 root root 4096 Oct 17 10:27 . dr-xr-x---. 13 root root 4096 Oct 17 16:00 .. drwxr-xr-x 8 root root 4096 Oct 17 17:04 .git #这个就是我们的仓库所有的版本记录全在这里 -rw-r--r-- 1 root root 270 Oct 17 10:27 .gitignore -rw-r--r-- 1 root root 955 Oct 17 10:27 README.en.md -rw-r--r-- 1 root root 1316 Oct 17 10:27 README.mdgitignore介绍作用告诉 Git哪些文件 / 文件夹不要纳入版本管理不要提交到仓库可以在ignore中添加需要被忽略的后缀它通过这样的方法过滤掉带有特定后缀的文件让对应的临时文件不被管理。那么在多人协作时如果出现了本地和远端历史不一样时出现了冲突先把远端最新的提交到本地合并本地代码变成最新版本再push上传远端仓库的价值在于保持最新命令git pullgit fetch下载远端快照 git merge合并到本地当前分支那么上述我们已经简单了解了怎么管理代码接下来我们来了解怎么调试代码二、gdb预备知识编译与模式linux下gcc/g编译的程序默认是release模式无法直接用gdb调试要启用调试必须再编译时添加 -g选项生成debug模式的可执行文件。Reading symbols from xxx...(no debugging symbols found)...done. # 括号中的内容表示无法调试没有调试符号一般gcc和g编译程序默认是以release方式发布的如果通过这个方式发布的程序就无法调试解决方法是添加 -g 调试mycmd:mycmd.c gcc -g mycmd.c -o mycmd2.1 gdb常见命令首先准备一段调试用代码#include stdio.h int Sum(int s, int e) { int result 0; int is; for (; i e; i) { result i; } return result; } 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/cgdb 中的命令均可简写只需打出首字母比如d为delete下面我们举出几个常见的gdb中的命令。cgdb的区别是有一个可视化界面需要自行安装一般建议使用cgdb开始gdb fille退出q命令作用l列出指定文件的源代码r执行当前程序n单步执行不进入函数内部s单步执行进入函数内部b 行在该行处设置断点不加行数字则默认第一行如果是b函数名则在函数第一行达断点2.2 断点之用途断点是调试的核心通过在断点的设置可以实现确认错误发生区域的功能在gdb中对断点的设置有多种形式现在为大家列出。(gdb) b Sum #在函数Sum第一行打上断点 Note: breakpoint 2 also set at pc 0x400587. Breakpoint 3 at 0x400587: file mycmd.c, line 4.查看断点(gdb) info b #查看断点 Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004005b5 in main at mycmd.c:12 breakpoint already hit 1 time 2 breakpoint keep y 0x0000000000400587 in Sum at mycmd.c:1 3 breakpoint keep y 0x0000000000400587 in Sum at mycmd.c:4 (gdb) d b 3 #删除第三个断点 Ambiguous delete command b 3: bookmark, breakpoints. (gdb) d b 2 Ambiguous delete command b 2: bookmark, breakpoints. (gdb) b 13 #删除之后如果再添加新的断点的话那么会考虑已删去的排序 Note: breakpoint 1 also set at pc 0x4005b5. Breakpoint 4 at 0x4005b5: file mycmd.c, line 13.对于断点的删除与禁用(gdb) d breakpoints #删除所有断点 Delete all breakpoints? (y or n) y (gdb) info b #查看当前断点 No breakpoints or watchpoints. (gdb) disable breakpoints #禁用当前断点 (gdb) enable breakpoints #启用当前断点2.3 程序的运行与暂停先给大家列出一些命令命令功能示例c从当前位置执行直到下一个断点或程序结束continuen单步执行不进入函数内部逐过程s单步执行进入函数内部逐语句finish执行完当前整个函数停在函数返回之后回到调用这个函数的地方。u 行快速执行到指定行不加行则直接跑完整个循环停在循环外面那行逐过程与逐语句的区别next : 逐过程执行下一行源码如果这一行有函数调用直接把整个函数跑完不进入函数内部停在当前函数的下一行。(gdb) n # 执行一行遇到函数直接跳过进去的过程 (gdb) n 3 # 一次性连续执行3行steps逐语句执行下一行源码遇到自定义函数会进入函数内部停在函数第一行。注意printf这种库函数默认不会进。此外在调试时还有一个常显示的功能比如我们要看for循环执行到第几层了可以使用 p(gdb) p i #print i $1 7 #左边的1表示这是第一次print的数但是这样的话我们每次想看都需要使用p如果想要每次执行都能够自动显示的话(gdb) display i #每次都打印i 3: i 13 (gdb) n 3: i 13 (gdb) n 3: i 14 (gdb) n 3: i 14 (gdb) undisplay i #注意这种方式不对后面应该接监视项的编号数字不能直接写变量名 i。 warning: bad display number at or near i (gdb) undisplay 3 #取消编号为3的display (gdb) n (gdb)当然display还可以显示很多东西比如 i 的地址(gdb) display i 1: i (int *) 0x7fffffffe428 (gdb) n 1: i (int *) 0x7fffffffe428 (gdb) n 1: i (int *) 0x7fffffffe428 (gdb) n 1: i (int *) 0x7fffffffe428 (gdb)此外在调试中还有一个until继续执行程序直到到达指定行号 / 跳出当前函数然后停下。但要注意的是不能回退(gdb) until 12 0x00000000004005dc in main () at mycmd.c:17 #当前代码在17行不能跳到12行 (gdb) u 15 running done, result is: [1-100]5050 0x00007ffff7a2f555 in __libc_start_main () from /lib64/libc.so.6 (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y The program being debugged has been started already. Starting program: /root/lesson/mycmd I will begin Breakpoint 1, Sum (s1, e100) at mycmd.c:4 #断点在第四行当前停在了这里 (gdb) u 10 Sum (s1, e100) at mycmd.c:10 #成功运行了 (gdb)查看当前栈帧的所有局部变量栈帧每调用一次函数就会在栈上开辟一块独立内存区域这块区域就叫栈帧。(gdb) info locals start 1 end 100 n 32767修改变量的值# set var 变量名 值 set var n 0 #将局部变量改为02.4 堆栈跟踪当程序崩溃时堆栈跟踪时定位问题的关键gdb中 backtrace可以查看函数的调用链(gdb) bt #0 0x00000000004005dc in main () at mycmd.c:17核心规则#0永远是当前正在执行的函数编号数字越大代表越早调用的外层函数函数 return 之后它的栈帧直接消失bt 里面就看不到这个函数了三、gdb中的三种调试技巧3.1 变量监测watch作用watch 变量当这个变量的值被修改时程序自动停下。(gdb) watch i # 监测for循环中i的变化 Hardware watchpoint 2: i (gdb) n (gdb) n Hardware watchpoint 2: i #i变化时立刻打印出来了 Old value 2 New value 3 0x00000000004005a0 in Sum (s1, e100) at mycmd.c:6注意watch 只能监测当前栈帧能访问到的变量如果你已经finish退出 Sum 函数Sum 的局部变量n栈帧销毁不能再 watch n。 必须在进入 Sum 函数、栈帧还存在的时候设置watch n。局部变量出了函数就失效全局变量可以全程 watch。3.2 set var作用调试时直接修改内存里变量的值不改动源码文件。可以直接确定并验证问题的原因适用场景场景 1修复未初始化的垃圾值int n; // 没初始化栈上是随机垃圾值32767gdb 进入 Sum 后info locals set var n 0把垃圾值手动清零继续单步调试看程序正常逻辑。场景 2强制触发 if/else 分支假设代码if(n 10) { // 分支A } else { // 分支B }调试时程序走到else你想直接看分支 A的执行效果set var n 20 n直接修改 n强制跳进 if 分支不用改源码。场景 3模拟异常情况比如判断ret malloc(1024)想模拟 malloc 失败返回 NULLset var ret NULL直接让后面代码走内存分配失败的逻辑很难手动构造的场景一键模拟。场景 4跳过循环直接修改循环控制变量while(cnt 100) { cnt; }调试到循环中间不想一步步循环直接set var cnt 100下一次循环判断直接退出快速跳出循环。3.3 条件断点当需要满足特定情况时触发断点可以使用条件断点(gdb) b 9 if i20 #在第九行添加断点注意是两个等号 Breakpoint 3 at 0x4005a8: file mycmd.c, line 9. (gdb) info b Num Type Disp Enb Address What 3 breakpoint keep y 0x00000000004005a8 in Sum at mycmd.c:9 stop only if i20 (gdb) condition 3 i30 #给三号断点追加条件会覆盖已有条件也可给已有断点添加条件 (gdb) info b Num Type Disp Enb Address What 3 breakpoint keep y 0x00000000004005a8 in Sum at mycmd.c:9 stop only if i30上述就是本期的全部内容对于git工具的用法我会在后续再出一个更加详细的内容~