ファイルサイズでバッファーを確保し
そこに読み込むだけのプログラムなのですが
関数を抜けるとき(例ではwmain)に
デバッグエラーになります。
buf( len + 1 )だとエラーにならないのですが
+1する必要がないように思えて不思議です。
どなたかわかる方がいれば説明してもらえないでしょうか。
環境:
・Windows XP SP2
・VC++ 2005 SP1
エラー内容:
-------------------------------------------------
Debug Error!
Program: e:\study\c++\heaptest\debug\HeapTest.exe
HEAP CORRUPTION DETECTED: after Normal block (#74) at 0x004D0068.
CRT detected that the application wrote to memory after end of heap buffer.
(Press Retry to debug the application)
-------------------------------------------------
サンプルコード:
-------------------------------------------------
#include <fstream>
#include <vector>
int wmain( int argc, wchar_t* argv[] )
{
if( argc < 2 )
return 1;
std::wifstream ifs( argv[ 1 ], std::ios::binary );
if( !ifs )
{
return 1;
}
ifs.seekg( 0, std::ios::end );
size_t len = ifs.tellg();
std::vector<unsigned char> buf( len );
ifs.seekg( 0, std::ios::beg );
for( size_t i = 0; i < buf.size(); i++ )
{
ifs.read( reinterpret_cast<wchar_t*>( &buf[ i ] ), 1 );
}
ifs.close();
return 0;
}
-------------------------------------------------
あたりまえなような気が駿河
たとえば len=100 であったとして i=99 を処理する際には &buf[99] が read() に渡されることになる
wifstream.read は wchar_t に相当するサイズ分を書き込むわけで、
その結果 &buf[99] だけでなくその後ろも破壊される
wifstream を使う以上は vector<wchar_t> としないとバグっちゃうぞ
wifstream で sjis なファイルを読むのは意味がないような気がするけどさ
なるほど。
1バイトだけ読んで書き込んでくれるわけじゃないんですね。
ちょっと勘違いしていました。
ありがとうございます。
でも、書き込みの時じゃなくて、関数を抜けるときにエラーになるのは何でなのでしょうか?
あと、unsigned shortの変数に2バイトreadした場合(例えばbitmapの先頭'B''M')、2バイト読み込めない('B'しか読めてない)のですが、これもなぜかご存知でしたら教えていただけないでしょうか。
> 書き込みの時じゃなくて、関数を抜けるときにエラーになるのは何でなのでしょうか?
そもそも C/C++ は1バイト書き込みごとにエラーチェックしたりする親切言語ではない
だから書き込みそのものでは一切エラーチェックされない
関数を抜けるときに vector::~vector が呼ばれるわけだが、
Debug 版はこれがメモリ破壊チェックしているのでエラーが出る
# Release 版はチェックしないので何も言わずに吹っ飛ぶ可能性が大
> 1バイトだけ読んで書き込んでくれるわけじゃないんですね。
> 2バイトreadした場合
「1バイト」という文言をどういう意味に使っているのかな?
wifstream にどのような挙動を期待しているのかな?
wifstream は実質「使えない」関数なので注意しないとだめだぞ
wifstream は以下のような挙動を行うので注意が必要だ
ファイルから 'B' を読む→wchar_t に変換する→wchar_t の L'B' を wchar_t バッファにストアする
ファイルから 'M' を読む→wchar_t に変換する→wchar_t の L'M' を wchar_t バッファにストアする
ファイルから SJIS の第一バイトを読む→wchar_t に変換(失敗)する→
第一バイトのコード(=漢字になっていない)を wchar_t バッファにストアする
ファイルから SJIS の第二バイトを読む→wchar_t に変換(失敗)する→
第二バイトのコード(=漢字になっていない)を wchar_t バッファにストアする
意味がない、と先にコメントした理由はこういうことなわけだ
> wifstream は以下のような挙動を行うので注意が必要だ
> ファイルから 'B' を読む→wchar_t に変換する→wchar_t の L'B' を wchar_t バッファにストアする
> ファイルから 'M' を読む→wchar_t に変換する→wchar_t の L'M' を wchar_t バッファにストアする
'B'(0x42)と'M'(0x4d)を読んで、0x4d42をwchar_tバッファにストアする挙動を期待していました。
read(_Elem *_Str, streamsize _Count)は、_Countバイトまでsizeof(_Elem)バイトずつ読み込む処理を繰り返すものと思い込んでいました。
streamsizeとバイト数あたりの認識があやふやだったように思います。
なんとなく理解できた気がしますが、もう少し試してみます。
大変参考になりました。
ありがとうございました。