C++的调试技巧

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

调试标记

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

通过预处理器调试标记

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

#define DEBUG 
#undef DEBUG
//***
#ifdef DEBUG
//***
#endif

运行期调试标记

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

//****
bool debug = false;

int main(int argc, char* argv[]){
    if(string(argv[i])== "--debug=on") debug = true;
//****
}

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

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

#define PR(x) cout << #x << " = " << endl;

它与如下语句具有同样的效果

cout << "a = " << a  << endl;

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

C语言assert()宏

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

#include <cassert>
using namespace std;

int main(){
    int i=100;
    assert(i!=100);//fails
}

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