这些是MultiByteToWideChar()和WideCharToMultiByte()的空终止符规则吗?我不太了解MSDN

时间:2015-04-10 08:05:18

标签: winapi encoding

我正在努力确保我的UTF-8和UTF-16之间的转换代码在空终止符方面是正确的。

MultiByteToWideChar()的情况下,我理解如果您将输出缓冲区大小设置为0,则会获得字符数<包含终止空值。我的问题是:您是否将计数包括终止空值作为新的缓冲区大小,并与计数包括终止空值进行比较?或者换句话说,这是正确的吗?

n = MultiByteToWideChar(..., NULL, 0);
if (MultiByteToWideChar(..., buf, n) != n) error();

我猜测输入缓冲区大小下的模糊

  

如果此参数设置为正整数,则该函数将精确处理指定的字节数。如果提供的大小不包含终止空字符,则生成的Unicode字符串不以空值终止,并且返回的长度不包括此字符。

,输入缓冲区大小为-1,答案是肯定的;是这样吗?

对于WideCharToMultiByte(),我根本不确定null终止符。如果我为输出缓冲区计数传递0,返回的计数是否包含空终止符?对于实际转换,我是否说输出缓冲区的大小包括空终止符?返回值是否包含空终止符?

我当前的代码用no,no和no(分别)回答这些。这似乎有效,但我宁愿不相信那些偶然起作用的代码。我的唯一提示是以下模糊:

  

如果此参数为-1,则该函数处理整个输入字符串,包括终止空字符。因此,生成的字符串具有终止空字符,函数返回的长度包括该字符。

所以我认为答案真的是肯定的,是的,是的,但我还是不完全确定。

感谢。

为了更好的衡量,这是我的代码:

// note: assume logLastError() calls DebugBreak() and that uiAlloc() aborts on failure

#define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz)

WCHAR *toUTF16(const char *str)
{
    WCHAR *wstr;
    int n;

    n = MBTWC(str, NULL, 0);
    if (n == 0)
        logLastError("error figuring out number of characters to convert to in toUTF16()");
    wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]");
    // TODO verify return includes null terminator
    if (MBTWC(str, wstr, n) != n)
        logLastError("error converting from UTF-8 to UTF-16 in toUTF16()");
    return wstr;
}

#define WCTMB(wstr, str, bufsiz) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, bufsiz, NULL, FALSE)

char *toUTF8(const WCHAR *wstr)
{
    char *str;
    int n;

    n = WCTMB(wstr, NULL, 0);
    if (n == 0)
        logLastError("error figuring out number of characters to convert to in toUTF8()");
    // TODO does n include the null terminator?
    str = (char *) uiAlloc((n + 1) * sizeof (char), "char[]");
    if (WCTMB(wstr, str, n + 1) != n)
        logLastError("error converting from UTF-16 to UTF-8 in toUTFF8()");
    return str;
}

1 个答案:

答案 0 :(得分:1)

MultiByteToWideChar返回值的文档说:

  

如果函数成功且cchWideChar为0,则返回值是lpWideCharStr指示的缓冲区所需的大小(以字符为单位)。

那么,对你的问题。

  

如果我为输出缓冲区计数传递0,返回的计数是否包含空终止符?

是的,如果您将-1传递给cbMultiByte。如果你通过了strlen(lpMultiByteStr),那就没有。

  

对于实际转换,我是否说输出缓冲区的大小是否包含空终止符?

如果您希望缓冲区以空值终止,则为“是”,否则为“否”。


所以,完成了:

n = MultiByteToWideChar(..., -1, NULL, 0);

如果您希望缓冲区以空值终止,则可以选择分配长度为n的缓冲区;如果您不希望以空值终止,则可以选择分配长度为n-1的缓冲区。显然,您需要将nn-1作为cchWideChar参数传递,以匹配缓冲区的实际长度。


查看代码,很清楚您要创建以null结尾的缓冲区。您的toUTF16代码是正确的。您的toUTF8代码不是。您应该使用与toUTF16中相同的长度处理代码。更重要的是,WideCharToMultiByte的最终参数有点不精确。它是指向布尔值的指针。代码应该是:

#define WCTMB(wstr, str, bufsiz) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, bufsiz, NULL, NULL)

char *toUTF8(const WCHAR *wstr)
{
    char *str;
    int n;

    n = WCTMB(wstr, NULL, 0);
    if (n == 0)
        logLastError("error figuring out number of characters to convert to in toUTF8()");
    str = (char *) uiAlloc(n * sizeof (char), "char[]");
    if (WCTMB(wstr, str, n) != n)
        logLastError("error converting from UTF-16 to UTF-8 in toUTFF8()");
    return str;
}