作为软件工程专业学生,刚进大学的第一堂编程课,是在Microsoft Visual C++ 6.0中用C++打印出"Hello World":点一下屏幕上方的三角形按钮开始调试,程序无错便在屏幕最上层弹出一个黑框,黑框里的第一行文字,是"Hello World"。
待工作之后,发现编译调试C++程序,不在Windows环境下也可以,只需要在Linux系统中输入两行指令:
bash
gcc -o helloworld helloworld.c
./helloworld
# Hello World
也能得到想要的答案:Hello World!
随着工作越久,写的代码越发复杂,调试代码在工作中的占比越发高了起来。如何能够保证调试代码方便、快捷又专业呢?
养成阅读习惯三年的我,第一反应是找一本书来补补课。
寻书过程很简单,只以"C++调试"作为关键字于书城中搜索便好。做一些简单对比,我最终选定《C/C++代码调试的艺术》看了起来。全书近16万字,我按照书中示例边敲边看,累计花8个半小时看完。
一般讲解某项技术的技术书,会不止讲解该项技术,还会将该项技术的来龙去脉理清楚,并将相关联知识点都进行收录(甚至会推荐更精细化的书)。于是完整读完一本技术书相较阅读某篇博客获取知识是有很大优势的,每读完一本技术书,都会在脑子中维护一个关于某项技术的全面目录。当工作中需要用到该项技术时,先翻阅脑中目录,如若脑中详细内容不再清晰,则再依据书中目录寻找详细答案。
《C/C++代码调试的艺术》,顾名思义,便是关于"C/C++代码调试"的全面讲解。书中大体内容如下:
全书围绕C/C++程序调试这一主题,系统深入地介绍了在Windows和Linux操作系统上如何高效地调试C/C++程序。本书分为11章,内容涵盖了程序调试的基本知识、Visual C++调试的基本功能与技巧、Linux系统中gdb工具的使用、死锁调试、动态库调试、内存检查、远程调试、转储文件调试分析、发行版调试,以及调试的高级话题和调试方面的扩展知识。
如上简介所述,作者将C/C++代码的调试分作两个方向讲解,一是在Windows上基于Visual Studio的调试;二是Linux系统中gdb的使用。每一个章节,即讲了Windows上的操作方式,也介绍了Linux下的处理手法。
书中内容,由浅入深,不管读者是初学者还是资深开发者,都能够从书中获取到想要的知识。对初学者来说,是新知识的获取;对资深开发者来说,是参考手册。
我极其佩服作者对于书中浅显部分的处理。对于刚开始学习调试程序的新手(visual studio相当复杂,即便是老手,也可能要花很长时间找一个按钮)来说,找到调试软件中的某个按钮,是极可能花费半小时甚至更久的,作者在书中,将这些按钮位置通过截图展现的清楚明白。此种细节的处理,体现了作者的严谨、耐心与专业。
除了介绍简单常用的调试技巧之外,书中还介绍了许多高端玩法。
- C/C++程序的内存由程序员自己管理,当程序逻辑不严谨时,很容易造成内存泄露。本书第6章,是专门的内存检测章节,通过修改编译选项、启用地址擦除系统等方式,堆溢出、栈溢出,都能被检测到。
- 当开发环境不由我们自己掌控时,可以进行远程调试,Windows连Windows、Linux连Linux,Windows连Linux,只要有网络有工具,万物皆可调试。
- 发布给客户的程序不包含调试信息,调试起来会很困难,此时可以借用调试版本中的调试符号供发行版本使用。
- 想要更深入的了解程序背后的运作机制,能看懂些汇编代码是必不可少的技能。看懂汇编代码,便能借助工具不修改源码直接修改二进制文件对程序进行一些改造。(此方法为黑客必备技能。)
不管是简单调试还是高端玩法,书中都有完整Demo可以让读者跟着动手。按照书中示例代码进行调试时,我记录了部分会在工作中频繁使用的一些gdb指令(Windows上的调试,大都是图形界面,需要用时直接翻书便好),摘录到此处供查阅:
bash
# 开始调试
gdb appname
# 在filename.cpp的第350行添加断点
b filename.cpp:350
# 打印变量名
print var_name
# 查看断点列表
info break
# 查看调用栈
bt
# 可以直接切换栈
frame 3
# 列出所有的局部变量
info locals
# 查看当前函数的参数
info args
# 查看当前帧的信息
info frame
# 继续执行
c
# 执行下一行
next
# 进入下一个函数
s
# 跳出当前函数
finish
# 展示字符串打印的长度
show print elements
# 将字符串打印长度限制去掉
set print elements 0
# 设置打印更美观
set print pretty
# 更美观地打印数组
set print array on/off
# 打印vector的值
print *(vector_name._M_impl._M_start)@2
# 查看当前位置10行源代码
list
# 查看函数的源代码
list func_name
# 在gdb中执行shell的ls指令
shell ls
更多的指令,可以在gdb环境中使用help
随用随查。
本书的推荐语为:"《C/C++代码调试的艺术》是一本关于C/C++调试的'百科全书',关于C/C++调试的方方面面,书中都有详细讲解。
"如果您的工作中经常使用C/C++调试,是可以借助本书于脑中形成一个关于调试的全面目录,然后将书常备案头待需要时再随手翻阅的。"