解決済みの質問
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の他の文字列操作関数には記述の誤りがあるものはありますか?
投稿日時 - 2010-03-20 01:29:26
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
投稿日時 - 2010-03-22 09:47:15
お礼
>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);
こんな便利な関数があったのですね
色々と詳しいところありがとうございます♪
投稿日時 - 2010-03-22 15:59:17
10人が「このQ&Aが役に立った」と投票しています
ベストアンサー以外の回答(1件中 1~1件目)
UNICODEでは1文字が何バイトになるか…という辺りが規定できないのでしょう。
Win32APIでも、ANSI版は「バイト数」、UNICODE版は「文字数」で扱うものが多いです。
GetModuleFileName()など…
>nSize
>[入力]lpFilename バッファのサイズを、TCHAR 単位で指定します。パス名とファイル名がこのバッファより大きかった場合、この関数は文字列を切り捨てます。
「TCHAR 単位」というのが、バイト数ではない…というコトになります。
投稿日時 - 2010-03-20 12:59:08
お礼
ありがとうございます。
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でしょうか?
投稿日時 - 2010-03-20 14:12:16