none
文字列の安全なコピー(strcpy_s)に関して

    質問

  • 安全なコピー をするには strcpy_s を使いなさいとのことで、
    以下のようなコーディングになってしまいます。
    char Msg[200];
    if (Err == -1)
    strcpy_s(Msg, sizeof("エラー発生,,,,,,"), "エラー発生,,,,,,");
    else
    strcpy_s(Msg, sizeof("エラー無し,,,,,,"), "エラー無し,,,,,,");

    もう少しスマートな書き方はありませんか?
    (char *Msg; Msg = "エラー発生,,,,,,"; で動いていますが、ダメなんですよね。)

    SV2008 で、C++のMFCのDLLを作成しています。
    ただ、Cの知識程度で、グローバルな関数を書いています。
    (知らぬ間にC++の命令も使っているようですが)


    mnicksashimisan

    2018年10月29日 8:09

回答

  • strcpy_s の2つ目の引数は、一つ目の引数の配列の個数です。

    なので、上記の例の場合

    strcpy_s( Msg, 200, "エラー発生,,,,,," );

    と最終的にコンパイルされる必要があります。

    ですが、せっかくなのでこれを機にMFCの文字列クラスを利用するなども検討してもいいと思います。ほかの部分はCスタイルのままでも問題ないと思いますので、

    char Msg[200]; ではなく、CString Msg; に置き換えれば

    CString Msg;
    if( Err == -1 )
      Msg = "エラー発生,,,,,,";
    else
      Msg = "エラー無し,,,,,,";
    

    とできます。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2018年10月29日 10:05

すべての返信

  • 同じスコープ内で定義された静的な文字列(例 char Msg[200];)であれば、下記のようにバッファの要素サイズの引数を省略して記述できたと思います。

    char Msg[200];
    strcpy_s(Msg, "エラー発生,,,,,,");

    あるいは、バッファの要素のサイズを求める _countof マクロを使うと下記のように書けます。

    char Msg[200];
    strcpy_s(Msg, _countof(Msg), "エラー発生,,,,,,");
    参考サイト: https://msdn.microsoft.com/ja-jp/library/ms175773.aspx


    追伸: すみません。Visual Studio 2008 で、_countof マクロが使えたかどうか微妙ですので、使えない場合は、下記のように _countof の define を書く必要があるかもしれません。

    #ifndef _countof
    #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
    #endif
    
    char Msg[200];
    strcpy_s(Msg, _countof(Msg), "エラー発生,,,,,,");
    要素サイズやバッファサイズを知るために、_countof にも sizeof にもポインタは渡せないので、動的に確保したバッファやスコープ外で定義されたバッファに対しては、そのバッファの要素数を何らかの方法(例えば関数の引数とか)で渡す必要があります。

    2018年10月29日 8:25
  • 自分は意味的にも、安全上も以下の様なコードしてます。
    const int Def_NumMaxChar_of_Buf = 200; // #defineでも可
    char Msg[ Def_NumMaxChar_of_Buf]; // バッファ
    strcpy_s( Msg, Def_NumMaxChar_of_Buf, "エラーなし,,,,");

    200という数値にこだわりがなければ、
    stdio.hで定義されている BUFSIZ (#define BUFSIZ 512)等を使っても良いのではないでしょうか。


    char Msg2[ BUFSIZ]; // バッファ
    strcpy_s( Msg2, BUFSIZ, "エラーなし,,,,");

    2018年10月29日 9:59
  • strcpy_s の2つ目の引数は、一つ目の引数の配列の個数です。

    なので、上記の例の場合

    strcpy_s( Msg, 200, "エラー発生,,,,,," );

    と最終的にコンパイルされる必要があります。

    ですが、せっかくなのでこれを機にMFCの文字列クラスを利用するなども検討してもいいと思います。ほかの部分はCスタイルのままでも問題ないと思いますので、

    char Msg[200]; ではなく、CString Msg; に置き換えれば

    CString Msg;
    if( Err == -1 )
      Msg = "エラー発生,,,,,,";
    else
      Msg = "エラー無し,,,,,,";
    

    とできます。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2018年10月29日 10:05
  • # いろいろな方が回答していますが、どれもしっくりこないので、更に回答を追加します。

    まず最初に大間違いがあります。第2引数はバッファオーバーランを検出するための書き込み先のバッファーサイズです。sizeof("エラー発生,,,,,,") は書き込もうとしている元データのサイズですので、バッファオーバーランが検出できず、セキュリティ上全くの無駄となっています。これならstrcpy()を使った方がマシです。

    次にstrcpy_s()ですが、

    errno_t strcpy_s(
       char *strDestination,
       size_t numberOfElements,
       const char *strSource 
    );
    template <size_t size>
    errno_t strcpy_s(
       char (&strDestination)[size],
       const char *strSource 
    ); // C++ only

    の2種類があります。char Msg[200]; のように固定サイズバッファであれば後者のオーバーロードを使用して strcpy_s(Msg, "エラー発生,,,,,,"); と書くとC++コンパイラーが自動的に strcpy_s(Msg, 200, "エラー発生,,,,,,"); に展開してくれます。

    更にセキュリティ保護されたテンプレート オーバーロードを使うこともできます。#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1としておくと strcpy(Msg, "エラー発生,,,,,,"); と書いた場合にも strcpy_s(Msg, 200, "エラー発生,,,,,,"); に展開してくれます。

    # ちなみに_countofマクロは昔から存在してますよん

    2018年10月29日 13:50
  • CString Msg;
    if( Err == -1 )
      Msg = "エラー発生,,,,,,";
    else
      Msg = "エラー無し,,,,,,";
    やりたかったことはこれです。

    グローバル関数の中でも使えますし、fprintf の引数としても使え、
    上手く動作しました。ありがとうございました。

    (C++なのかMFCなのか分かりませんが、難しい文字列の話が
     いっぱい出てきて近づきたくなかったのですが、CStringは簡単そうですね)

    mnicksashimisan

    2018年10月30日 2:21
  • 「やりたかったこと」は質問者さんの意思に過ぎません。具体的な質問文はタイトルが「文字列の安全なコピー(strcpy_s)に関して」となっているため、私含め皆さんがstrcpy_sについて説明しているわけですが。質問者さんが本当に求めていることについて、正確に質問できていないことを理解してください。
    2018年10月30日 5:14
  • 不適切なタイトルでの質問になり、申し訳ありませんでした。


    mnicksashimisan

    2018年10月31日 0:39