一、引言
学习到 《Windows 核心编程》(第五版)P28 的时候,看到了作者对于多字节字符串与宽字符字符串相互转换的精妙的描述,忍不住写了一个 Demo 来整理作者的思路。
联想到在实际工作中,多字节字符串与宽字符字符串的相关转换是非常常见的,并且对于 MultiByteToWideChar 和 WideCharToMultiByte 的函数存在滥用误用的情况,因此认真整理了一下。
二、实例 Demo
在参考了作者对于 MultiByteToWideChar 函数调用的五个步骤后,我类似的整理了 WideCharToMultiByte 函数调用的五个步骤,这两者其实非常相似,不同点在于:
1. MultiByteToWideChar 返回宽字符数,而 WideCharToMultiByte 返回的是字节数,而这影响到了我们分配内存的工作
2. WideCharToMultiByte 函数比 MultiByteToWideChar 多了两个参数,具体可以查看 API 文档,这里这两个参数在实际工作中很少能够遇见,一般都使用 NULL 填充
以下是我详细的 Demo 代码:
#include <iostream>
#include <cstdlib>
#include <windows.h>
int main()
{
// 将一个多字节字符串转换为 Unicode 形式的步骤
// int MultiByteToWideChar (
// UINT uCodePage,
// DWORD dwFlags,
// PCSTR pMultiByteStr,
// int cbMultiByte,
// PWSTR pWideCharStr,
// int cchWideChar);
// 1. 调用 MultiByteToWideChar,为 pWideCharStr 参数传入 NULL,
// 为 cchWideChar 参数传入 0, ,为 cbMultiByte 参数传入 -1
char* szMultiByteStr = "hello world";
INT nChCount = MultiByteToWideChar(CP_ACP, 0, szMultiByteStr, -1, NULL, 0);
// 2. 分配一块足以容纳转换后的 Unicode 字符串的内存。它的大小是上
// 一个 MultiByteToWideChar 调用的返回值乘以 sizeof(wchar_t)
wchar_t* szWideCharStr = new wchar_t[nChCount];
wmemset(szWideCharStr, 0, nChCount);
// 3. 再次调用 MultiByteToWideChar,这一次将缓冲区地址作为 pWideCharStr
// 参数的值传入,将第一次 MultiByteToWideChar 调用的返回值乘以 sizeof(wchar_t)
// 后得到的大小作为 cchWideChar 参数的传入
MultiByteToWideChar(CP_ACP, 0, szMultiByteStr, -1, szWideCharStr, nChCount * sizeof(wchar_t));
// 4. 使用转换后的字符串
std::wcout << szWideCharStr << std::endl;
// 5. 释放 Unicode 字符串占用的内存块
delete[] szWideCharStr;
// 将一个宽字符字符串转换为多字节字符串
// int WideCharToMultiByte(
// UINT uCodePatge,
// DWORD dwFlags,
// PCWSTR pWideCharStr,
// int cchWideChar,
// PSTR pMultiByteStr,
// int cbMultiByte,
// PCSTR pDefaultChar,
// PBOOL pfUseDefaultChar);
// 1. 调用 WideCharToMultiByte,为 pMultiByteStr 参数传入 NULL,
// 为 cbMultiByte 参数传入 0,为 cchWideChar 参数传入 -1
wchar_t* szWideCharStr2 = L"wang ying";
INT nCbCount = WideCharToMultiByte(CP_ACP, 0, szWideCharStr2, -1, NULL, 0, NULL, NULL);
// 2. 分配一块足以容纳转换后的多字节字符串的内存。它的大小直接就是上
// 一次调用 WideCharToMultiByte 的返回值(直接就是字节数)
char* szMultiByte2 = new char[nCbCount];
memset(szMultiByte2, 0, nCbCount);
// 3. 再次调用 WideCharToMultiByte,这一次将缓冲区地址作为 pMultiByteStr
// 参数的值传入,将第一次 WideCharToMultiByte 调用的返回值作为 cbMultiByte
// 参数的值传入
WideCharToMultiByte(CP_ACP, 0, szWideCharStr2, -1, szMultiByte2, nCbCount, NULL, NULL);
// 4. 使用转换后的字符串
std::cout << szMultiByte2 << std::endl;
// 5. 释放多字节字符串占用的内存块
delete[] szMultiByte2;
// 窗口暂停显示
system("pause");
return 0;
}
三、总结
从前一直对于 MultiByteToWideChar 和 WideCharToMultiByte 这两个函数敬而远之,甚至于不想去仔仔细细搞懂这两个函数的具体用法(因为参数看上去非常多,而且两个函数比较绕)。
但是通过了 《Window核心编程》(第五版)作者这里的五个步骤的描述,我已经能够清晰的分清楚两个函数的区别,并且产生了比较易用理解的印象,这是难能可贵的。
最后,Jeffrey Richter 真是一个大神啊,膜拜膜拜:)