Visual Studio条件断点:你真的会用吗?

本文介绍如何在VisualStudio中设置复杂的条件断点,通过实例演示如何利用QuickWatch工具生成条件表达式,确保程序仅在特定条件下中断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用Visual Studio进行debug的时候,设置断点是最常用的、不可或缺的技术之一。大多数情况下,我们只需要在Visual Studio里按F9键,设置一个普通断点即可。但是对于一些特殊情况,这一点可能就不太管用。典型的情况就是在次数很多的循环里,我们需要在特定条件下,程序中断执行。这时候要使用条件断点。条件断点的关键是设置一个表达式,当表达式条件为真时,中断执行。一般的情况下,这个表达式很好写,如对于整型变量i,只需写 i == 10,即可在i的值为10的时候中断执行。

 

条件断点设置 

但是对于一些复杂一点的代码,可能就没有那么简单了。下面是一段测试代码(仅供测试条件断点之用,会有内存泄漏等问题),如果要在有注释的代码行上设置条件断点,使注释里描述的条件满足时中断执行,那么这些条件表达式该如何写呢?你可以先自己试着先想一下,然后再看后面的答案。 

[c-sharp]  view plain copy
  1. // TestAtlVariant.cpp : Defines the entry point for the console application.  
  2. //  
  3.  
  4. #include "stdafx.h"  
  5. #include <vector>  
  6. #include <map>  
  7. #include <string>  
  8. #include <iostream>  
  9. #include "atlsafe.h"  
  10.   
  11. using namespace std;  
  12.   
  13. struct point  
  14. {  
  15. public:  
  16.     point(int i, int j) { this->i = i; this->j = j; }  
  17.   
  18.     int i;  
  19.     int j;  
  20. };  
  21.   
  22. // dummmy functions for test  
  23. void func(int i) {}  
  24. void func(string str) {}  
  25. void func(CComBSTR bstr) {}  
  26. void func(point * p) {}  
  27.   
  28. int _tmain(int argc, _TCHAR* argv[])  
  29. {  
  30.     int iArray[3];  
  31.     string strArray[3];  
  32.     CComBSTR bstrArray[3];  
  33.     vector<string> strVec;  
  34.     vector<CComBSTR> bstrVec;  
  35.     vector<point*> pointVec;  
  36.     map<stringstring> strMap;  
  37.     map<CComBSTR, CComBSTR> bstrMap;  
  38.     map<string, point*>  pointMap;  
  39.   
  40.     iArray[0] = 1;  
  41.     iArray[1] = 2;  
  42.     iArray[2] = 3;  
  43.   
  44.     strArray[0] = string("a1");  
  45.     strArray[1] = string("b2");  
  46.     strArray[2] = string("c3");  
  47.   
  48.     bstrArray[0] = CComBSTR("a1");  
  49.     bstrArray[1] = CComBSTR("b2");  
  50.     bstrArray[2] = CComBSTR("c3");  
  51.   
  52.     strVec.push_back("a1");  
  53.     strVec.push_back("b2");  
  54.     strVec.push_back("c3");  
  55.   
  56.     bstrVec.push_back("a1");  
  57.     bstrVec.push_back("b2");  
  58.     bstrVec.push_back("c3");  
  59.   
  60.     pointVec.push_back(new point(1,1));  
  61.     pointVec.push_back(new point(2,2));  
  62.     pointVec.push_back(new point(3,3));  
  63.   
  64.     strMap.insert(pair<stringstring>("a1""a1"));  
  65.     strMap.insert(pair<stringstring>("b2""b2"));  
  66.     strMap.insert(pair<stringstring>("c3""c3"));  
  67.   
  68.     bstrMap.insert(pair<CComBSTR, CComBSTR>("a1""a1"));  
  69.     bstrMap.insert(pair<CComBSTR, CComBSTR>("b2""b2"));  
  70.     bstrMap.insert(pair<CComBSTR, CComBSTR>("c3""c3"));  
  71.   
  72.     pointMap.insert(pair<string, point*>("a1"new point(1,1)));  
  73.     pointMap.insert(pair<string, point*>("b2"new point(2,2)));  
  74.     pointMap.insert(pair<string, point*>("c3"new point(3,3)));  
  75.   
  76.     for(int i=0; i<3; i++)  
  77.     {  
  78.         func(iArray[i]); // 1. iArray[i] == 2  
  79.     }  
  80.   
  81.     for(int i=0; i<3; i++)  
  82.     {  
  83.         func(strArray[i]); // 2. strArray[i] == "b2"  
  84.     }  
  85.   
  86.     for(int i=0; i<3; i++)  
  87.     {  
  88.         func(bstrArray[i]); // 3. bstrArray[i] == "b2"  
  89.     }  
  90.   
  91.     for(vector<string>::iterator strIter = strVec.begin(); strIter != strVec.end(); strIter++)  
  92.     {  
  93.         func(*strIter); // 4. *strIter == "b2"  
  94.     }  
  95.   
  96.     for(vector<CComBSTR>::iterator bstrIter = bstrVec.begin(); bstrIter != bstrVec.end(); bstrIter++)  
  97.     {  
  98.         func(*bstrIter); // 5. *bstrIter == "b2"  
  99.     }  
  100.   
  101.     for(vector<point*>::iterator pointVecIter = pointVec.begin(); pointVecIter != pointVec.end(); pointVecIter++)  
  102.     {  
  103.         func(*pointVecIter); // 6. *pointerIter == 2  
  104.     }  
  105.   
  106.     for(map<stringstring>::iterator strMapIter = strMap.begin(); strMapIter != strMap.end(); strMapIter++)  
  107.     {  
  108.         func(strMapIter->first); // 7. strMapIter->first == "b2"  
  109.         func(strMapIter->second); // 8. strMapIter->second == "b2"  
  110.     }  
  111.   
  112.     for(map<CComBSTR, CComBSTR>::iterator bstrMapIter = bstrMap.begin(); bstrMapIter != bstrMap.end(); bstrMapIter++)  
  113.     {  
  114.         func(bstrMapIter->first); // 9. bstrMapIter->first == "b2"  
  115.         func(bstrMapIter->second); // 10. bstrMapIter->second == "b2"  
  116.     }  
  117.   
  118.     for(map<string, point*>::iterator pointMapIter = pointMap.begin(); pointMapIter != pointMap.end(); pointMapIter++)  
  119.     {  
  120.         func(pointMapIter->first); // 11. pointMapIter->first == "b2"  
  121.         func(pointMapIter->second); // 12. pointMapIter->second->i == 2  
  122.     }  
  123.   
  124.     return 0;  
  125. }  

 

 

 

 

下面是在以上有注释的代码行上设置条件断点所需要的条件表达式:

1.       iArray[i] == 2

2.       (strArray[i])._Bx._Buf[0x00000000] == 'b' && (strArray[i])._Bx._Buf[0x00000001] == '2'

3.       *((bstrArray[i]).m_str+0) == 'b' && *((bstrArray[i]).m_str+1) == '2'

4.       (*(strIter)._Myptr)._Bx._Buf[0x00000000] == 'b' && (*(strIter)._Myptr)._Bx._Buf[0x00000001] == '2'

5.       *((*(bstrIter)._Myptr).m_str+0) == 'b' && *((*(bstrIter)._Myptr).m_str+1) == '2'

6.       (*(*(pointVecIter)._Myptr)).i == 2

7.       (((strMapIter)._Ptr->_Myval).first)._Bx._Buf[0x00000000] == 'b' && (((strMapIter)._Ptr->_Myval).first)._Bx._Buf[0x00000001] == '2'

8.       (((strMapIter)._Ptr->_Myval).second)._Bx._Buf[0x00000000] == 'b' && (((strMapIter)._Ptr->_Myval).second)._Bx._Buf[0x00000001] == '2'

9.       *((((bstrMapIter)._Ptr->_Myval).first).m_str+0) == 'b' && *((((bstrMapIter)._Ptr->_Myval).first).m_str+1) == '2'

10.    *((((bstrMapIter)._Ptr->_Myval).second).m_str+0) == 'b' && *((((bstrMapIter)._Ptr->_Myval).second).m_str+1) == '2'

11.    (((pointMapIter)._Ptr->_Myval).first)._Bx._Buf[0x00000000] == 'b' && (((pointMapIter)._Ptr->_Myval).first)._Bx._Buf[0x00000001] == '2'

12.    (*(((pointMapIter)._Ptr->_Myval).second)).i == 2

 

值得注意的是,如果直接使用注释里的表达式作为条件断点的条件表达式,是不行的。Visual Studio会给出错误提示,无法设置条件断点。

这些表达式看上去很复杂,手工很难直接写出来。秘诀在于,Visual Studio的Quick Watch可以帮我们写这些表达式。以最后一个断点为例,对pointMapIter显示Quick Watch窗口,在Value里找到我们要取的值,在Expression里就会显示相应的表达式。如图所示:

 

 QuickWatch窗口

我们可以把这里显示的表达式拷贝出来,必要时略加修改,再加上比较条件,就可以作为条件断点表达式来使用。以上面的第2条为例,由于不能直接判断字符串相等,采用的方法是取出字符逐个比较。这种从QuickWatch窗口获取复杂的条件表达式的方法不仅对C++适用,对于其他编程语言,如C#,也是适用的。

最后,为了验证上述条件断点确实有效,把程序在调试器里执行一遍,每当命中一个断点时,就继续执行,直到最后一个断点命中时,再看断点窗口,应该每个断点都命中一次。如下图的Hit Count一列所示:

断点窗口

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值