一、调试标记
如果在程序中加入调试代码,可能引起不便。一开始得到了太多的信息,这使得很难把故障孤立出来。当认为已经找到了故障时,我们开始删掉调试代码,却有可能发现再需要这些代码。我们可以用两种标记解决这类问题:预处理器调试标记和运行期调试标记。
预处理器调试标记
通过使用预处理器#define定义一个或更多的调试标记(在头文件中更适合),可以测试一个使用#ifdef语句和包含条件调试代码的标记。当认为调试完成了,只需要使用#undef标记,代码就会自动消失(这会减少可执行文件的大小和运行时间)。
#include "stdafx.h"
#include <iostream>
using namespace std;
#define DEBUG /* 定义一个调试标记,可以测试一个使用#ifdef语句和包含条件调试代码的标记。*/
//#undef DEBUG /* 当认为调试完成了,只需要使用此标记关闭,代码就会自动消失 */
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef DEBUG /* 检查标志 DEBUG 是否被定义 */
cout << "Debug 1" << endl ; /* 在这里编写调试代码 */
#endif
return 0;
}
二、把变量和表达式转换成字符串
写调试代码的时候,编写由包含变量名和后跟变量的字符数组组成的打印表达式是很乏味的。幸运的是,标准C具有字符串化运算符 ‘#’ 。在一个预处理器宏中的参数前面使用一个 # ,预处理器会把这个参数转换为一个字符数组。把这一点与没有插入标点符号的若干个字符数组结合而连接成一个单独的字符数组,能够生成一个十分方便的宏用于调试期间打印出变量的值:
#include "stdafx.h"
#include <iostream>
using namespace std;
#define P(A) cout << #A << ": " << (A) << endl ;
static int static_a ;
int _tmain(int argc, _TCHAR* argv[])
{
P(static_a);
return 0;
}
三、C语言assert宏
在标准头文件<cassert>中,会发现assert() 是一个方便的调试宏。当使用assert() 时,给它一个参数,即一个表示断言为真的表达式。预处理器产生测试该断言的代码。如果断言不为真,则在发出一个错误信息告诉断言是什么以及它失败之后,程序会终止。
#include "stdafx.h"
#include <iostream>
//#define NDEBUG //用此关闭assert调试
#include <cassert>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int i = 100 ;
assert(i != 100);
return 0;
}
这个宏来源于标准C,所以在头文件assert.h 中也可以使用。
当完成调试后,通过在程序的 #include <cassert> 之前插入语句行
#define NDEBUG
或者在编译器命令行中定义ndebug, 可以消除宏产生的代码。在<cassert>中使用的 ndebug 是一个标记,用来改变宏产生代码的方式。