多字节和宽字符之间的转换方法

274 阅读5分钟

在 Windows 中,宽字符字符串使用的是 UTF16 编码,而多字节字符串使用的是 GB2312 编码,两者无法进行直接赋值。所以,在某些情况下需要对它们进行转换。本人大致用过以下几种转换方法。

使用 Windows 提供的 WideCharToMultiByte 系列函数进行转换

使用 WideCharToMultiByte 可以将宽字符转换成多字节,而使用 MultiByteToWideChar 可以将多字节转换成宽字符。使用这两个函数需要包含 Windows.h 这个头文件。代码例子如下:

  • 宽字符转换成多字节
int _tmain(int argc, _TCHAR* argv[])
{
	WCHAR wideChar[] = L"我是一个忧伤的字符串。";
	// 1. 首先指定接收转换结果的指针
	char * multiByte;
	// 2. 然后第一次调用函数,获取存储转换结果所需缓冲区的大小
	int len = WideCharToMultiByte(CP_ACP, NULL,
		wideChar,	// 要被转换的宽字符字符串
		-1,			// 要转换的长度,设为-1表示转换整串
		NULL,		// 第一次调用,接收缓冲区设置为NULL
		NULL,		// 接收缓冲区的大小,设为NULL表示让函数返回需要的大小
		NULL, NULL);
	// 3. 根据返回的结果创建合适大小的缓冲区
	multiByte = new char[len];
	// 4. 第二次调用函数,进行真正的转换
	WideCharToMultiByte(CP_ACP, NULL,
		wideChar,	// 要被转换的宽字符字符串
		-1,			// 要转换的长度,设为-1表示转换整串
		multiByte,	// 第二次调用,设为接收转换结果的缓冲区指针
		len,		// 设定接收缓冲区大小
		NULL, NULL);
	// 5. 转换结束,可以输出查看转换结果
	cout << multiByte << endl;
	delete multiByte;
 
	system("pause");
	return 0;
}
  • 多字节转换成宽字符
int _tmain(int argc, _TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	char multiByte[] = "我是一个忧伤的字符串。";
	// 1. 首先指定接收转换结果的指针
	WCHAR * wideChar;
	// 2. 然后第一次调用函数,获取存储转换结果所需缓冲区的大小
	int len = MultiByteToWideChar(CP_ACP, NULL,
		multiByte,		// 要被转换的多字节字符串
		-1,				// 要转换的长度,设为-1表示转换整串
		NULL,			// 第一次调用,接收缓冲区设为NULL
		0);				// 接收缓冲区长度,设为0代表函数返回需要的长度
	// 3. 根据返回的结果创建合适大小的缓冲区
	wideChar = new WCHAR[len];
	// 4. 第二次调用函数,进行真正的转换
	MultiByteToWideChar(CP_ACP, NULL,
		multiByte,		// 要被转换的多字节字符串
		-1,				// 要转换的长度,设为-1表示转换整串
		wideChar,		// 第二次调用,设为接收转换结果的缓冲区
		len);			// 设置接收缓冲区的大小
	// 5. 转换结束,可以输出查看转换结果
	wcout << wideChar << endl;
	delete wideChar;
 
	system("pause");
	return 0;
}

使用 wprintf 系列函数进行转换

使用 wprintfA 函数可以很简单就将宽字符转换成多字节。代码例子如下:

int _tmain(int argc, _TCHAR* argv[])
{
	WCHAR * wideChar = L"我是一个忧伤的字符串。";
	char multiByte[MAX_PATH];
	// 一个函数搞定
	// 第一个参数是接收转换的结果
	// 第二个参数设为 "%S" (注意S大写)
	// 第三个参数是要转换的内容
	wsprintfA(multiByte, "%S", wideChar);
	cout << multiByte << endl;
 
	system("pause");
	return 0;
}

使用 wprintfW 函数可以很简单就将多字节转换成宽字符。代码例子如下:

int _tmain(int argc, _TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	char * multiByte = "我是一个忧伤的字符串。";
	WCHAR wideChar[MAX_PATH];
	// 一个函数搞定
	// 第一个参数是接收转换的结果
	// 第二个参数设为 "%S" (注意S大写)
	// 第三个参数是要转换的内容
	wsprintfW(wideChar, L"%S", multiByte);
	wcout << wideChar << endl;
 
	system("pause");
	return 0;
}

使用 wcstombs 系列函数进行转换

wcstombs 可以实现从宽字符到多字节的转换,但是编译器会报警建议使用安全的 wcstombs_s 函数替代(此类报警可以通过 #pragma warning(disable:4996) 进行关闭)。代码例子如下:

int _tmain(int argc, _TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	WCHAR * wideChar = L"我是一个很忧伤的字符串。";
	char multiByte[MAX_PATH];
	size_t numConverted = 0;
	// 第一个参数为返回成功转换的字节数,如果不需要可以设为NULL
	// 第二个参数为接收转换结果的缓冲区
	// 第三个参数为要转换的内容
	// 第四个参数为要转换的长度,单位是字节数
	wcstombs_s(&numConverted, multiByte, wideChar, -1);
	cout << "成功转换" << numConverted << "个字节:" << multiByte << endl;
 
	system("pause");
	return 0;
}

同样,相反过程的函数就是 mbstowcs,对应的安全版本的函数为 mbstowcs_s,代码例子如下:

int _tmain(int argc, _TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	char * multiByte = "我是一个很忧伤的字符串。";
	wchar_t wideChar[MAX_PATH];
	size_t numConverted = 0;
	// 第一个参数为返回成功转换的字节数,如果不需要可以设为NULL
	// 第二个参数为接收转换结果的缓冲区
	// 第三个参数为要转换的内容
	// 第四个参数为要转换的长度,单位是WCHAR长度的个数
	mbstowcs_s(&numConverted, wideChar, multiByte, -1);
	wcout << L"成功转换" << numConverted << L"个字节:" << wideChar << endl;
 
	system("pause");
	return 0;
}

使用ATL的W2A和A2W宏进行转换

ATLW2AA2W 宏用起来是最方便的,需要包含头文件 atlconv.h。代码例子如下:

int _tmain(int argc, _TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	char * multiByte = "我是忧伤的多字节字符串。";
	wchar_t * wideChar = L"我是忧伤的宽字符字符串。";
	// 在使用 W2A 和 A2W 宏之前需要加 USES_CONVERSION
	USES_CONVERSION;
	// W2A 完成宽字符到多字节的转换
	cout << W2A(wideChar) << endl;
	// A2W 完成多字节到宽字符的转换
	wcout << A2W(multiByte) << endl;
 
	system("pause");
	return 0;
}