你是怎么调试的?

2013-05-28 16:43:00 +08:00
 YUCOAT
作为一枚学生,我觉得我们编程方面的教育在两个地方存在严重的不足,第一点是不注重代码的规范,第二点就是没有注重调试能力的培养。

第一个问题其实不是什么大问题,很多人自学编程学到一定程度的时候开始注重代码的规范性。读多了,写多了,代码的风格就固定下来了。在学校里面,基本上扫一眼代码的风格就可以粗略地判断这个人的编程水平,这一点你同意吗?反正我身边是这样。

第二个问题就是该帖子的重点,也就是调试的问题了。
我多半是在Linux平台写C程序,写了两年左右的样子,说来也惭愧,调试工作一直都做得不好,用gdb调试的时候也仅仅局限于“设置断点-执行-watch、s、print”,代码比较短的时候还比较好,假如长到1000行再多一点循环语句,调试起来就会很吃力。

除了gdb,其实Linux下还有很多其他的调试工具,但我一直都没怎么去研究。
其实我还算好的了,平时编程要是遇到什么问题,一般都能通过调试解决,只是我的调试方式效率有点低。而且没办法判断程序是否出现内存泄漏。

网上编程的例子一抓一大把,相比之下debug方面的教程就少得多了,书店里面也是这样,往往难得找到一本不错的debug书。在这样的环境之下,大家都来说说是怎么学习调试的。
3513 次点击
所在节点    Linux
6 条回复
greatghoul
2013-05-28 17:07:09 +08:00
1. 代码规范

等你到了单位,许多单位都有现在的代码指导规范,甚至一些公司已经具体化到了 IDE 中,会自动提醒你写出符合公司要求的代码,所以单靠代码风格不太能很准确的判断一个人的能力。

真正的水平,体现在代码的质量上,而不是风格,漂亮的解决业务中的问题,同时容易阅读,注释得当,逻辑清晰,很少重复,一般来说,就是好代码。

2. 关于调试。

我没有写过 C ,但说说我调试的方法,我会优先使用日志覆盖,在关键的位置打上合理级别和内容的日志。这样做有如下好处。

- 不需要断点,哪里出错从日志上大概就能看出来,然后直接察看日志附近的代码
- 为以后考虑,试想到了生产环境,你哪里还有机会去设置断点,如果真的程序出了问题,
通过历史的日志,还能了解一些现场的情况,这些都是断点做不到的。

当然了,最好是两者结合起来用,对于一些问题,断点的确比日志要快一些,但是尽量少用吧。

仅是个人经验
fangzhzh
2013-05-28 17:10:45 +08:00
debug: 一般问题, printf, 教严重的dump core 的问题: gdb
学习debug, gdb cheetsheep是你的好朋友, 附上 google第一个结果: http://darkdust.net/files/GDB%20Cheat%20Sheet.pdf
我当时用gdb的时候,打了一份在手边

内存泄漏 linux 的话, valgrind, 你用了绝对会喜欢.

题外话: 很早看过一句话: debug is the mother of all evils, 当时不以为然. 慢慢的发现, 流程很重要.
debug解决的是语法,最多是逻辑的问题, 对流程问题无能为力.
有时候,如果很长时间的调试, 改来改去,有时代码能用,有时代码不能用,那么就跳出来想一想,是不是流程不对, 有时候流程对了,就会少很多莫名其妙的错误.
alexrezit
2013-05-28 17:14:08 +08:00
扯淡. 从学习编程 (Objective-C 是我的入门语言) 第一天起我就开始保证大小写命名规则缩进风格完全和官方一致了, 甚至不清楚的时候还会花上很久去读官方的源码.
alexrezit
2013-05-28 17:18:09 +08:00
另外说句题外话: 虽然我认识的人不是很多, 但在我所认识的编码风格干净整齐的人与编码风格乱糟糟的人这两种人之间, 收入差距可以达到 2-5 倍, 技术水平和文明程度 (例如平时讲话的用词, 行为习惯, 出版物和软件的正版率等等) 也相差甚远.
efi
2013-05-28 18:13:27 +08:00
内核panic只打印一串函数调用栈,内核开发者光看这一串调用就能看出问题所在。为什么?因为他们非常理解在问题发生路径上这些函数应该做什么,不应该做什么。debug最终是要理解代码的目的,发现程序体现出什么与此目的不一致的状态,才能真正解决问题。用debugger补东补西只是治标,不能增加对程序的理解。

我采取的一般做法是:发现症状以后
1. 找到发生症状的代码位置(看日志、core)。
2. 理解上下文代码。
3. 根据症状对问题发生的位置、原因提出几个快速猜想。
4. 实验重现,在相应的地方查看程序状态是否符合设计,猜想是否成立:
5a. (对于小程序)如果没有猜想成立,在代码调用流程上加printf做二(多)分查找,缩小范围,直到找到某一处程序状态不符合设计,转3。
5b. (对于大程序)如果没有猜想成立,按照代码提交历史作二分查找(git bisect),直到找到两个相邻版本不一致,查看差异代码,转5a或3。
6. 猜想成立,修复,再重现一次验证修复。结束。

其实这就是分治法+科学方法
https://en.wikipedia.org/wiki/Scientific_method

调试工具主要适用于难以通过修改程序来实验测试猜想的环境(比如生产环境,特殊架构,特殊设备,自动化)。
efi
2013-05-28 18:19:31 +08:00
对了,调试实验的时候打开ccache可以大幅提高重新编译速度。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/70420

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX