教えて! goo のコンテンツに対する取り組みについて

http://msdn.microsoft.com/ja-jp/library/td1esda9 …

を見て、たとえば以下のような関数を書いたとします。

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の他の文字列操作関数には記述の誤りがあるものはありますか?

gooドクター

A 回答 (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 …
    • good
    • 0
この回答へのお礼

>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

UNICODEでは1文字が何バイトになるか…という辺りが規定できないのでしょう。


Win32APIでも、ANSI版は「バイト数」、UNICODE版は「文字数」で扱うものが多いです。
GetModuleFileName()など…
>nSize
>[入力]lpFilename バッファのサイズを、TCHAR 単位で指定します。パス名とファイル名がこのバッファより大きかった場合、この関数は文字列を切り捨てます。
「TCHAR 単位」というのが、バイト数ではない…というコトになります。
    • good
    • 0
この回答へのお礼

ありがとうございます。
TCHAR単位ってちゃんと書いてあればどうコードを書けばいいかちゃんと判断出来ますが

http://msdn.microsoft.com/ja-jp/library/ce3zzk1k …
http://msdn.microsoft.com/ja-jp/library/eywx8zcx …

このへんは文字数って書いてあるのでこれでも判断できます

http://msdn.microsoft.com/ja-jp/library/8e46eyt7 …
これも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

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

gooドクター

このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング