【问题标题】:Are these the null-terminator rules for MultiByteToWideChar() and WideCharToMultiByte()? I don't quite understand MSDN这些是 MultiByteToWideChar() 和 WideCharToMultiByte() 的空终止符规则吗?我不太明白 MSDN
【发布时间】:2015-04-10 08:05:18
【问题描述】:

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

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

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

我从输入缓冲区大小下的简介中猜测

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

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

对于WideCharToMultiByte(),我完全不确定空终止符。如果我为输出缓冲区计数传递 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;
}

【问题讨论】:

    标签: winapi encoding


    【解决方案1】:

    MultiByteToWideChar 返回值的文档说:

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

    所以,对于你的问题。

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

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

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

    如果您希望缓冲区以空值终止,则是,如果您不这样做,则否。


    所以,已经完成了:

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

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


    查看您的代码,很明显您想要创建以空值结尾的缓冲区。 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;
    }
    

    【讨论】:

    • 所以返回应该等于输出大小,WideCharToMultiByte() 遵循相同的规则。谢谢!还要感谢您发现最后一个参数问题;我用-Wall -Wextra 编译,我很惊讶 gcc 没有抓住它......
    猜你喜欢
    • 2011-08-25
    • 1970-01-01
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    相关资源
    最近更新 更多