他小的有

程序闪退的罪魁祸首竟然是格式化字符串

最近公司在开发一个项目,开发完成之后呢,程序偶尔有闪退的现象,不是很频繁,有时候一天出现一次,有时候一个小时出现一次,最严重的时候几分钟出现一次,简单来说就是看运气,这种概率性事件最麻烦之处在于,你想查的时候没有发生,以为它稳定时又崩溃了,总之让你觉得很苦恼,更糟糕的是你在本机运行一点事都没有,到了客户那里麻烦不断。

当然像这样的问题有经验有程序都没想到内存非法访问,亦或多线程冲突。知道了问题所在就好查了吗,事件好像未必如此,毕竟程序有点庞大,想要查每一句代码变得比较繁琐,更何况有时候程序由于是多人开发的,还不写注释什么的,看起来就更头疼。

像这样的情况单步调试一般不太可能,公司的这个项目中好在线程比较少,可以在线程某些认为高敏感的地方加了记录到文件,比如在某些地方LOG到文件,然后在程序退出的时候查看日志里的文件看执行到哪一个步骤,再通过不断在缩小范围或是不是每次闪退之后都发生了同样的前面日志,如果每次都在不断缩小的地方闪退的,意味首我们跟下来是对的,查了好久,终于发现问题竟然出现在这里(将double转string):

//double->string
string CConvert::ToString(double d, const char *pszFormat)
{
	char szTempBuf[128] = {0};
	sprintf(szTempBuf, pszFormat, d);
	return string(szTempBuf);
}

当然转换的方式有多种,这个比较常用,而且不少博客在举例出的好几种中自然也包含这种。

咋一看似乎没有什么问题,确实也没有看出有什么问题,但是却忽略了一个问题是当double变量d没有被初始化的时候,这个时候就会出现的问题是格式化的结果如果超出128,最终将导致闪退,打开float.h一看可以看到以下定义。

#define DBL_MAX         1.7976931348623158e+308 /* max value */
...
#define DBL_MIN         2.2250738585072014e-308 /* min positive value */

意味着如果将double转成字符串,最终可以达到300多个字符,虽然说一般情况下这种事情是不会发生的,但是如果如果double变量没有被初始化时,亦或者进了其它条件语句而使用double变量没有被初始化,就很有可能发了这样的情况,而且是随机性事件,如果你坚持使用这样的方法来格式化的话最好将szTempBuf大小调至512(我一般喜欢2的某次方),使用其它方式或者其它比较成熟的库也是不错的选择。

虽然很多时候编译器也会推荐我们使用更安全的版本sprintf_s(似乎也防止不了错误,以后再深究),但是真正关心的人有几个呢,甚至觉得麻烦和碍眼(就像我),多少人能懂前人的用心良苦。

程序闪退的情况很多种,我这里只是写出了我之前程序遇到的一种,未必能对你有用,但是这种情况确实存在,而且很普遍,特别是使用这种方式格式化的。

在此记下,希望大家不要犯类似的错误。

本站部分资源收集于网络,纯个人收藏,无商业用途,如有侵权请及时告知!

2
分享到:

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址