wchar_t wcscpy_s 的数组大小问题
wchar_t array size issue with wcscpy_s
我对尺寸问题感到困惑。 运行 以下代码在运行时抛出异常。具体好像出现在最后,文字还是粘贴成功。由于我的技能有限,我无法清楚地解释异常。
它开始于我决定使用 wcscpy_s 函数,因为 wcscpy 的贬值在我的 noob 程序中运行良好。
#define _CRT_SECURE_NO_WARNINGS
#include <afxwin.h>
int main() {
wchar_t wcSource[7] = L"Testeu"; // Throws an exception error. However, wcSource[8] doesn't
//wchar_t wcSource[9] = L"TestCopy"; // Runs fine
UINT iSize = sizeof(wcSource);
if (OpenClipboard(NULL)) {
EmptyClipboard();
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_DDESHARE, iSize);
wchar_t *wpchData;
wpchData = (wchar_t*)GlobalLock(hClipboardData);
//wcscpy(wpchData, wcSource); // Works fine
wcscpy_s(wpchData, iSize, wcSource);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
CloseClipboard();
}
return 0;
}
wcscpy_s()
需要 CHARACTER 计数,但您传递给它的是 BYTE 计数。在 Windows 上,sizeof(wchar_t)
是 2 个字节。
为剪贴板缓冲区分配内存时需要字节计数(在您的示例中需要 14 个字节),但是由于您将字节计数作为字符计数传递给 wcscpy_s()
,所以您告诉剪贴板缓冲区最多可以容纳 14 个 wchar_t
元素,而实际上它只能容纳 7 个。您授予 wcscpy_s()
超出剪贴板缓冲区范围的权限(例如,如果它想要在用实际字符填充之前预填充缓冲区内存)。 这样做会破坏调用堆栈,这很容易在main()
退出时引发异常。
您需要传递 wcscpy_s()
剪贴板缓冲区可以容纳的最大字符数。不是它可以容纳的最大字节数。
您可以将 iSize
除以 sizeof(wchar_t)
,例如:
wcscpy_s(wpchData, iSize / sizeof(wchar_t), wcSource);
或者,由于您使用源数组的确切 BYTE 大小来分配剪贴板缓冲区,您可以使用 _countof()
获取数组中的字符数(您不能传递分配的剪贴板缓冲区_countof()
), 例如:
wcscpy_s(wpchData, _countof(wcSource), wcSource);
或者,您可以使用 wsclen()
,例如:
wchar_t wcSource[] = L"Testeu";
int iLen = wcslen(wcSource) + 1;
UINT iSize = iLen * sizeof(wchar_t);
...
hClipboardData = GlobalAlloc(GMEM_DDESHARE, iSize);
...
wcscpy_s(wpchData, iLen, wcSource);
我对尺寸问题感到困惑。 运行 以下代码在运行时抛出异常。具体好像出现在最后,文字还是粘贴成功。由于我的技能有限,我无法清楚地解释异常。 它开始于我决定使用 wcscpy_s 函数,因为 wcscpy 的贬值在我的 noob 程序中运行良好。
#define _CRT_SECURE_NO_WARNINGS
#include <afxwin.h>
int main() {
wchar_t wcSource[7] = L"Testeu"; // Throws an exception error. However, wcSource[8] doesn't
//wchar_t wcSource[9] = L"TestCopy"; // Runs fine
UINT iSize = sizeof(wcSource);
if (OpenClipboard(NULL)) {
EmptyClipboard();
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_DDESHARE, iSize);
wchar_t *wpchData;
wpchData = (wchar_t*)GlobalLock(hClipboardData);
//wcscpy(wpchData, wcSource); // Works fine
wcscpy_s(wpchData, iSize, wcSource);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
CloseClipboard();
}
return 0;
}
wcscpy_s()
需要 CHARACTER 计数,但您传递给它的是 BYTE 计数。在 Windows 上,sizeof(wchar_t)
是 2 个字节。
为剪贴板缓冲区分配内存时需要字节计数(在您的示例中需要 14 个字节),但是由于您将字节计数作为字符计数传递给 wcscpy_s()
,所以您告诉剪贴板缓冲区最多可以容纳 14 个 wchar_t
元素,而实际上它只能容纳 7 个。您授予 wcscpy_s()
超出剪贴板缓冲区范围的权限(例如,如果它想要在用实际字符填充之前预填充缓冲区内存)。 这样做会破坏调用堆栈,这很容易在main()
退出时引发异常。
您需要传递 wcscpy_s()
剪贴板缓冲区可以容纳的最大字符数。不是它可以容纳的最大字节数。
您可以将 iSize
除以 sizeof(wchar_t)
,例如:
wcscpy_s(wpchData, iSize / sizeof(wchar_t), wcSource);
或者,由于您使用源数组的确切 BYTE 大小来分配剪贴板缓冲区,您可以使用 _countof()
获取数组中的字符数(您不能传递分配的剪贴板缓冲区_countof()
), 例如:
wcscpy_s(wpchData, _countof(wcSource), wcSource);
或者,您可以使用 wsclen()
,例如:
wchar_t wcSource[] = L"Testeu";
int iLen = wcslen(wcSource) + 1;
UINT iSize = iLen * sizeof(wchar_t);
...
hClipboardData = GlobalAlloc(GMEM_DDESHARE, iSize);
...
wcscpy_s(wpchData, iLen, wcSource);