你如何正确使用 WideCharToMultiByte

Posted

技术标签:

【中文标题】你如何正确使用 WideCharToMultiByte【英文标题】:How do you properly use WideCharToMultiByte 【发布时间】:2010-09-17 23:23:39 【问题描述】:

我已经阅读了WideCharToMultiByte 上的文档,但我被这个参数卡住了:

lpMultiByteStr
[out] Pointer to a buffer that receives the converted string.

我不太确定如何正确初始化变量并将其输入函数

【问题讨论】:

您是否有任何理由似乎提出问题但不接受任何答案?在这些网站上,通过反馈奖励好的答案通常是一种很好的做法,以表彰人们在回答您的问题时投入的时间。您在下面得到了一些非常好的答案...(轻推) 【参考方案1】:

您可以通过创建一个新的 char 数组来使用 lpMultiByteStr [out] 参数。然后你传入这个 char 数组来填充它。只需要初始化字符串的长度+1,这样转换后就可以有一个以null结尾的字符串了。

这里有几个有用的帮助函数,它们显示了所有参数的用法。

#include <string>

std::string wstrtostr(const std::wstring &wstr)

    // Convert a Unicode string to an ASCII string
    std::string strTo;
    char *szTo = new char[wstr.length() + 1];
    szTo[wstr.size()] = '\0';
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL);
    strTo = szTo;
    delete[] szTo;
    return strTo;


std::wstring strtowstr(const std::string &str)

    // Convert an ASCII string to a Unicode String
    std::wstring wstrTo;
    wchar_t *wszTo = new wchar_t[str.length() + 1];
    wszTo[str.size()] = L'\0';
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wszTo, (int)str.length());
    wstrTo = wszTo;
    delete[] wszTo;
    return wstrTo;

--

当你在文档中看到它有一个指向类型指针的参数并且他们告诉你它是一个输出变量时,你会想要创建那个类型,然后传入一个指向它的指针。该函数将使用该指针来填充您的变量。

所以你可以更好地理解这一点:

//pX is an out parameter, it fills your variable with 10.
void fillXWith10(int *pX)

  *pX = 10;


int main(int argc, char ** argv)

  int X;
  fillXWith10(&X);
  return 0;

【讨论】:

代码应该考虑到多字节char字符串中所需的字节数可能比宽字符串中的字符数多。根据所涉及的编码,单个宽字符可能会导致多字节 char 字符串中包含 2 个或更多字节。 亚洲字符作为示例出现在脑海中,但这实际上取决于用于转换的代码页。在您的示例中,这可能不是问题,因为任何非 ANSI 字符都将替换为问号。 要获得转换所需的大小,调用WideCharToMultiByte,目标缓冲区大小为0。然后它将返回目标缓冲区大小所需的字节数。 是否有可移植的方式,即 POSIX 方式来做到这一点? WideCharToMultiByte 是一个 Windows 函数。 在使用类似 gb2312 的代码时,字节数或宽字符数会被此代码中断。【参考方案2】:

详细说明 Brian R. Bondy 提供的 answer:以下示例说明了为什么不能简单地将输出缓冲区的大小调整为源字符串中的宽字符数:

#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>

/* string consisting of several Asian characters */
wchar_t wcsString[] = L"\u9580\u961c\u9640\u963f\u963b\u9644";

int main() 


    size_t wcsChars = wcslen( wcsString);

    size_t sizeRequired = WideCharToMultiByte( 950, 0, wcsString, -1, 
                                               NULL, 0,  NULL, NULL);

    printf( "Wide chars in wcsString: %u\n", wcsChars);
    printf( "Bytes required for CP950 encoding (excluding NUL terminator): %u\n",
             sizeRequired-1);

    sizeRequired = WideCharToMultiByte( CP_UTF8, 0, wcsString, -1,
                                        NULL, 0,  NULL, NULL);
    printf( "Bytes required for UTF8 encoding (excluding NUL terminator): %u\n",
             sizeRequired-1);

还有输出:

Wide chars in wcsString: 6
Bytes required for CP950 encoding (excluding NUL terminator): 12
Bytes required for UTF8 encoding (excluding NUL terminator): 18

【讨论】:

代码页/编码转换的一个重要且经常被忽视的方面的绝佳示例! -1 OP 向 lpMultiByteStr 参数寻求帮助。这个答案没有回答 OP,它与另一个发布的答案相切。 @Error454:他们在 2008 年没有 cmets。只需标记它。 +1 表示排除 null,返回的 sizeRequired 包含 null 的空间,所以正确初始化 lpMultiByteStr 必须考虑到这一点【参考方案3】:

这里有几个函数(基于 Brian Bondy 的示例),它们使用 WideCharToMultiByte 和 MultiByteToWideChar 在 std::wstring 和 std::string 之间进行转换,使用 utf8 不会丢失任何数据。

// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring &wstr)

    if( wstr.empty() ) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo( size_needed, 0 );
    WideCharToMultiByte                  (CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;


// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str)

    if( str.empty() ) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo( size_needed, 0 );
    MultiByteToWideChar                  (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;

【讨论】:

需要注意的是,在 C++11 之前,std::string 和 std::wstring 不能保证它们的内存是连续的。 我严重怀疑是否存在没有连续向量的商用 stl 实现。第一个 C++ 规范中不需要连续内存的事实是一个疏忽:herbsutter.com/2008/04/07/… @tfinniga 之前的评论是关于字符串,而不是向量。字符串在 C++98 中不能保证是连续的(不是 Sutter 提到的结果),尽管所有现实世界的实现 make them contiguous. @Swift c_str() 保证返回一个指向连续缓冲区的指针,但在 C++11 之前,这不能保证与字符串的内部表示相同。 如何处理非英文字母,例如斯堪的纳维亚语 ÅåÄäÖöÆæØø?据我所见,它变得乱码。 :-(【参考方案4】:

这是WideCharToMultiByteMultiByteToWideCharC 实现。 在这两种情况下,我都会确保将null 字符添加到目标缓冲区的末尾。

如果显式指定输入字符串长度而不使用终止空字符,MultiByteToWideChar 不会以空值终止输出字符串。

如果输入字符串长度明确指定且没有终止空字符,WideCharToMultiByte 不会以空值终止输出字符串。

即使有人指定-1 并传入null 终止的字符串,我仍然为额外的null 字符分配足够的空间,因为对于我的用例来说这不是问题。

wchar_t* utf8_decode( const char* str, int nbytes )     
    int nchars = 0;
    if ( ( nchars = MultiByteToWideChar( CP_UTF8, 
        MB_ERR_INVALID_CHARS, str, nbytes, NULL, 0 ) ) == 0 ) 
        return NULL;
    

    wchar_t* wstr = NULL;
    if ( !( wstr = malloc( ( ( size_t )nchars + 1 ) * sizeof( wchar_t ) ) ) ) 
        return NULL;
    

    wstr[ nchars ] = L'\0';
    if ( MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, 
        str, nbytes, wstr, ( size_t )nchars ) == 0 ) 
        free( wstr );
        return NULL;
    
    return wstr;
 


char* utf8_encode( const wchar_t* wstr, int nchars ) 
    int nbytes = 0;
    if ( ( nbytes = WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, 
        wstr, nchars, NULL, 0, NULL, NULL ) ) == 0 ) 
        return NULL;
    

    char* str = NULL;
    if ( !( str = malloc( ( size_t )nbytes + 1 ) ) ) 
        return NULL;
    

    str[ nbytes ] = '\0';
    if ( WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, 
        wstr, nchars, str, nbytes, NULL, NULL ) == 0 ) 
        free( str );
        return NULL;
    
    return str;

【讨论】:

以上是关于你如何正确使用 WideCharToMultiByte的主要内容,如果未能解决你的问题,请参考以下文章

📃如何正确的提问

你如何正确地承诺请求?

如何正确使用开源项目?

从后台线程使用 Core Data 托管上下文......你如何正确地做到这一点?

你如何正确地用 NULL 更新 mysql 字段?

如何正确使用长尾关键词?站长工具长尾词挖掘