3

非Unicodeの16ビットワードをファイルに書き込み、後で読み戻したい。少しのバイト操作で、とを使用してモードでこれを実行できることを知っていcharます。16ビットワードを直接使用するにはどうすればよいですか?fstream::read()fstream::write()

たとえば、次のことができるはずです。

 basic_ofstream<uint16_t> aw;
 aw.open("test.bin", ios::binary);
 uint16_t c[] = {0x55aa, 0x1188};
 aw.write(c, 2);
 aw.close();

 basic_ifstream<uint16_t> ax;
 ax.open("test.bin", ios::binary);
 uint16_t ui[2];
 ax.read(ui, 2);
 ax.close();
 cout << endl << hex << unsigned(ui[0]) << " " << unsigned(ui[1]) << endl;

gcc 4.4出力:

d 0

Vc ++ 10出力:

CCCC CCCC

私もstd::basic_filebuf<uint16_t>直接使用してみましたが、同じ結果が得られました。なんで?

4

4 に答える 4

6

ストリームをインスタンス化して読み取りを行うことができたのには、実際に驚いています。結果は、実装で定義されている可能性があります(つまり、コンパイラのドキュメントで説明されている動作を見つける可能性があります)が、指定されていない可能性があります(完全に未定義ではありませんが)。charストリームクラスは、他のタイプのインスタンス化をサポートする必要はないと思いますwchar_t。つまり、ユーザーが少なくともいくつかのファセットを提供する必要はありません。

標準ストリームクラスは文字型のテンプレートですが、サポートされていない型をインスタンス化するのは簡単ではありません。最低限、std::codecvt<int16_t, char, std::mbstate_t>バイト単位の外部表現と内部表現の間で変換する適切なファセットを実装する必要があります。その外観から、あなたが試した2つのシステムは、デフォルトの実装に対して異なる選択をしました。

std::codecvt<internT, externT, stateT>文字の外部表現と文字の内部表現の間で変換するために使用されるファセットです。charストリームは、バイトを外部タイプとして表すと見なされるサポートにのみ必要ですexternT。内部文字タイプinternTは任意の整数タイプにすることができますが、変換はコード変換ファセットを実装することによって定義する必要があります。私が正しく思い出せば、ストリームは状態タイプstateTがであると想定することもできますstd::mbstate_t(このタイプに定義されたインターフェースがないため、実際には多少問題があります!)。

文字タイプのI/Oストリームの作成に専念しているのでない限り、uint16_tバイトを使用してバイトを読み取りstd::ifstream、それらを文字タイプに変換することをお勧めします。同様に文字を書くために。フォーマットもサポートするI/Oストリームを実際に作成するには、他の多くのファセット(たとえば、std::ctype<uint16_t>)も必要であり、これらすべてに加えて、からインスタンス化できるいくつかを含むようにstd::num_punct<uint16_t>を構築する必要があります。std::locale標準ライブラリの実装(例、std::num_get<uint16_t>およびstd::num_put<uint16_t>;それらのイテレータタイプはデフォルトで適切であると思います)。

于 2012-10-09T19:30:09.807 に答える
2

コードを試してみると、ファイルは書き込まれていますが、中には何もありません。閉じた後のサイズは0です。そのファイルから読み取る場合、何も読み取ることができません。出力に表示されるのは、初期化されていないガベージです。

デフォルトのcharでofstream/ifstreamを使用する以外に、実際に何かを書き込むかどうかを示さないため、必ずしもメソッドread()に依存する必要はありません。write()詳細については、 http://en.cppreference.com/w/cpp/io/basic_ostream/writeを参照してください。特にこれは興味深いです:

この関数はフォーマットされていない出力関数です。sentry型のオブジェクトを作成することで実行を開始します。このオブジェクトは、必要に応じてtie()された出力バッファーをフラッシュし、ストリームエラーをチェックします。構築後、歩哨オブジェクトがfalseを返す場合、関数は出力を試行せずに戻ります。

これが、charなど以外のタイプで動作するように設計されていないように見えるため、ファイルに出力が書き込まれない理由である可能性があります。

更新:書き込み/読み取りが成功するかどうかを確認するには、何かがうまくいかなかったことをすでに示しているはずの失敗ビットまたは不良ビットを確認します。

cout << aw.fail() << aw.bad() << "\n";
cout << ax.fail() << ax.bad() << "\n";

両方ともtrueに設定されているので、本当の質問は次のようになっているはずです。なぜ呼び出しが write()失敗したのですか?

于 2012-10-09T19:48:30.403 に答える
1

私は読むことをお勧めします:http ://www.cplusplus.com/articles/DzywvCM9/

切れ端:

「これらのタイプの問題は、サイズが明確に定義されていないことです。intはあるマシンでは8バイトですが、別のマシンでは4バイトしかない場合があります。一貫しているのはchar...だけです。これは常に1バイトであることが保証されています。 「」

u16 ReadU16(istream& file)
{
  u16 val;
  u8 bytes[2];

  file.read( (char*)bytes, 2 );  // read 2 bytes from the file
  val = bytes[0] | (bytes[1] << 8);  // construct the 16-bit value from those bytes

  return val;
}

void WriteU16(ostream& file, u16 val)
{
  u8 bytes[2];

  // extract the individual bytes from our value
  bytes[0] = (val) & 0xFF;  // low byte
  bytes[1] = (val >> 8) & 0xFF;  // high byte

  // write those bytes to the file
  file.write( (char*)bytes, 2 );
}

保証された#ビットタイプを定義するために、「typedef」キーワードも更新することをお勧めします。少し学習曲線がありますが、BoostおよびC99コンパイラは保証されたサイズタイプも定義します。X ++ 0xについてはよくわかりませんが、移植するには新しすぎます。

于 2012-10-09T19:27:54.947 に答える
1

char特殊化とreinterpret_castを使用できます。

basic_ofstream<char> aw;
...
aw.write( reinterpret_cast<const char*>(i16buf), n2write*sizeof(int16_t) );

basic_ifstream<char> ax;
...
ax.read( reinterpret_cast<char*>(i16buf), n2read*sizeof(int16_t) );

「sizeof(int16_t)」は、sizeof(int16_t)== 1のエッジケース(DSPプロセッサなど)用です。

もちろん、特定のバイト順序で読み取り/書き込みを行う必要がある場合は、エンディアン変換関数が必要です。エンディアンを決定する標準のコンパイル時の方法はないことに注意してください。

于 2012-10-09T19:49:26.247 に答える