C++调试经验小结

工作稍微有一段时间了,实践过程中遇到了一些debug方面的问题。涉及到的细节时间长了难免会有遗忘,因此在这里记录下来,也希望能对其他正在和bug做苦苦斗争的同学能有所帮助。

  • valgrind
    这工具是Linux下面检查内存错误的大杀器,主要用来程序在内存操作上的问题,包括越界读写,内存泄露等。具体工作原理可以参考这里
    valgrind最大的问题是,它是在运行时检查程序的内存问题的,会让程序的运行速度降低20倍左右。对于玩具程序而言这不是什么问题,但是如果你的程序初始化就需要十分钟的话,用它来检查问题的可操作性就很弱了。
    另外一个问题是,valgrind不能设置检查的范围(也可能是我不会使)。如果你的程序需要链接各种外部库,那么很可能你需要检查的错误信息会淹没在外部库的出错信息里面。
  • gdb调试
    用gdb调试程序应该是每一个linux下c++程序员的必修课,不过对于内存越界仍然有一些trick可以用。
    对于最理想的越界情况,类的成员变量或者堆上的数据被破坏导致程序出错,这时候只需要定位到出错时候出问题的数据内存地址,再用watch *0x12345这样的方式设置watch断点,就可以断到导致越界的凶手处了。
    不过内存越界往往会破坏一些奇怪的地方,导致gdb看上起根本没法儿调试。比如有时候越界写可能导致c++对象的虚函数表被破坏,这种情况会导致出错时候最后一层函数的调用堆栈变成问号。因为虚函数表其实就是保存在对象开头处的内存指针,只需要针对出错对象的内存地址使用watch断点就可以找到犯罪现场了。
  • 静态代码检查
    相比较于valgrind, gdb这些费时费力亡羊补牢的方式,静态代码检查工具可能会省掉很多不必要的调试时间。最常用的可能就是cppcheck这个工具了,它会检查数组越界、内存泄露、资源未释放等等问题。
  • 性能调优
    可能很多人会使用log日志等方式来自己统计性能。但是这么做统计的粒度取决于日志输出的频率,同时还需要使用宏或者其他方式针对release和debug环境做不同的处理。目前看来最好用的方案是google的性能统计工具gperf tools。这个工具的优点在于可以进行函数级别的性能统计,对程序本身的性能影响可控(取决于你需要的统计频率,用户可以针对统计精度和性能影响之间做权衡),并且可以不用修改程序源代码。
    gperf tools的使用本身没有什么好说的,需要注意的一点是,使用官方推荐的libunwind(一个gperf tools的依赖库)版本会导致程序崩溃,我在使用最新的git上的版本以后没有遇到问题。
    对于需要统计性能的程序,需要在编译时候使用-g参数将函数符号编译进去,否则最终统计出来的性能数据中只能看到内存地址,看不到函数名。
    最后一个需要注意的地方就是,如果被统计的程序一直处于挂起状态是没法儿统计到数据的。gperf tools需要程序一直占用cpu,然后才会进行断点统计。

VirusBuster — Shanghai Gamejam 2013参赛作品

上周末(7月19)被石曦拽去上海参加了第三届Shanghai Gamejam,然后还拉上了鹏鹏。到了现场发现全是码农的天下,美术总数不超过10个人。比赛现场拉了几个人,最后组成了一个6个人的小团队,通过两天的奋战做出来了这款Virus Buster。

VirusBuster_title_small

比赛的主题是“异类”,讨论后决定做这个白细胞吞噬其他病毒的休闲类游戏。引擎使用了Unity,发现用Unity做2D游戏开发效率非常高。结合引擎内置的Physix,直接省掉了碰撞检测、物理控制等工作。另一方面,因为用的语言是C#,进一步降低了代码量。

一开始的版本是完全没有挑战的类似吃豆子感觉的东东,大家觉得太没有挑战,于是加入了障碍物、会发射子弹的敌人等等东东。觉得难度还不够,于是又增加了玩家控制的惯性,同时还加入了每吃一个病毒会加速的设计。结果到后来感觉做的这个游戏越来越像“是男人就撑30秒”了。美术这边小强为各位病毒同学加上了小脸,于是整个游戏有了一种莫名的萌感。带刺的荆棘(或者说是树枝?)会随着游戏进程不断长出来,然后还会随着水流诡异摇来摇去,等着玩家撞上去送死 囧。

到比赛结束提交最终版本的时候游戏已经有了初步的可玩性。不过因为始终只是两天搞出来的东西,游戏内容并不是很长。期待后续加入更复杂的关卡和敌人后会更加吸引人;除此之外放到iOS和android上面用陀螺仪来控制也应该会很有趣。感兴趣的童鞋到下面去下载比赛时提交的版本来试试吧。

 

点这里下载