CSDN博客

img wu4long

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

发表于2004/9/14 13:03:00  948人阅读

在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>

0 0

相关博文

我的热门文章

img
取 消
img