读取 wcscpy_s 之后的字符串字符时出错
Error reading characters of string after wcscpy_s
我对 wcscpy_s
功能有疑问。在 wcscpy_s
returns 之后,我函数的参数(stringOne
和 stringTwo
)不可读。
这是显示问题的简单演示。
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=]。另一方面,当您有 指针 到 动态 分配的缓冲区时,您必须显式传递正确的缓冲区大小。
我对 wcscpy_s
功能有疑问。在 wcscpy_s
returns 之后,我函数的参数(stringOne
和 stringTwo
)不可读。
这是显示问题的简单演示。
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=]。另一方面,当您有 指针 到 动态 分配的缓冲区时,您必须显式传递正确的缓冲区大小。