• ベストアンサー

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

質問者が選んだベストアンサー

  • ベストアンサー
回答No.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

LongSecret
質問者

お礼

>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); こんな便利な関数があったのですね 色々と詳しいところありがとうございます♪

その他の回答 (1)

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

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

LongSecret
質問者

お礼

ありがとうございます。 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でしょうか?

関連するQ&A

  • CString から LPCTSTRの型に変換

    visual studio 2013 VC++を使用していますが、WINDOWSの関数に渡すためにCString からLPCTSTRに変換する必要があります。実際にどのようにするのかわかりません。 例えば、以下のサンプルは他の質問コーナーの回答をアレンジしたものです CString str = _T("ABC"); int siz = str.GetLength()+1; LPCTSTR pszFName = new TCHAR[siz]; _tcscpy_s( pszFName, siz, str ); で変換するのですが LPCTSTRからwchar_t*へ変換できませんとエラーがでます _tcscpy_s()は使用できないのでしょうか

  • VS2008 C++ 書式付文字列書込み関数

    VS2008 C++で文字セットはUnicode文字セットを使用しています TCHAR bur[50]; _stprintf_s(buf, 50, _T("T = %d"), 100); を実行すると「T=100」の後にNULLがきて、ここまでは正常ですが、残りの部分には0xfefeが文字列バッファの最後までコピーされます。 正常な動作なのでしょうか。

  • TCHAR文字列?の特定部分の数字文字をint型の数値に変える方法

    TCHAR文字列?の特定部分の数字文字をint型の数値に変える方法ですが どうすればよいでしょうか? int test(LPCTSTR s) { int a, b, c, d; /* TCHAR?型文字列を数値のintに変える方法???  a = 12の前2桁 b = 34の2桁 c = 5の最後の1桁 */ d = a + b - c; return d; } ret = test(_T("12345")); の場合、retに41が返ってきてほしい。

  • %sの使い方について教えてください。

    %sの使い方について教えてください。 char c[4] = "abc" printf("%s",c); この関数は%sでcのアドレス(&c[0])を読み込み、stdoutにそのアドレスを書込み、文字列abcが表示されると認識しています。 printf("%s",stdin); とすればstdinのアドレスがstdoutに書き込まれて標準入力が表示されると思っていたのですが、実際はprintf("%s",*stdin)としなければ出力されませんなぜでしょうか? 回答をよろしくお願いします。 もう一つ別件なのですが、printf("%d",sizeof *stdin); と入力すると、32と出力されます。 なので、stdinは32バイトの大きさだと認識したのですが、char型の文字が32文字以上を書き込むことができます。(scanf()で入力が失敗して32文字以上の文字をバッファに保管できるということです。) これはどういうことでしょうか、分かる方是非、回答をよろしくお願いします。

  • char型変数をLPCTSTR型に変換したい

    大学の研究でプログラム作成している者です. 現在外部ファイルの文字列をfscanf()でchar型変数に取り込み,それをLPCTSTR型変数に変換して,関数に引数として渡そうとしてます. しかし,現在はchar/THCARの変換が正しくできず困っております.現在のコードは以下のような流れになってます. ----------------------------------------------- char name[MAX_PATH]; TCHAR name_t[MAX_PATH]; fscanf( &fp, "%s", name ); wsprintf( name_t, _T("%s"), &name ); // char ⇒ TCHAR makedFunction( name_t ); // 自作関数(引数はLPCTSTR) ----------------------------------------------- しかし, wsprintf()で変換した時点で,文字列がおかしくなってしまい困ってます. 開発環境はVisualStudio2010で,MFC作成(Unicode文字列)となってます.ちなみにマルチバイト文字列を使用する解決方法はなしとします. 解決方法をご存知の方がおられましたら,是非とも,ご回答よろしくお願い致します.

  • 自作DLLの引数について、ポインタ渡しが??

    VS2005 VC++環境でMFCスマートデバイスDLLを作成しています(アプリ側もVS2005 VC++)。 テスト用のアプリからDLL内の文字列を引数とする関数を呼び出すと、 呼ばれた関数に正しく文字列が渡りません。 以下の場合、func1のw1はデバッガで正しく見れません。 でもw2にtcscpyは成功しw2には正しく値がセットされます。 このときにw1のアドレスがなぜか変更されます。 以下の例では引数が1つですが、2つ以上引数がある時には その他の引数のアドレスもとびます。 func2のl1は正常に見れます。 func3のl1は正常に見れません。 ポインタ渡しするときに異常になるのですが、 原因がさっぱりわかりません。 同じことをWindowsXP用のプロジェクトを作り、 XPで確認するとどれも正常に見れます。 どなたかアドバイスをお願いします。 ----------------------------------------DLL側---------------------------------------- extern "C" __declspec(dllexport) void func1(WCHAR * w1) { WCHAR w2[16] ; _tcscpy(w2,w1); return; } extern "C" __declspec(dllexport) void func2(long l1) { long l2 ; l2 = l1 ; return; } extern "C" __declspec(dllexport) void func3(long *l1) { long l2 ; l2 = *l1 ; return; } ----------------------------------------アプリ側---------------------------------------- extern "C" __declspec(dllimport) void func1(WCHAR *); extern "C" __declspec(dllimport) void func2(long ); extern "C" __declspec(dllimport) void func3(long *); ・・・・中略・・・・ WCHAR a[16] ; _tcscpy(a,_T("ABC")); func1(a); func2(123); long l3 = 123 ; func3(&l3);

  • 可変長引数関数の引数の文字列サイズを取得したい

    以下のような可変長の文字列を受け取れる関数があったとします。 ...の部分で引数を受け取ることが可能ですが、この場合引数の文字列サイズを 知ることは可能なのでしょうか? 関数を呼び出してみて例を挙げるとするなら、  GetArgs( "%s", "あいうえお" ); この「あいうえお」の部分の文字数をGetArgs内で知りたいのです。 void GetArgs( char * FormatString, ... ) {   va_list VaList;   va_start( VaList, FormatString );   // ここでFormatStringの引数の文字列サイズを取得したい   va_end( VaList ); }

  • OCXのメソッドの引数に文字列を返したい

    こんにちは。いつもお世話になっております。 早速ですが質問させて下さい。 VisualC++のClassWizardにて作成したメソッドの引数に文字列を返したいのですがどうすればよいでしょうか。 例えば、「test.ocx」というOCXにGetFileNameというメソッドを追加したとします。 ---<GetFileName>--- UINT GetFileName( LPCTSTR FilePath, //ファイルフルパス LPCTSTR FileName //ファイル名 ) ------------------- ---<VBからの呼び出し>--- FilePath = "C:\Program Files\test.txt" ret = obj.GetFileName(FilePath, FileName) 'ここでFileNameに値を返したい ------------------------ ここでFileNameにOCXから値を返すようにしたいのですが、型(ClassWizardパラメータリストの「タイプ」)は何になるのでしょうか。 数値を返す場合は、「long*」でできたのですが、 文字列を返す方法が分かりません。(「LPCTSTR*」というのもないですし) どうかご教示下さい。 <環境> Windows 2000, Visual C++ 6.0, Visual Basic 6.0

  • 効率的な拡張子チェック関数を考えています

    現在以下のような関数を試作してみました。 fnがファイルパスで、exが比較する拡張子の、「.」を含まない部分です。 (CompareStringはこの設定で大文字小文字の差を許容して比較します) BOOL CompareExtension(LPCTSTR fn ,LPCTSTR ex){ int i = _tcslen(fn); while ( fn[--i] != '.' ) if ( !i ) return 0; if ( CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE, fn+i+1, -1, ex , -1 ) != CSTR_EQUAL ) return 0; return 1; } これをたとえばこのように呼び出すと if ( CompareExtension(_T("a\\b\\c\\d.txtefg"),_T("tXtEFg")) ) _tprintf(_T("EQUAL\n")); 1が返り、EQUALと出力されます。 このとき 1.今のところ例外を見つけていませんが このfn+i+1は、この用途で、アルファベットの拡張子しか扱わないとしたら必ず PathFindExtension(fn)+1 のかわりになりますでしょうか? 2.Unicodeでもこのままで出来てしまっているのですが、文字定数も_T('.')などとマクロで囲わないと保証はされないのでしょうか? 3.「拡張子を自分でコード内に指定する」「パスが正常に渡されることが保証されてて、その文字数が拡張子の文字数より必ず多い」ならwhile文をなくして、ピリオドが来るべき位置を数字で打ってしまっても問題ないですよね? 4.またその他どこかになんらかの危険性がある可能性はあるでしょうか?

  • strncpyと_tcsncpy_sのヌルの扱いが違う点

    strncpyの場合は、\0を付加しないのですが、_tcsncpy_sは ヌルを付加しますが、これは仕様でしょうか? 同じ意味の関数なのにヌルの振る舞いが異なると勘違いします。 TCHAR型を扱う関数で、strncpyと同じようにnullを付加しない関数はあるのでしょうか? このあたりについて詳しく書かれている本も探しております。 strcpy(buf1, "aaaaa"); strncpy(buf1, "b", 1); 結果 buf[0] = "b" buf[1] = "a" buf[2] = "a" buf[3] = "a" buf[4] = \0 _tcscpy_s(buf1, sizeof(buf1), "aaaaa"); _tcsncpy_s(buf1, sizeof(buf1), "b", 1); 結果 buf[0] = "b" buf[1] = \0 buf[2] = "a" buf[3] = "a" buf[4] = \0

専門家に質問してみよう