VS Debug的条件断点 (深入浅出判断string)

9 篇文章 1 订阅
4 篇文章 0 订阅

条件断点

运行环境:

  • Windows10
  • Visual Studio 2019
  • 编译器默认C++

Debug的条件断点的打开方式:断点右键-选择条件
在这里插入图片描述
使用这种方式可以减少用修改源码来断点。
条件断点是在断点处的约束触发条件,并且可以设置断点忽略次数,条件断点在多线程上也能使用,可以线程ID用来分离线程(只在指定的线程中断点)
在这里插入图片描述
断点优先级:线程>条件>忽略计数器
只有前面的条件满足了,忽略计数器才会自减。

比如说下面这段代码,其中设置了命中次数3,conditions是index==1,那么debug会在第三个1中断,再点击运行不出触发后面1的中断,第一个0不会触发忽略计数器–。
在这里插入图片描述
我觉得触发条件可以等价下面的:

// 条件
bool condition(){
	return (i == 3);
}

int count = 3;
while (count > 0){
	if(condition()){
  		count--;
	  	if(count == 0){
	    	...// breakpoint
	  	}
	}
}

条件断点要注意1

  • 不能有副作用,有副作用等于无效判断
  • 条件断点支持的函数:strlen, wcslen, strnlen, wcsnlen, strcmp, wcscmp, _stricmp, _wcsicmp, strncmp, wcsncmp, _strnicmp, _wcsnicmp, strchr, wcschr, strstr, wcsstr (某个网站上复制过来的,全不全不知道,但是看着够用)
  • 条件断点表达式能够直接访问private等受到限制的变量

判断字符串相等

错误案例

错误案例1

表达式为s == "abc"
在这里插入图片描述
得到:
在这里插入图片描述

错误案例2

看来条件断点不支持调用string== 重载,那么根据上面的注意事项第2点,改用strcmp来实现:
第1种:strcmp(s, "abc") == 0 VS中断报错
这个肯定是不行的,就算放到代码里面也会有错。
在这里插入图片描述
第2种:strcmp(s.c_str(), "abc") == 0 VS显示有副作用,看来这种也不行,我觉得副作用可以ban掉,但是不妥所以没往这个方向研究,如果有人研究ban掉副作用,可以一起讨论一下。
在这里插入图片描述

错误案例3

条件表达式:s.compare("abc")==0
在这里插入图片描述
看VS的中断没有报错提示还以为没有问题,一运行又崩了。
在这里插入图片描述

可执行写法

既然上面的方式都不行,那就去只能查一下究竟要用什么方法才能不修改源码实现我想要的效果。
根据VS debug中断报错信息不存在“std::basic_string<char,std::char_traits<char>,std::allocator<char>>”到“const char *“适当的转换函数 查了许多网站后,找不到这类问题的解决方法(确实有解决的,但是那个问题是07年提出的,不是同一个版本的VS,它的解决方法在VS上显示有副作用),大概就是说明往这个方向深入是无解。

更换搜索关键词 vsdebug condition breakpoint strcmp,最后在Stack Overflow上找到了解决方法2
(调试器中是不能直接判断字符串相等,采用的方法一般是逐字符判断,但是我不喜欢这样)

正确用法1

条件表达式 s.size() > 0 && strcmp(&s[0], "abc") == 0
说明:&s[0] 表示 char*(char),因为 [] 的优先级比& 高,因此s[0]得到char的变量,取地址符&可以得到变量的地址,因此等价于&s[0]可以获得非consts.c_str()
我推荐就用这个方法,可以不用考虑其他问题,在&&之前加s.size()>0就是避免s == ""的情况。
在这里插入图片描述

正确用法2

条件表达式

(s.size() < 16 && strcmp(s._Mypair._Myval2._Bx._Buf,"123456789012345") == 0) || (s.size() >= 16 && strcmp(s._Mypair._Myval2._Bx._Ptr,"1234567890123456") == 0)

三目运算符也是可以的,建议先IDE里面写,太长容易写错。

(s.size() < 16) ? (strcmp(s._Mypair._Myval2._Bx._Buf, "123456789012345") == 0): (strcmp(s._Mypair._Myval2._Bx._Ptr, "1234567890123456") == 0);

分析string

这个实现方法跟string内部实现有关系,虽然可以根据string.c_str()猜出来上面这个怎么写,但是发现这些对像_Compressed_pair这种STL类不了解,但是研究这个类不是debug的目的,这时候就该换个思路。

_Compressed_pair<_Alty, _Scary_val> _Mypair;
_NODISCARD _CONSTEXPR20_CONTAINER _Ret_z_ const _Elem* c_str() const noexcept {
    return _Mypair._Myval2._Myptr();
}

首先c_str()实现原理如上,由于条件断点的第三点条件断点表达式能够直接访问private等受到限制的变量,因此我可以直接现在VS调试的监视里面查看string的数据,可以查到如下:
在这里插入图片描述
结果论的话,我们可以直接查看原始格式,表达式s变成s,!,这样就可以忽略任何数据类型视图自定义项,看到变量的真实结构。在这里插入图片描述
这里需要说明std::string原始结构3,下面的数据运行环境我在开头有写,也许其他系统的参数就不是这样:

  • _Mypair._Myval2._Mysize:对应std::string.size(),初始0
  • _Mypair._Myval2._Myres:对应std::string.capacity(),初始15
  • _Mypair._Myval2._Bx._Buf:不是指针,它是std::string用于保存字符串的内部小缓冲区,是一种缓冲区优化(不实际在堆上分配string),可以看到缓冲区的大小为16。当字符串长度小于16时,内存就指向_Buf区域
  • _Mypair._Myval2._Bx._Ptr:是指向堆缓冲区的指针,只有当字符串长度大于等于16时,内存才指向_Ptr区域
  • _Mypair._Myval2._Bx_Buf_Ptr的并集

字符串默认最大空间大小就是15,这跟缓冲区有关系,但是为什么我说缓冲区大小为16,而不是15,这是因为字符串结尾是一定是’\0’,因此传入第16个字符时,会导致’\0’跑到下标16上面,超出capacity的15,接着触发1.5内存扩容。

综上所述,长度小于16用_Buf,否则_Ptr。

(s.size() < 16) ? (strcmp(s._Mypair._Myval2._Bx._Buf, "123456789012345") == 0): (strcmp(s._Mypair._Myval2._Bx._Ptr, "1234567890123456") == 0);

再深入就要看string的具体实现了,以及实现string的相关模板类原理,我找到一篇写得还可以的,找个时间再深入研究。
https://zhuanlan.zhihu.com/p/371669822

资料参考来源:


  1. https://baike.baidu.com/item/%E6%9D%A1%E4%BB%B6%E6%96%AD%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F/22799975?fr=aladdin ↩︎

  2. https://stackoverflow.com/questions/1740858/how-to-create-conditional-breakpoint-with-stdstring ↩︎

  3. https://stackoverflow.com/questions/17195667/stdstring-internal-buffer-corruption ↩︎

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值