首页 > 代码库 > 第六篇:使用预处理器帮助调试

第六篇:使用预处理器帮助调试

前言

       你是否遇到过以下情况?

       情况一:为了调试方便,代码中夹杂各种cout语句。当调试好了,把这些语句删了,运行“正式版”后,又发现新问题,只得把这些cout语句一个个添加回去再进行调试。如此不断循环。

       情况二:希望在代码中获取到源文件的文件名,当前代码行号,编译时间等信息。

       情况三:纠结于是否实现某些概率极低(几乎不存在)的错误检测

       如果有,那么这篇随笔适合你,或者说,预处理器带来的调试技术适合你。

技巧一:设置调试区代码开关

       请看下面的源代码:

 1 #include <iostream> 2   3 using namespace std; 4   5 int main() 6 { 7     /* 8     * 源代码区一 9     */10 11     #ifdef DEBUG112     cout << "DEBUG1" << endl;13     #endif14  15     /*16      * 源代码区二17     */18 19     #ifdef DEBUG220     cout << "DEBUG2" << endl;21     #endif22 23     /*24      * 源代码区三25     */26 27     return 0;28  }

       两段包含cout语句的代码段都是调试语句,而两个宏DEBUG1和DEBUG2就是所谓的开关。现在假设我想执行上面的那段调试代码,则可以输入以下指令打开DEBUG1开关并完成编译(这条命令等效于在源文件开头加上#define DEBUG1再编译):

1 g++ -DDEBUG1 1.cpp -o run

       运行结果如下:

  技术分享

  结果显示DEBUG1开关对应的调试语句得到执行。可以用同样的方法操纵开关DEBUG2及其对应调试代码。明白了吧,你可以通过打开开关自由地选择需要编译并运行的调试区代码。

技巧二:使用预定义宏获取相关信息

       预处理器提供了一些预定义的宏可获取编译,文件的相关信息,参见下面代码:

 1 #include <iostream> 2  3 using namespace std;  4  5 int main() 6 { 7     cout << "文件名: " << __FILE__ << endl; 8     cout << "当前行号: " << __LINE__ << endl; 9     cout << "编译日期: " << __DATE__ << endl;10     cout << "编译时间: " << __TIME__ << endl;11 12     return 0;13 }

       运行结果:

       技术分享

技巧三:使用assert断言宏确保某个条件不发生

  基本格式为 assert(表达式)。当表达式为真,语句不做任何事情,否则语句输出错误并终止程序执行,请看下面代码:

 1 #include <iostream> 2 #include <cassert>    // 要使用assert断言宏必须包含这个头文件 3   4 using namespace std; 5   6 int main() 7 { 8     int t=0; 9     cin >> t;10 11     assert (t !=0);12     cout << "t: " << t << endl;13  14     return 0;15 }

       assert在这里的作用是确保t不等于0。如果t=0,程序会弹出错误并停止运行。编译代码并运行,

       当输入为0时运行结果:

       技术分享

       当输入其他数字时运行结果:

       技术分享

       最后要强调的是,assert只是调试工具,它绝对不能代替逻辑检查参与到异常处理中。

第六篇:使用预处理器帮助调试