如何安全动态格式化字符串

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在C语言中,我们如果希望进行格式化进行输出,一般我们用 sprintf 来字符串。

例如:

char temp[100];

sprintf(temp, "%s", "HelloWorld" );

通常上面的操作应该没有任何问题。但是,在某些情况下,是有意想不到的结果产生。

比如:在进行出错信息进行输出时,我们采取如下写法:

char temp[64];

sprintf( temp, "Error at file %s , line %d , column %d , Message: %s", strFile, lineNumber, columnNumber, strMessage);

一般情况下,如果出错信息较少,上面程序没有任何问题,如果出错信息很长,上面的数据会越界,从而导致改写其他内存中的内容,引发一些你想象不到的错误。

这时,估计你的解决方案就是增大temp的空间,比如:temp[1000]。

没错,这样改正之后,造成上面出错的概率会较少很多,但是还没有完全解决此问题。

在用户如果提供比较多的出错信息时,还是有问题产生。

那么我们有没有办法来完全解决此问题呢????

在C++中,有个string类,可以用来动态存储字符串,它会根据当前字符串的长度来调整它的长度。

且string.begin() 相当于char*指针。

说到这,你是不是有一种冲动改写上面的程序?( I so ).

string strTemp;

strTemp.reserve(64); //优化string的内存分配策略

sprintf( strTemp.begin(), "Error at file %s , line %d , column %d , Message: %s", strFile, lineNumber, columnNumber, strMessage);

编译通过,^_^(窃喜) !

测试一下,在较短的出错消息(没有超过64)时,没有任何问题,但是在超过64之后,会进行出错!!!(是不是比上面的比较‘安全’? )

为什么上面会出错???string 不是动态进行扩展存储空间吗?

没错,如果超过64之后,string会进行动态分配空间,由于string一般确保它的存储空间连续性,所以它是重新分配一块足够大的空间,然后将数据copy过去,这个过程类似于realloc 来分配空间。这必然导致我们现在的string.begin()和以前的begin()所指向的地址不一样。

而我们sprintf指向的地址是以前的string.begin(),不是重新分配之后的空间,一般以前分配的空间会被释放,所以会导致程序出错。

哪我们还有没有别的办法来改善上面的问题???

MFC中的CString类有个成员函数Format就可以用来格式化字符串,并且可以动态扩展此字符串。

是不是很酷???

但是,对于我来说,凡是不在UI地方(即界面显示部分),尽量避免使用MFC中的内容,使得以后的移植比较方便(可能有点杞人忧天的感觉),嘿嘿!!

难道就没有别的解决方案???

毕竟格式化字符串是非常常见的事情,连C中都有一个特定的函数来完成(sprintf)。难道C++里面就没有解决方案吗?

记得在C++的IO输出流中,标准的cout,就可以用来格式化输出到屏幕。

如果是fstream就可以用于格式化输出到文件中。(说到这里,好像记得有个字符串流?)

赶快进行msdn搜索,呵呵,找到了这个家伙。

不再多说了,直接进行示例.

std::ostringstream strOut( ios_base::out);

strOut << "Error at file " << file

<< " line " << lineNumber << " column " << columnNumber << endl;

strOut << " Message:" << CErrorMsg(errorCode).getErrorMsg() << endl;

strOut << " UserMessage: " << errStr << endl;

然后我们可以把上面的字符串提取出来.

string strValue = strOut.str();

到了这一步,你应该知道如何来使用string类型的值了吧。

呵呵,终于将它进行解决了,并且解决的如此彻底( 嘘,不要告诉别人,告诉你一个秘密,以前碰到此问题,没有很好的进行解决过,只是适当的将temp的数组增大,即将出错的概率进行了降低!)。

什么??? 你无法编译???? 加入相关头文件不就可以了吗???不知道哪个头文件,那去msdn中查找啊。

什么你没有查到?耐心一点会有的(不过在比较隐蔽的地方)。

Use <sstream> to work with objects of type basic_string.

Use <strstream> work with char *, which are C strings

即:在上面中,我们只要加入下面一句就可以了:

#include <sstream>

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航