为什么在从 WCHAR 转换为 char 时会得到一个额外的空终止字符?
Why do I get an extra null terminating character when converting from WCHAR to char?
我正在研究使用此 C 代码的字符串空终止。
#include <Windows.h>
#include <stdio.h>
int wmain(int argc, WCHAR *argv[])
{
WCHAR *wstr = argv[1];
int wlen, len, written;
char *strA;
DWORD nOut = 0;
wlen = lstrlenW(wstr);
printf("wlen: %d\n", wlen);
if (wstr[wlen] == 0) printf("wstr[%d] == 0\n", wlen);
if (wstr[wlen + 1] == 0) printf("wstr[%d] == 0\n", wlen + 1);
len = WideCharToMultiByte(GetConsoleOutputCP(), 0, wstr, wlen, NULL, 0, NULL, NULL);
printf("len: %d chars required\n", len);
strA = HeapAlloc(GetProcessHeap(), 0, len + 1);
if (!strA) return -1;
written = WideCharToMultiByte(GetConsoleOutputCP(), 0, wstr, wlen, strA, len, NULL, NULL);
printf("written: %d\n", written);
strA[len] = 0; /* Null terminate the ASCII string */
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), strA, len, &nOut, NULL); printf("\n");
if (strA[len] == 0) printf("strA[%d] == 0\n", len);
if (strA[len + 1] == 0) printf("strA[%d] == 0\n", len + 1);
HeapFree(GetProcessHeap(), 0, strA);
return 0;
}
如果我提供一个由偶数个 WCHAR 组成的输入字符串,例如Hello!
,我得到:
wlen: 6
wstr[6] == 0
wstr[7] == 0 /* Where does this come from? */
len: 6 chars required
written: 6
Hello!
strA[6] == 0
strA[7] == 0 /* Where does this come from? */
但是如果我提供一个包含奇数个 WCHAR 的字符串,例如Hello
,我只得到:
wlen: 5
wstr[5] == 0
len: 5 chars required
written: 5
Hello
strA[5] == 0
为什么在 wstr[len+1]
和 str[len+1]
处多了一个空终止符?据我所知,没有为 ASCII 字符串中的第二个 NUL 分配足够的内存。
strA = HeapAlloc(GetProcessHeap(), 0, len + 1);
strA[i]
的有效索引 i
包括 0
到 len
。这意味着读取 strA[len + 1]
会调用未定义的行为,因为您正在读取超出缓冲区末尾的内容。
当您调用未定义的行为时,允许发生任何事情。一种可能的结果是您未定义的行为导致您读取值为 0
.
的 char
同样,在这之后
wlen = lstrlenW(wstr);
您知道 wstr[i]
的有效索引 i
包含 0
到 wlen
。所以再次阅读 wstr[wlen + 1]
.
是错误的
简单地说,停止读取超出缓冲区的末尾。
您将错误的长度值传递给 WideCharToMultiByte
。应该是:
UINT cp = GetConsoleOutputCP();
len = WideCharToMultiByte(cp, 0, wstr, -1, NULL, 0, NULL, NULL);
和
written = WideCharToMultiByte(cp, 0, wstr, -1, strA, len+1, NULL, NULL);
我正在研究使用此 C 代码的字符串空终止。
#include <Windows.h>
#include <stdio.h>
int wmain(int argc, WCHAR *argv[])
{
WCHAR *wstr = argv[1];
int wlen, len, written;
char *strA;
DWORD nOut = 0;
wlen = lstrlenW(wstr);
printf("wlen: %d\n", wlen);
if (wstr[wlen] == 0) printf("wstr[%d] == 0\n", wlen);
if (wstr[wlen + 1] == 0) printf("wstr[%d] == 0\n", wlen + 1);
len = WideCharToMultiByte(GetConsoleOutputCP(), 0, wstr, wlen, NULL, 0, NULL, NULL);
printf("len: %d chars required\n", len);
strA = HeapAlloc(GetProcessHeap(), 0, len + 1);
if (!strA) return -1;
written = WideCharToMultiByte(GetConsoleOutputCP(), 0, wstr, wlen, strA, len, NULL, NULL);
printf("written: %d\n", written);
strA[len] = 0; /* Null terminate the ASCII string */
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), strA, len, &nOut, NULL); printf("\n");
if (strA[len] == 0) printf("strA[%d] == 0\n", len);
if (strA[len + 1] == 0) printf("strA[%d] == 0\n", len + 1);
HeapFree(GetProcessHeap(), 0, strA);
return 0;
}
如果我提供一个由偶数个 WCHAR 组成的输入字符串,例如Hello!
,我得到:
wlen: 6
wstr[6] == 0
wstr[7] == 0 /* Where does this come from? */
len: 6 chars required
written: 6
Hello!
strA[6] == 0
strA[7] == 0 /* Where does this come from? */
但是如果我提供一个包含奇数个 WCHAR 的字符串,例如Hello
,我只得到:
wlen: 5
wstr[5] == 0
len: 5 chars required
written: 5
Hello
strA[5] == 0
为什么在 wstr[len+1]
和 str[len+1]
处多了一个空终止符?据我所知,没有为 ASCII 字符串中的第二个 NUL 分配足够的内存。
strA = HeapAlloc(GetProcessHeap(), 0, len + 1);
strA[i]
的有效索引 i
包括 0
到 len
。这意味着读取 strA[len + 1]
会调用未定义的行为,因为您正在读取超出缓冲区末尾的内容。
当您调用未定义的行为时,允许发生任何事情。一种可能的结果是您未定义的行为导致您读取值为 0
.
char
同样,在这之后
wlen = lstrlenW(wstr);
您知道 wstr[i]
的有效索引 i
包含 0
到 wlen
。所以再次阅读 wstr[wlen + 1]
.
简单地说,停止读取超出缓冲区的末尾。
您将错误的长度值传递给 WideCharToMultiByte
。应该是:
UINT cp = GetConsoleOutputCP();
len = WideCharToMultiByte(cp, 0, wstr, -1, NULL, 0, NULL, NULL);
和
written = WideCharToMultiByte(cp, 0, wstr, -1, strA, len+1, NULL, NULL);