C++的调试技巧

目录

  1. 1. 调试标记
    1. 1.1. 通过预处理器调试标记
    2. 1.2. 运行期调试标记
  2. 2. 将变量和表达式表示为字符串
  3. 3. C语言assert()宏

在开发C++程序的过程中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当遇到需要调试程序的场景<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>优秀的调试器例如GDB等可以使调试的过程变得更有效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使程序的运行更加透明<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但总有不能使用调试器的场景例如嵌入式开发不存在显示屏等情况<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这时可以利用一些调试技巧对程序进行调试

调试标记

当进行程序开发时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能会在源程序中添加一些调试的代码方便测试<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但是后来程序完成的时候需要找到这些代码一一进行删除<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在程序运行的过程中可能有会发现需要这些代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这些麻烦可以利用调试标记解决<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

通过预处理器调试标记

可以利用预处理器标记来分离出用于调试的代码和确保程序正常工作的代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过预处理器定义#define FOOBAR(一般用DEBUG<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但不能用NDEBUG)和ifdef ifndef 等预处理语句可以实现这个目的<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当认为调试完成了<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以利用undef来表示调试已经完成<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>例如如下的代码片段<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight c++"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">#"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">define DEBUG 
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">#"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">undef DEBUG
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">//***
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">#"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">ifdef DEBUG
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">//***
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">#"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">endif

运行期调试标记

某些情况下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>运行期打开调试标记会更加方便<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>例如每次定义预处理标记都会导致程序的重新编译<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg><h-char class=bd bd-beg>为了实现打开或关闭调试<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以定义一个bool型数据变量

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight c++"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">//****
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"type"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">bool debug = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"literal"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">false;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"function"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"type"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">int "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">main"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"type"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">int argc, "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"type"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">char* argv[]){
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">if("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">string(argv[i])== "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"--debug=on") debug = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"literal"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">true;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">//****
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}

将变量和表达式表示为字符串

若在编写程序的时候可以将字符串和变量名与其内容一一用输出打印函数组成打印表达式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但这样的话工作量非常的大<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以通过宏定义和字符串化运算符 # 来将变量转化为一个字符数组<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在预处理语句中的参数前使用#来标记就可以实现这个功能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight c++"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">#"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">define PR(x) cout << #x << "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">" = " << endl;

它与如下语句具有同样的效果<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight c++"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">cout << "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"a = " << a  << endl;

在实际使用的时候也可以使用ifdef来使得P(A) 不起作用

C语言assert()宏

头文件<cassert>中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>有assert()方便的调试宏<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当使用assert时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>参数为一个表示为真的表达式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>预处理器产生测试断言的代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>若测试结果不为真<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>则发生一个错误信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>返回错误信息并终止程序运行<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight c++"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">#"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">include "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><cassert>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">using "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">namespace std;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"function"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"type"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">int "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">main"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">(){
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"type"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">int i="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">100;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">assert(i!="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">100);"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">//fails
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}

在完成调试后<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以通过编译器参数命令行或者在#include<cassert> 前定义 #define NDEBUG 来消除宏产生的测试代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>