CArchive::ReadString()とCArchive::WriteString()を使って文字列を読み書きしようとしたら文字化けしてハマったのでメモ。
以下のようなコードを書いたら、読み込み時に文字化けした。
void Serialize(CArchive &ar){
TCHAR path[MAX_PATH+1];
if(ar.IsStoring()){ // save
(中略)
ar.WriteString(path);
} else { // load
ar. ReadString(path, MAX_PATH);
}
原因はCArchive::WriteString()とCArchive::ReadString()の設計が非対称なため。ReadString()が'\0'までを読み込む関数だと思ったら大間違いで、こいつは'\n'までを読み込む関数。一方、WriteString()は’\0'の直前までを書き出す関数で、書き終わっても'\n'を付与しない。つまり、読み込みと書き込みで区切り文字が異なるのだ。そのため上記プログラムだとMAX_PATHまで読んでしまい、本来読むべき領域からオーバーランし文字化けしたデータとなる。
また、この仕様だと'\n'を含む文字列をWriteStringした場合、ReadStringの処理がかなり困ったことになりそうである。すなわち、改行がある場合は意図したよりも短い文字列が読み込まれてしまう。
なんというか、getstr()との互換性をもたせようとした?せいで最悪な事態になっている気がする。この仕様を審査承認した人たちの罪は大きいと思う。