读取 wcscpy_s 之后的字符串字符时出错

Error reading characters of string after wcscpy_s

我对 wcscpy_s 功能有疑问。在 wcscpy_s returns 之后,我函数的参数(stringOnestringTwo)不可读。 这是显示问题的简单演示。

void testFunc(LPCWSTR stringOne, LPCWSTR stringTwo) {

    wchar_t* defaultVal = L"Default";

    wchar_t tmp[100];

    int lenBefore = wcslen(stringOne); // Works

    auto result = wcscpy_s(tmp, sizeof(tmp), defaultVal);

    int len = wcslen(tmp);

    int len2 = wcslen(stringOne); // Throws Exception Access violation
}


int main() {
    testFunc(L"Test", L"Test");
}

wcscpy_s 的文档指出此函数的调试版本使用特殊值 0xFE.

填充目标缓冲区

当您调用 wcscpy_s(tmp, sizeof(tmp), defaultVal); 时,您传递 tmp 缓冲区的大小,但 wcscpy_s 需要字符数的长度。因此,您传递给 wcscpy_s 的长度是应有长度的两倍,并且由于 tmp 缓冲区被 0xfe 覆盖,您会得到缓冲区溢出和未定义的行为,即使长度如果源字符串 (L"Default";) 很小。

所以使用_countof(tmp) instead of _sizeof(tmp).

这就是说,我建议你学习如何使用 Visual Studio 调试器。

正如 Michael Walz 的回答中所解释的那样,您遇到了由于传递不正确的缓冲区大小而导致的缓冲区溢出。

除了他建议使用 _countof(tmp) 而不是 sizeof(tmp) 之外,我想补充一点,在 C++ 中有一个方便的重载 wcscpy_s() that automatically deduces the correct buffer size:

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

基本上,您可以编写 更简单的 代码,这样就可以了:

wchar_t tmp[100];

// Use the C++-only template overload of wcscpy_s
// that automatically deduces the destination buffer size
auto result = wcscpy_s(tmp, defaultVal);

如果您使用此重载,您将免受那些 sizeof/_countof 不匹配类型的错误。

请注意,此 C++ 重载仅在您具有像 wchar_t tmp[100] 的静态缓冲区时才有效,因为 C++ 编译器必须能够在 编译时[=] 计算出缓冲区大小35=]。另一方面,当您有 指针 动态 分配的缓冲区时,您必须显式传递正确的缓冲区大小。