转自 https://blog.csdn.net/qwang24/article/details/4087423
条件断点
在使用Visual Studio进行debug的时候,设置断点是最常用的、不可或缺的技术之一。大多数情况下,我们只需要在Visual Studio里按F9键,设置一个普通断点即可。但是对于一些特殊情况,这一点可能就不太管用。典型的情况就是在次数很多的循环里,我们需要在特定条件下,程序中断执行。这时候要使用条件断点。条件断点的关键是设置一个表达式,当表达式条件为真时,中断执行。一般的情况下,这个表达式很好写,如对于整型变量i,只需写 i == 10,即可在i的值为10的时候中断执行。
但是对于一些复杂一点的代码,可能就没有那么简单了。下面是一段测试代码(仅供测试条件断点之用,会有内存泄漏等问题),如果要在有注释的代码行上设置条件断点,使注释里描述的条件满足时中断执行,那么这些条件表达式该如何写呢?你可以先自己试着先想一下,然后再看后面的答案。
// TestAtlVariant.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <vector> #include <map> #include <string> #include <iostream> #include "atlsafe.h" using namespace std; struct point { public: point(int i, int j) { this->i = i; this->j = j; } int i; int j; }; // dummmy functions for test void func(int i) {} void func(string str) {} void func(CComBSTR bstr) {} void func(point * p) {} int _tmain(int argc, _TCHAR* argv[]) { int iArray[3]; string strArray[3]; CComBSTR bstrArray[3]; vector<string> strVec; vector<CComBSTR> bstrVec; vector<point*> pointVec; map<string, string> strMap; map<CComBSTR, CComBSTR> bstrMap; map<string, point*> pointMap; iArray[0] = 1; iArray[1] = 2; iArray[2] = 3; strArray[0] = string("a1"); strArray[1] = string("b2"); strArray[2] = string("c3"); bstrArray[0] = CComBSTR("a1"); bstrArray[1] = CComBSTR("b2"); bstrArray[2] = CComBSTR("c3"); strVec.push_back("a1"); strVec.push_back("b2"); strVec.push_back("c3"); bstrVec.push_back("a1"); bstrVec.push_back("b2"); bstrVec.push_back("c3"); pointVec.push_back(new point(1,1)); pointVec.push_back(new point(2,2)); pointVec.push_back(new point(3,3)); strMap.insert(pair<string, string>("a1", "a1")); strMap.insert(pair<string, string>("b2", "b2")); strMap.insert(pair<string, string>("c3", "c3")); bstrMap.insert(pair<CComBSTR, CComBSTR>("a1", "a1")); bstrMap.insert(pair<CComBSTR, CComBSTR>("b2", "b2")); bstrMap.insert(pair<CComBSTR, CComBSTR>("c3", "c3")); pointMap.insert(pair<string, point*>("a1", new point(1,1))); pointMap.insert(pair<string, point*>("b2", new point(2,2))); pointMap.insert(pair<string, point*>("c3", new point(3,3))); for(int i=0; i<3; i++) { func(iArray[i]); // 1. iArray[i] == 2 } for(int i=0; i<3; i++) { func(strArray[i]); // 2. strArray[i] == "b2" } for(int i=0; i<3; i++) { func(bstrArray[i]); // 3. bstrArray[i] == "b2" } for(vector<string>::iterator strIter = strVec.begin(); strIter != strVec.end(); strIter++) { func(*strIter); // 4. *strIter == "b2" } for(vector<CComBSTR>::iterator bstrIter = bstrVec.begin(); bstrIter != bstrVec.end(); bstrIter++) { func(*bstrIter); // 5. *bstrIter == "b2" } for(vector<point*>::iterator pointVecIter = pointVec.begin(); pointVecIter != pointVec.end(); pointVecIter++) { func(*pointVecIter); // 6. *pointerIter == 2 } for(map<string, string>::iterator strMapIter = strMap.begin(); strMapIter != strMap.end(); strMapIter++) { func(strMapIter->first); // 7. strMapIter->first == "b2" func(strMapIter->second); // 8. strMapIter->second == "b2" } for(map<CComBSTR, CComBSTR>::iterator bstrMapIter = bstrMap.begin(); bstrMapIter != bstrMap.end(); bstrMapIter++) { func(bstrMapIter->first); // 9. bstrMapIter->first == "b2" func(bstrMapIter->second); // 10. bstrMapIter->second == "b2" } for(map<string, point*>::iterator pointMapIter = pointMap.begin(); pointMapIter != pointMap.end(); pointMapIter++) { func(pointMapIter->first); // 11. pointMapIter->first == "b2" func(pointMapIter->second); // 12. pointMapIter->second->i == 2 } return 0; }
下面是在以上有注释的代码行上设置条件断点所需要的条件表达式:
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里就会显示相应的表达式。我们可以把这里显示的表达式拷贝出来,必要时略加修改,再加上比较条件,就可以作为条件断点表达式来使用。以上面的第2条为例,由于不能直接判断字符串相等,采用的方法是取出字符逐个比较。这种从QuickWatch窗口获取复杂的条件表达式的方法不仅对C++适用,对于其他编程语言,如C#,也是适用的。
示例如下:
code是std::string类型,断点条件设置为code.compare("300065")==0时会报错:"无法设置断点。此表达式有副作用,将不会对它进行计算"。 然后使用快速监视(Quick Watch)看code的值最终测试出好用的表达式为
((code)._Bx._Buf)[0]=='3'&&((code)._Bx._Buf)[3]=='0'&&((code)._Bx._Buf)[4]=='6'&&((code)._Bx._Buf)[5]=='5'
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