2

一部のメモリからistringstreamエンコードされたものを再作成するために使用しようとしています。wstringメモリは次のように配置されます。

  1. wstring エンコーディングの開始を示す 1 バイト。勝手にこれは「!」です。
  2. 文字列の文字長をテキスト形式で格納するための n バイト。たとえば、0x31、0x32、0x33 は「123」、つまり 123 文字の文字列になります。
  3. 1 バイト区切り (スペース文字)
  4. 文字列を構成する wchar である n バイト。wchar_t はそれぞれ 2 バイトです。

たとえば、バイト シーケンスは次のとおりです。

21 36 20 66 00 6f 00 6f 00

"!6 foo" です (ドットを使用して char 0 を表します)

私が持っているのは、pDataこのエンコードされたデータを含むメモリブロックの先頭への char* ポインター (と呼びましょう) だけです。データを消費して wstring ("foo") を再構築し、ポインタをエンコードされたデータの終わりを過ぎた次のバイトに移動する「最良の」方法は何ですか?

istringstream を使用して、プレフィックス バイト、文字列の長さ、および区切り文字を消費できるようにしていました。その後、読み取るバイト数を計算し、ストリームのread()関数を使用して、適切にサイズ変更された wstring に挿入できます。問題は、そもそもこのメモリを istringstream に入れるにはどうすればよいかということです。最初に文字列を作成してから、それを istringstream に渡すことができます。

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

ただし、文字列が最初の null バイトで切り捨てられるため、これは機能しません。または、文字列の他のコンストラクターを使用して、使用するバイト数を明示的に指定することもできます。

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

lenこれは機能しますが、事前に何があるかを知っている場合に限ります。データが可変長であることを考えると、これは注意が必要です。

これは本当に解決可能な問題のようです。ストリングスとストリームの新人ステータスは、簡単な解決策を見落としていることを意味しますか? それとも、文字列全体のアプローチで間違ったツリーを吠えていますか?

4

4 に答える 4

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バイト)、実際のサイズ(unsigned longのサイズ)、区切り文字(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がかなり大きくなる可能性があります)が、文字列の長さを動的に読み取ることは避けます。

于 2010-02-19T14:24:54.723 に答える
0

この順序で何かがうまくいくようです:

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

難しい部分は、サイズの可変長を扱うことです。長さを指定するものがなければ、文字列の長さを指定するものとしてデータを扱うのをいつ停止するかを推測するのは困難です。

ポインタの移動に関しては、関数内で行う場合はポインタへの参照を渡す必要がありますが、それ以外の場合は、取得したポインタに見つけたサイズを追加するだけです。

于 2010-02-19T14:42:45.043 に答える
0

stringstream のrdbufを設定してみてください:

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

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

編集: このソリューションには、string(char*, len) の状況と同様の問題があることがわかります。バッファ オブジェクトについて詳しく教えてください。長さが不明で、null で終了していない場合、処理が非常に難しくなります。

于 2010-02-19T13:41:03.343 に答える
0

ここで(非推奨ですが標準の) 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));
于 2010-02-19T14:52:07.647 に答える