MultiByteToWideChar使用垃圾终止输出缓冲区,但报告没有错误.为什么?

Arc*_*des 1 c c++ unicode winapi visual-studio-2012

在前几天开发程序时,我不得不将ASCII字符串转换为Unicode字符串.顺便说一下,我正在使用Visual Studio 2012在Windows上工作.我注意到Win32函数MultiByteToWideChar有一些奇怪的行为,我无法理清.我写了一些测试代码,如下:

int main()
{
    /* Create const test string */
    char str[] = "test string";

    /* Create empty wchar_t buffer to hold Unicode form of above string, and initialize (zero) it */
    wchar_t *buffer = (wchar_t*) LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t) * strlen(str));

    /* Convert str to Unicode and store in buffer */
    int result = MultiByteToWideChar(CP_UTF8, NULL, str, strlen(str), buffer, strlen(str));
    if (result == 0)
        printf("GetLastError result: %d\n", GetLastError());

    /* Print MultiByteToWideChar result, str's length, and buffer's length */
    printf_s(
        "MultiByteToWideChar result: %d\n"
        "'str' length: %d\n"
        "'buffer' length: %d\n",
        result, strlen(str), wcslen(buffer));

    /* Create a message box to display the Unicode string */
    MessageBoxW(NULL, buffer, L"'buffer' contents", MB_OK);

    /* Also write buffer to file, raw */
    FILE *stream = NULL;
    fopen_s(&stream, "c:\\test.dat", "wb");
    fwrite(buffer, sizeof(wchar_t), wcslen(buffer), stream);
    fclose(stream);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它只是需要一个普通的字符串,创建一个缓冲区来存储Unicode字符串,该转换Unicode字符串到缓冲区看跌期权,并显示了我一些成果,也将缓冲区写入到文件中.

输出:

MultiByteToWideChar result: 11
'str' length: 11
'buffer' length: 16
Run Code Online (Sandbox Code Playgroud)

已经很奇怪了.该函数正在处理C字符串中正确数量的字符,但wcslen报告输出缓冲区比C字符串长!我很确定我也正确分配了缓冲区.

我一直在使用不同大小的字符串长度试过,但总有垃圾结尾,并wcslen始终报告缓冲区的长度是4的倍数.

最后,对于这个特定的字符串("test string"),这是打印到文件的原始缓冲区:

74 00 65 00 73 00 74 00 20 00 73 00 74 00 72 00   t.e.s.t. .s.t.r.
69 00 6E 00 67 00 AB AB AB AB AB AB AB AB EE FE   i.n.g...........
Run Code Online (Sandbox Code Playgroud)

(那是32个字节,或16个Unicode字符.)

最后的10个字节是5个字符; 四个U + ABAB,一个U + FEEE,对我来说毫无意义.

每次尝试转换字符串时都会出现不同的数量.

我有点想法了.任何人?

提前致谢!

Han*_*ant 5

/* Create empty wchar_t buffer to hold Unicode form of above string, and initialize (zero) it */
wchar_t *buffer = (wchar_t*) LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t) * strlen(str));
Run Code Online (Sandbox Code Playgroud)

这确实是问题的起点.strlen(str)的值没有意义,特别是当输入字符串以utf-8编码时.你倾向于偶然逃脱它,因为它通常会创建一个太长的缓冲区,而不是计算一个一个错误.

但你也可以通过正确的方式轻松避免这个错误.您必须两次调用该函数.第一次,为最后一个参数(cchWideChar)传递0.该函数返回缓冲区所需的大小(字符,而不是字节).现在,这足以分配缓冲区在第二次调用函数时传递正确的值.

  • 实际上,如果您知道编码,那么您可以计算出保证不会太小的尺寸.对于UTF-8和UTF-16计数,UTF-8代码单元的数量给出了所需UTF-16代码单元的数量的上限.它可能比必要的大(例如,三个UTF-8代码单元可能对应于单个UTF-16代码单元)但它永远不会小于必要的. (2认同)