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

传递给 wcsncpy_s() 的大小是缓冲区大小,而不是缓冲区可以存储的字符数。它包括零终止符。您需要添加 1。

于 2010-07-09T18:07:50.977 回答
3

to 的第四个参数strncpy_s是从源缓冲区复制的字符数,它不考虑终止的 null - 即,实际上,如果源缓冲区包含具有(nIndex - nLast)或更多字符的字符串,(nIndex - nLast)则将被复制,并且然后还会附加一个空字符。所以目标缓冲区必须准备好接受(nIndex - nLast + 1)字符来解释那个空值。

现在您的 +1 似乎可以做到这一点,但您也应该在 的第二个参数中反映它strncpy_s,它告诉它缓冲区有多大。将其更改为(nIndex - nLast + 1),它应该可以工作。

于 2010-07-09T18:09:09.360 回答
2

wcsncpy_s()来自(http://msdn.microsoft.com/en-us/library/5dae5d43.aspx )的文档:

这些函数尝试将 strSource 的前 D 个字符复制到 strDest,其中 D 是 count 和 strSource 长度中的较小者。如果这些 D 字符将适合 strDest(其大小以 numberOfElements 给出)并且仍然为空终止符留出空间,则复制这些字符并附加终止空;否则,strDest[0] 设置为空字符并调用无效参数处理程序

因此,计数必须以字符(元素)而不是字节指定,你已经在做,并且目标缓冲区大小必须考虑空终止符,你在缓冲区中腾出空间,但不告诉(这里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 回答