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

Error reading characters of string after wcscpy_s

本文关键字:字符 出错 字符串 读取 wcscpy      更新时间:2023-10-16

我对wcscpy_s函数有问题。wcscpy_s返回后,我的函数的参数(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) 而不是 _sizeof(tmp) .

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

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

除了他建议使用 _countof(tmp) 而不是 sizeof(tmp) 之外,我还想补充一点,C++ 中有一个方便的 wcscpy_s() 重载,可以自动推断出正确的缓冲区大小:

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++编译器必须能够在编译时计算出缓冲区大小。另一方面,当指针指向动态分配的缓冲区时,必须显式传递正确的缓冲区大小。