使用istringstream处理可变长度的内存块

时间:2010-02-19 13:25:46

标签: c++ string stl stringstream

我正在尝试使用istringstream从某些内存中重新创建编码的wstring。记忆的布局如下:

  1. 1个字节,表示wstring编码的开始。任意地这是'!'。
  2. n个字节,用于以文本格式存储字符串的字符长度,例如, 0x31,0x32,0x33将是“123”,即123个字符的字符串
  3. 1个字节分隔符(空格字符)
  4. n个字节,它们是构成字符串的wchars,其中wchar_t是每个2字节。
  5. 例如,字节序列:

    21 36 20 66 00 6f 00 6f 00

    是“!6 f.o.o.” (用点表示char 0)

    所有我得到的是一个char *指针(让我们称之为pData)到内存块的开头,其中包含这些编码数据。使用数据重建wstring(“foo”)的“最佳”方法是什么,并且还将指针移动到编码数据末尾的下一个字节?

    我正在玩istringstream以允许我使用前缀字节,字符串的长度和分隔符。之后,我可以计算要读取的字节数,并使用流的read()函数插入到适当调整大小的wstring中。 问题是,我如何首先将这个内存放入istringstream?可以首先尝试构造一个字符串,然后将其传递给istringstream,例如

    std::string s((const char*)pData);
    

    但这不起作用,因为字符串在第一个空字节处被截断。或者,我可以使用字符串的其他构造函数来显式声明要使用的字节数:

    std::string s((const char*)pData, len);
    

    哪个有效,但前提是我事先知道len是什么。鉴于数据长度可变,这很棘手。

    这似乎是一个真正可以解决的问题。我的新秀状态是否有字符串和流意味着我忽略了一个简单的解决方案?或者我是用整个字符串方法咆哮错误的树?

4 个答案:

答案 0 :(得分:0)

尝试设置字符串流的rdbuf

char* buffer = something;
std::stringbuf *pbuf;
std::stringstream ss;

std::pbuf=ss.rdbuf();
std::pbuf->sputn(buffer, bufferlength);
// use your ss

编辑:我看到这个解决方案会遇到与你的字符串(char *,len)类似的问题。你能告诉我们你的缓冲对象的更多信息吗?如果您不知道长度,并且它不是空终止,那么处理将非常困难。

答案 1 :(得分:0)

是否可以修改编码长度的方式,并将其设为固定大小?

unsigned long size = 6; // known string length
char* buffer = new char[1 + sizeof(unsigned long) + 1 + size];
buffer[0] = '!';
memcpy(buffer+1, &size, sizeof(unsigned long));

缓冲区应保存起始指示符(1个字节),实际大小(无符号长整数),分隔符(1个字节)和文本本身(size)。
这样,您可以轻松获得“非常”的大小,然后将指针设置为超出开销,然后在字符串构造函数中使用len变量。
unsigned long len;
memcpy(&len, pData+1, sizeof(unsigned long)); // +1 to avoid the start indicator
// len now contains 6
char* actualData = pData + 1 + sizeof(unsigned long) + 1;
std::string s(actualData, len);

这是低级别且容易出错:)(例如,如果您读取的任何内容未按预期方式编码,则len可能会变得非常大),但您可以避免动态读取字符串的长度

答案 2 :(得分:0)

这个订单似乎应该有效:

std::wstring make_string(char const *input) { 
    if (*input != '!')
       return "";
    char length = *++input;
    return std::wstring(++input, length);
}

困难的部分是处理大小的可变长度。没有指定长度的东西,很难猜测何时停止将数据视为指定字符串的长度。

至于移动指针,如果要在函数内部执行,则需要传递对指针的引用,否则只需将找到的大小添加到指针即可。

答案 3 :(得分:0)

在这里(ab)使用(已弃用但仍然标准的)std :: istrstream很诱人:

// Maximum size to read is 
// 1 for the exclamation mark
// Digits for the character count (digits10() + 1)
// 1 for the space
const std::streamsize max_size = 3 + std::numeric_limits<std::size_t>::digits10;

std::istrstream s(buf, max_size);

if (std::istream::traits_type::to_char_type(s.get()) != '!'){
    throw "missing exclamation";
}

std::size_t size;
s >> size;

if (std::istream::traits_type::to_char_type(s.get()) != ' '){
    throw "missing space";
}

std::wstring(reinterpret_cast<wchar_t*>(s.rdbuf()->str()), size/sizeof(wchar_t));