2001-11-07 [長年日記]
λ. wstring
mbとwcの変換部分がイケてない気がする。
- NULを含む文字列を正しく扱えない
-
こっちは微妙なんで後でちゃんと調べようと思うけど、結論から書くと、変換時にはterminating NULを含めて変換した上で、変換結果のterminating NULをRubyから隠すべきだと思う。どっちでも同じように思えるかもしれないけど、statefulなエンコーディングを扱う際に差が出る。たとえば、mbがISO-2022-JPだとすると「ほげほげ」という文字列は「ESC $ B 0x24 0x5b 0x24 0x32 0x24 0x5b 0x24 0x32 ESC ( B」で表され、Cで扱う際の対応関係は次のようになる。
mb ESC $ B 0x24 0x5b 0x24 0x32 0x24 0x5b 0x24 0x32 ESC ( B NUL wc ほ げ ほ げ NUL
前者は特に問題があるわけでもなさそうなので、このままで行きたいと思います。<br><br>後者は修正しましたが、問題なのは引数が少ないほうのmbs_to_wcsとwcs_to_mbsですよね?
自分で話をruby-extに振っておいて、忙しくて反応できなくてすいませんでした。<br><br>で、この変換の件ですが、僕がmbstowcsとwcstombsの仕様を誤解していました。これまたすいません。<br># 知ったかぶりはするもんじゃないなぁ。<br><br>これらの関数はterminating NULを含めて変換した上で、出力した文字数/バイト数をterminating NULの分を除いて返すのですね。<br>ということは、これまでのコードで基本的にオッケーだったような・・・<br><br>これだけじゃアレなので、罪滅ぼしにTipsを一つ。<br>mbstate_tを初期化するポータブルな方法は確か<br>memset(&state, '\0', sizeof(state));<br>だったと思います。
get_wcs_sizeとget_mbs_sizeはterminating NULを除いたサイズを返すので、mbs_to_wcsとwcs_to_mbsでは、terminating NULを除いて変換していました。mbs_to_wstringでは、'\0'を変換してもしなくても、c_str()で必ず最後にL'\0'が付いた状態で逆変換されるので、問題ないと思います。<br><br>P.J. Plauger率いるDinkumwareのリファレンスには<br>mbstate_t mbst = {0};<br>と書いてありますが…。<br>http://www.dinkumware.com/htm_cpl/wchar.html#mbstate_t<br><br>mbstate_tが構造体の場合でも足りないメンバは0に初期化され、PODの場合でも0に初期化されるので、問題ないと思います。
なるほど。<br>確かにこれでも問題ないですね。<br><br># Cも以外と奥が深いんだなぁ<br># Opaqueなデータ構造をそういう方法で初期化するのって<br># 個人的には気持悪いですが…