你如何正确使用WideCharToMultiByte

Obe*_*ane 60 c++ unicode character-encoding codepages

我已经阅读了有关WideCharToMultiByte的文档,但我坚持这个参数:

lpMultiByteStr
[out] Pointer to a buffer that receives the converted string.
Run Code Online (Sandbox Code Playgroud)

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

tfi*_*iga 119

这里有几个函数(基于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;
}
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,在C++ 11之前,std :: string和std :: wstring并不能保证它们的内存是连续的. (8认同)
  • 我严重怀疑有没有商业上可用的stl实现没有连续的向量.第一个C++规范中不需要连续内存这一事实是一种疏忽:http://herbsutter.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/ (3认同)
  • @Swift c_str() 保证返回一个指向连续缓冲区的指针,但在 C++11 之前,这不能保证与字符串的内部表示相同。 (3认同)
  • 这如何处理非英语字母,例如斯堪的纳维亚语 ÅåÄäÖöÆæØø?从我所见,它变得乱码。:-( (3认同)
  • @tfinniga前面的评论是关于**字符串**,而不是向量。尽管在所有实际实现中,字符串[在字符串中都是连续的](http://stackoverflow.com/questions/1986966/does- s0指向标准字符串中的连续字符)。 (2认同)
  • 自从 C++17 弃用 `<codecvt>` 以来,类似的事情已经变得有些强制性。示例:/sf/ask/3970640551/ (2认同)
  • 我不建议使用 `(int)wstr.size()`,它无法在字符串上放置 `\0` 终止符。相反,只需传递 -1 即可让函数自动检测字符串长度。 (2认同)

Mic*_*urr 32

详细阐述Brian R. Bondy提供的答案:这是一个示例,说明为什么不能简单地将输出缓冲区的大小调整为源字符串中的宽字符数:

#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);
}
Run Code Online (Sandbox Code Playgroud)

并输出:

Wide chars in wcsString: 6
Bytes required for CP950 encoding (excluding NUL terminator): 12
Bytes required for UTF8 encoding (excluding NUL terminator): 18
Run Code Online (Sandbox Code Playgroud)

  • 代码页/编码转换的一个重要且经常被忽视的方面的一个很好的例子! (3认同)
  • @ Error454:他们在2008年没有评论.只是标记它. (3认同)

Bri*_*ndy 18

您可以通过创建新的char数组来使用lpMultiByteStr [out]参数.然后传入此char数组以使其填充.您只需要初始化字符串+ 1的长度,以便在转换后可以使用空终止字符串.

以下是一些有用的辅助函数,它们显示了所有参数的用法.

#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;
}
Run Code Online (Sandbox Code Playgroud)

-

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

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

//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;
}
Run Code Online (Sandbox Code Playgroud)

  • 代码应考虑到多字节字符串中所需的字节数可能大于宽字符串中的字符数.单个宽字符可能会在多字节字符串中产生2个或更多字节,具体取决于所涉及的编码. (5认同)
  • 要获得转换所需的大小,请调用WideCharToMultiByte,并将0作为目标缓冲区的大小.然后它将返回目标缓冲区大小所需的字节数. (3认同)