stl, string不仅是charString, 更是byteString
转载至:http://chzhou.blog.sohu.com/97459512.html
以前一直没有注意到STL中的string的length函数,但一直用它。天真的以为它会返回字符串的长度。这是因为我们在C中经常会用strlen去求一个字符串的长度,转到C++,看到std::string中有length,乖乖,万事大吉了。
我一直这样想当然的用这个函数没有出过问题。是我的运气呢,还是stl防备了这些可能出现的问题呢。
而我最近发现,std::string的能力比我想像的要更强大。
这两天对google刚刚开源的protocol buffer(简称PB)产生了兴趣。这个工具是用来将结构化的数据封装成二进制流。并提供反方向的工作。也就是说,它是一个能够完成序列化/反序列化工作的工具。当然,它的功能不限于此。
PB完成了对整数,实数,字符串的封装,完成了对结构体的封装,一切都完美无缺。它还完成了对Bytes的封装,太好了,这正是我想要的。我是想用它来封装一个地理数据(图层),里面有纯二进制数据。
等等,等我定义好我的协议文件。是的,我定义好了,帮我翻译成C++吧。
好的,翻译好了。
嗯,让我看看。一切都很好。但是,等一下,为什么把我的Bytes翻译成了std::string?
该死的google,难道不知道string是用来存字符串的吗,二进制中有零的话,不就被截断了,那我的数据还能有救?
嗯,是的,仔细看了std::string::assign和length的实现,是的。很好,std::string的能力超出了我的想像。二进制数据没有被截断,一切的所有都被完整地保留下来了。
这很让人兴奋,让我来试一试。编几行代码来测试一下std::string::assign和std::string::length.
编好了,贴在这里。
// TestStringLength.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h" //这个需要解释,但是算了。呵呵。
#include <string>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int pIntBuf[] = {1, 2, 3, 0, 0, 0, 5, 2, 3, 20, 50};
char pStrBuf[1000];
pStrBuf[500] = '\0';//在随机的缓冲区中加入一个结束符
std::string strBuf = "I Love you.";
char s = ' ';//是的,只是一个空格
//强制性的硬拷贝可能会越界,但是仍要试试,这当然是不会截断数据了。
std::string str1, str2, str3;
str1.resize(sizeof(pIntBuf)+1, '\0');
str2.resize(sizeof(pStrBuf)+1, '\0');
str3.resize(strlen(strBuf.c_str()) +1, '\0');
memcpy((void*)str1.c_str(), pIntBuf, sizeof(pIntBuf)+1);
memcpy((void*)str2.c_str(), pStrBuf, sizeof(pStrBuf)+1);
memcpy((void*)str3.c_str(), strBuf.c_str(), strlen(strBuf.c_str()) +1);
std::cout<<str1.length()<<s<<str2.length()<<s<<str3.length()<<endl;
std::cout<<strlen(str1.c_str())<<s<<strlen(str2.c_str())<<s<<strlen(str3.c_str())<<endl;
std::cout<<endl;
//试试string::assigh(string&), 发现也没有丢失数据。
std::string str4, str5, str6;
str4.assign(str1);
str5.assign(str2);
str6.assign(str3);
std::cout<<str4.length()<<s<<str5.length()<<s<<str6.length()<<endl;
std::cout<<strlen(str4.c_str())<<s<<strlen(str5.c_str())<<s<<strlen(str6.c_str())<<endl;
std::cout<<endl;
//用string::assign(char*), 数据丢失了。 当然, 因为char*根本不知道真实的长度,只能找到第一个'\0'
std::string str7, str8, str9;
str7.assign(str1.c_str());
str8.assign(str2.c_str());
str9.assign(str3.c_str());
std::cout<<str7.length()<<s<<str8.length()<<s<<str9.length()<<endl;
std::cout<<strlen(str7.c_str())<<s<<strlen(str8.c_str())<<s<<strlen(str9.c_str())<<endl;
std::cout<<endl;
return 0;
}
结果有了,也贴出来:
--------------------------------
45 1001 12
1 500 11
45 1001 12
1 500 11
1 500 11
1 500 11
--------------------------------
略作分析:
分三组,每组两行结果,第一行是真实的长度,第二行是结束符'\0'之前的长度。
第一组,前两行是硬拷贝的结果,很好,没有截断我的数据。
第二组,string::assigh(string& S),也是完全拷贝,没有丢掉S中结束符之后的部分。
由此可见,string并不是专为字符串而设计的,而是缓冲区,把它当成字符串使用的话,反而要多一份小心。
第三组,由于char*类型丢失了缓冲区的长度性息,理所当然的要丢失数据了。
好吧。这个std::string的认识又深了一层。
结论是,string不仅是charString,更是byteString。
继续研究这个google::protocolbuffer。