在你的dsa课上召唤上古神兽:vim/gdb基本用法

# 笔记 | 在你的dsa课上召唤上古神兽:vim/gdb基本用法 因为一些机缘巧合尝试了解一些古老的工具,感觉挺好用,简单分享一下。 **vim简介** Vim 是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,被广泛使用。 简单的来说, vi 是老式的字处理器,不过功能已经很齐全了,但是还是有可以进步的地方。vim 则可以说是程序开发者的一项很好用的工具。 一般Unix like的系统都会自带vi 编辑器,但不一定带vim,需要安装: ``` sudo apt-get install vim -y ``` 安装后可以在任意目录下输入 ``` vim foo ``` 即可打开一个名为foo 的文本文件。当然,也可以把foo换成你想要的其他名字。 这时候会看到这样的界面: ![](/static/uploads/images/ae57162c5d4ace9bdbcebc7eb386d7e3.jpg) ### 如果想要退出vim编辑器,只要输入 ``` :wq ``` ### 即可保存当前文件并退出。 当然,我们打开文件肯定是希望往里面写东西的。刚刚打开的vim处于**命令模式**,只要输入 ``` i ``` 就可以进入**输入模式**,此时可以正常的输入内容。(注意最下面状态栏显示 -- INSERT -- ) ![](/static/uploads/images/e11d08be4cd406d6fadb97bcf52b132b.jpg) 假如我们输入一些东西如图: ![](/static/uploads/images/68df16f865735c3e80086db46d8f5022.jpg) 这时,按下ESC键(键盘左上角,不是按下E,S,C三个键),就可以退出**输入模式**,进入**命令模式**。这时候界面应该像这样: ![](/static/uploads/images/62ffaaf28d7b4a45859d7218aa1bb99e.jpg) 命令模式下,顾名思义可以执行很多操作。比如,按两下y 键可以复制当前行,再按下p 键可以粘贴。我们把这句话粘贴10行: ![](/static/uploads/images/810171cb8dffc54ca129f17ac64e5006.jpg) 其他一些常用命令包括: * gg 回到文件头 * dd 删掉一行 * d114514 删掉114514行(换掉数字可以删掉其他数目的行) * /apple 查找文件全部的apple字符串,再按n查找下一处(换掉apple可以查询其它字符串) 当然其他命令可以查看这张经典图了解(tb有同款鼠标垫,但用vim和用鼠标的人群/场景疑似交集不大) 【https://www.runoob.com/w3cnote/all-vim-cheatsheat.html】 ![](/static/uploads/images/eb68db7073a5544227ede21637cca294.jpg) 假设这时候我们差不多折腾完了,就可以输入 ``` :wq ``` 保存文档并退出vim编辑器。 这时候再在当前目录下ls,即可找到我们刚才编辑的foo文件。 ![](/static/uploads/images/eecb20b3faecbdf7a9623bf4f23d1199.jpg) **gdb简介** gdb其实和vim没啥关系,这玩意是个调试器(debugger)。 gdb同样需要安装: ``` sudo apt-get install gccsudo apt-get install gdb ``` 比方说我们写了一个程序bar.c,他长这样: ![](/static/uploads/images/e3f52cc4c881886b532fefae334db7a4.jpg) 这时候我们退出vim,输入指令(如果你是cpp,则把gcc换成g++) ``` gcc -g bar.c -o bar ``` 就能用gcc进行编译。看起来什么都没有发生,但只要ls一下,就会发现多了一个bar文件: ![](/static/uploads/images/1f63f6660bf1fddef47aaea6edb6e5f8.jpg) 我们运行bar: ``` ./bar ``` 就会显示运行结果 ![](/static/uploads/images/301e269af025fc32e1f665713fe0682e.jpg) 这跟我们预想的不一样!别急,下面我们使用gdb工具进行调试。 输入指令: ``` gdb bar ``` 就可以进入调试界面: ![](/static/uploads/images/beed98db93882458105c9c795f74feb7.jpg) 再输入 ``` layout regs ``` 进入寄存器界面: ![](/static/uploads/images/aad21b63a7d2d9e25f25ce846159352f.jpg) 这里最上面是各个寄存器(因为没有运行程序,啥都没有),中间是源码,下面是命令行。 根据输出猜测是没有排好序就退出了,因此我们在swap处放一个断点,再在22行(退出逻辑)放一个端点: ``` b swapb 22 ``` ![](/static/uploads/images/a69eeedbf29ba4f52b249ed946d2856e.jpg) 好晦气,怎么全是b+ 这样就表示放置了两个断点。当程序运行到那里时,b+会变成B+(更晦气了),并暂停。我们输入 ``` r ``` 即可运行程序。 ![](/static/uploads/images/03b22fa17c373afe294437489f15b03c.jpg) 众所周知,函数前六个参数都在交接控制权前依次放在rdi, rsi, rdx, rcx, r8, r9这几个寄存器中,因此观察调用信息不难推断这一次调用为 ``` swap(0x555555558020, 0x555555558024); ``` 我们用这条指令以十进制打印首地址为0x555555558020的10个字: ``` x/10wd 0x555555558020 ``` ![](/static/uploads/images/b83b5e88e5658b211f2aee966b4a56d2.jpg) 可以看到我们的array[]数组确实存在这里。我们使用指令 ``` c ``` 继续运行程序到下一个断点: ![](/static/uploads/images/b7f8e96cf5b72d16dfc22cdce41f96b5.jpg) 再看一下array[]数组: ![](/static/uploads/images/b4466db812f182ae4000a9554c7a1723.jpg) 使用 ``` s ``` 命令一步一步运行: ![](/static/uploads/images/4270266345e0054f2a64baf0ebaf8a63.jpg) 发现第二次外循环,虽然有多处需要互换,但没有检测到,直接跳过了! ![](/static/uploads/images/4297c87e7d4b0bef212212499987e723.jpg) 并输出了错误结果。 于是便不难发现源代码的错误之处:这个选择排序的剪枝优化做错了。正常而言,应该确保后面顺序全对,才能终止;但这里只要a[i]是它及其后元素中的最小值就会终止,并不会保证后面顺序正确。 在vim中修改代码,再使用指令 ``` gcc bar.c -o bar -O2 ``` 进行编译(带O2优化)。再次运行: ``` ./bar ``` ![](/static/uploads/images/90512b2a9ecb8f2ed8fcb66b73ea8389.jpg) 发现程序输出了正确的结果!大功告成。 gdb的用法其实很丰富,可以参考http://csapp.cs.cmu.edu/2e/docs/gdbnotes-x86-64.pdf 进一步了解。 **后记** ### 还是被可视化界面惯得太好了。 另:祝大家中秋快乐!有时候倒腾倒腾老家伙还是挺好玩的,比如这个vim也算是越用越舒服了(前情提要:鼠标坏了,新鼠标太难用了。) **参考资料** https://www.runoob.com/linux/linux-vim.html https://www.runoob.com/w3cnote/all-vim-cheatsheat.html https://linuxtools-rst.readthedocs.io/zh-cn/latest/tool/gdb.html

评论

留下评论

邮箱仅用于识别,不会公开

支持 KaTeX:$...$ 行内 · $$...$$ 独立公式
加载评论中...