- ベストアンサー
_tcscpy_s(wcscpy_s)の第二引数って
http://msdn.microsoft.com/ja-jp/library/td1esda9%28VS.80%29.aspx を見て、たとえば以下のような関数を書いたとします。 TCHAR* fn; void OMG(LPCTSTR c){ int bytes( ( _tcslen(c) + 1 )*sizeof(TCHAR) ); if ( fn = (TCHAR*)malloc( bytes ) ) _tcscpy_s( fn, bytes, c ); //実行しないでください else return; /* fnを使用 */ free(fn); fn=0; } これ、マルチバイトだと正常に出来るのですが なぜかUnicodeだと落ちてしまいました。 第2引数の説明は コピー先の文字列バッファのサイズ。 <英語版でも> Size of the destination string buffer. となっていますが、その上に numberOfElements って書いてあるのでまさかと思い サイズではなく文字数に変えたら、どうも正常に動作するようになったようです。 とくに_sがつく関数は文字数だったりバッファサイズだったりまちまちな感がもともとあるのに、しかも こういうところでこういうことがあると厳しいものがあるのですが これは本当に誤植なのでしょうか? また、かなり稀なケースであり本当に誤植だとしたら、MSDNの他の文字列操作関数には記述の誤りがあるものはありますか?
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
C++のtemplateを使ったstrcpy_s,wcscpy_sは template <size_t size> errno_t strcpy_s( char (&strDestination)[size], const char *strSource ); // C++ only template <size_t size> errno_t wcscpy_s( wchar_t (&strDestination)[size], const wchar_t *strSource ); // C++ only となっています。 これをみると、sizeは「配列数」ということになります。 ですので、「numberOfElements」のさす意味そのもので「要素の数」(≠文字数)という解釈になります。 ちなみに、Unicodeでも1文字2バイトとは限りませんので 一概に文字数ともいえません。 (サロゲート で検索してみてください。) >TCHAR c[100]; > >if ( fn = (TCHAR*)malloc( sizeof c ) ) _tcscpy_s( fn, >sizeof(c)/sizeof(TCHAR), c ); > >とか >_tcscpy_s( fn, 100, c ); まぁ、結果的にあっていますが、fnに格納するときにバッファが足りているかをみるのをcを使うのはよろしくないかなと。 >int len( _tcslen(c) + 1 ); >if ( fn = (TCHAR*)malloc( len*sizeof(TCHAR) ) ) _tcscpy_s( fn, len, c ); のほうがよいですね。 まぁ、cに格納されている文字列を新しい領域をmallocしてコピーするのであれば、_tcsdupで TCHAR* fn = _tcsdup(c); と記述できます。 http://msdn.microsoft.com/ja-jp/library/y471khhc%28VS.80%29.aspx
その他の回答 (1)
- Wr5
- ベストアンサー率53% (2173/4061)
UNICODEでは1文字が何バイトになるか…という辺りが規定できないのでしょう。 Win32APIでも、ANSI版は「バイト数」、UNICODE版は「文字数」で扱うものが多いです。 GetModuleFileName()など… >nSize >[入力]lpFilename バッファのサイズを、TCHAR 単位で指定します。パス名とファイル名がこのバッファより大きかった場合、この関数は文字列を切り捨てます。 「TCHAR 単位」というのが、バイト数ではない…というコトになります。
お礼
ありがとうございます。 TCHAR単位ってちゃんと書いてあればどうコードを書けばいいかちゃんと判断出来ますが http://msdn.microsoft.com/ja-jp/library/ce3zzk1k%28VS.80%29.aspx http://msdn.microsoft.com/ja-jp/library/eywx8zcx%28VS.80%29.aspx このへんは文字数って書いてあるのでこれでも判断できます http://msdn.microsoft.com/ja-jp/library/8e46eyt7%28VS.80%29.aspx これも1 バイト文字またはワイド文字の数と書いてあるので(ANSIでは1バイト文字の数なのかバイト数なのかといえば後者のような気がしますが(まだ試していません)) 少なくともUnicodeではバイト数ではないと判断できます。 う~ん 両方対応するように一気に手直しした際、その中で _tcscpy_s先に見ちゃったから まちまちだと思ってしまったのかもしれませんが 実際には、おっしゃる通り 表記が一律でないだけで(ほぼ、あるいは全部かも) >ANSI版は「バイト数」、UNICODE版は「文字数」 のような感じがしますね。 表記上そう読めなかったら検証してみることにします。 現状はUnicodeは2バイトのはずですし 上記コードは int len( _tcslen(c) + 1 ); if ( fn = (TCHAR*)malloc( len*sizeof(TCHAR) ) ) _tcscpy_s( fn, len, c ); こういった具合に直しておけば問題はないはず。 また、こういう場合でも TCHAR c[100]; if ( fn = (TCHAR*)malloc( sizeof c ) ) _tcscpy_s( fn, sizeof(c)/sizeof(TCHAR), c ); とか _tcscpy_s( fn, 100, c ); といった具合にすればOK と、思うのですが、コード側の対処法としてはこんな感じの考え方でOKでしょうか?
お礼
>Unicodeでも1文字2バイトとは限りません そうだったのですか 調べてみたら色々な方式があるようですね。 しかし、いずれにしても >>int len( _tcslen(c) + 1 ); >>if ( fn = (TCHAR*)malloc( len*sizeof(TCHAR) ) ) _tcscpy_s( fn, len, c ); >のほうがよいですね。 ということは、sizeof(TCHAR)を使えばマルチバイトのバイト数と同じように判定できる、と考えて良いということですね。 >TCHAR* fn = _tcsdup(c); こんな便利な関数があったのですね 色々と詳しいところありがとうございます♪