4

この C++ コードはちょっと不自由ですが、維持する必要があります。「バッファが小さすぎる」問題を理解できないようです。Visual Studio 2010 を使用しています。デバッガーに表示される値に基づいて、再現に必要な最小限のコードを作成します。申し訳ありませんが、実際のスニペット自体はテストしていません。また、デバッグ中にシステムのクリップボードが「ビジー」になっているため、コピーして貼り付けるだけではうまくいかないため、エラーがどこかに忍び寄る可能性がありますが、再確認します。私を信じてください、あなたは関数全体を見たくありません-意味をなすには長すぎます:)

tchar.h から

#define _tcsncpy_s wcsncpy_s

afxstr.h から:

typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;

WinNT.h から:

typedef WCHAR TCHAR, *PTCHAR;

ああ、これらのマクロは決して終わらないようです。ここでやめます。最後に、myfile.cpp から:

CString str; // Actually a function parameter with value "07/02/2010"
DWORD nIndex = 10;
DWORD nLast = 0;
LPCTSTR psz = (LPCTSTR) str; // Debugger says that it also gets "07/02/2010".

CString s;
_tcsncpy_s(
    s.GetBuffer((int) (nIndex - nLast + 1)), // I added the " + 1" part hoping to fix a bug, but that changed nothing
    nIndex - nLast,
    psz + nLast,
    (size_t) (nIndex - nLast)
);

これでアサーションがヒットし、デバッガーが開きtcsncpy_s.inl、最後に次のコードが表示されます。

  53    ...
  54    if (available == 0)
  55    {
  56        if (_COUNT == _TRUNCATE)
  57        {
  58            _DEST[_SIZE - 1] = 0;
  59            _RETURN_TRUNCATE;
  60        }
  61        RESET_STRING(_DEST, _SIZE);
=>62        _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
  63    }
  64    _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
  65    _RETURN_NO_ERROR;
  66 }
  67
  68

デバッガーは 62 行目を指します: _RETURN_BUFFER_TOO_SMALL. 残念ながら、私は にいる間は物事の価値を見ることができませんtcsncpy_s.inl。おそらく、経験豊富なコーダーがここで何が起こっているのか教えてくれるでしょうか? このコードはかなり古く、Unicode を念頭に置いて書かれていないと思います (おそらく間違っています)。古い N のくだらない銃 (C++0X のトリックやその他の空想的なものは使用しないでください) へのこのこだわりを修正する最善の方法は何ですか? - 弾丸の傷にパッチを当てたいだけです。

4

3 に答える 3

3

の 4 番目の引数strncpy_sは、ソース バッファーからコピーする文字数であり、終端の null は考慮されません。つまり、実際には、ソース バッファーに文字列(nIndex - nLast)以上の文字列が含まれている場合、(nIndex - nLast)コピーされます。また、ヌル文字が追加されます。そのため、宛先バッファーは(nIndex - nLast + 1)、そのヌルも考慮して文字を受け入れるように準備する必要があります。

+1 はそれを行っているように見えますがstrncpy_s、バッファの大きさを示す の 2 番目の引数にも反映する必要があります。に変更すると(nIndex - nLast + 1)、動作するはずです。

于 2010-07-09T18:09:09.360 に答える
3

wcsncpy_s() に渡されるサイズはバッファー サイズであり、バッファーに格納できる文字数ではありません。ゼロターミネータが含まれています。1 を追加する必要があります。

于 2010-07-09T18:07:50.977 に答える
2

wcsncpy_s()( http://msdn.microsoft.com/en-us/library/5dae5d43.aspx )のドキュメントから:

これらの関数は、strSource の最初の D 文字を strDest にコピーしようとします。ここで、D は strSource のカウントと長さのうち小さい方です。これらの D 文字が strDest (numberOfElements として指定されたサイズ) 内に収まり、それでも null ターミネータの余地がある場合、それらの文字はコピーされ、終端の null が追加されます。それ以外の場合、strDest[0] は null 文字に設定され、無効なパラメーター ハンドラーが呼び出されます。

したがって、カウントは、既に行っているバイト数ではなく、文字 (要素) で指定する必要があります。また、宛先バッファーのサイズは、バッファー内にスペースを作っているが、伝えていない null ターミネーター文字を考慮する必要があります。 (ここでwcsncpy_s()知られて_tcsncpy()いる)について:

_tcsncpy_s(
    s.GetBuffer((int) (nIndex - nLast + 1)), // I added the " + 1" part hoping to fix a bug, but that changed nothing
    nIndex - nLast + 1,
    psz + nLast,
    (size_t) (nIndex - nLast)
);
于 2010-07-09T19:39:03.660 に答える