多字节 unicode和utf-8的转换

本来在网上能找到很多这方面的代码,但很多都是转帖,且很多细节让人理解起来很别扭,估计有的
转帖的也是不知所云。

虽说就两个Windows API的调用,但只有自己去写代码测试研究,才真正领会了这些细节。文中注释有写的不当的欢迎指正。

下面是我写的测试程序:

#include "stdafx.h"
#include <windows.h>
#include <locale.h>

/* MultiByteToWideChar和WideCharToMultiByte每个都调用了两次,
   第一次转换是为了得到转换后所需的长度 */
void TestMultiToWideChar()
{
	do 
	{
		/* 这里的szBuffer中的内容在中文Windows下默认用的是GB2312编码,也可以说是MBCS编码,
		有几个概念一直让人模糊,今天算是搞清楚了,GB2312编码,MBCS编码,ANSI编码,
		其实这三种编码是同一种编码格式,GB2312是专门针对中文的,是ANSI编码在中文系统下
		的别称,在日文系统下,ANSI就叫JIS了,而MBCS意思就是多字节编码,对于ASCII码,采用一个字节,
		对于中文采用两个字节,所以也叫MBCS,还有DBCS,在中文Windows下,就是GB2312,双字节编码。
		哎,名字太多了 */
		char szBuffer[32] = "赵武涛"; 
		printf("szBuffer = %s\n", szBuffer);

		/* MSDN关于CP_ACP的阐释: The current system Windows ANSI code page.
		 注意这里的CP_ACP表示转换要用到的CodePage类型,因为这里的szBuffer在中文Windows下
		是GB2312编码,所以这里用ANSI这个codePage就行了,GB2312就是ANSI编码的一种, 
		MultiByteToWideChar和WideCharToMultiByte这两个API的参数意义参考MSDN即可 */

		/* 第四个参数设为-1,MSDN里的解释为If this parameter is -1, the function processes the entire 
		input string, including the null terminator. Therefore, the resulting wide character string 
		has a null terminator, and the length returned by the function includes the terminating null character.
		也就是说,如果设为-1, 表示系统处理整个szBuffer里的内容,包括NULL结束符,并且返回值包括一个NULL结束符占的长度。
		最后一个参数设为0,MSDN里的解释为If this parameter is set to 0, the function returns the required buffer
		size for lpMultiByteStr and makes no use of the output parameter itself. 
		也就是说,设为0表示返回值是转换所需的WCHAR缓冲区长度,包括NULL结束符*/

		int nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, NULL, 0);
		if (nLen == 0) // 这里的nlen的长度以WCHAR为单位,及两个字节为单位
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		WCHAR *pwszBuffer = new WCHAR[nLen];
		nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, pwszBuffer, nLen);
		if (nLen == 0)
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		// pwszBuffer在内存中的字节序为75 8d 66 6b 9b 6d 00 00,结尾的NULL字符也占两个字节
		wprintf(L"pwszBuffer = %s\n", pwszBuffer);

		delete []pwszBuffer;
	} while (false);
}

void TestWideToMultiChar()
{
	do 
	{
		WCHAR wszBuffer[32] = L"赵武涛";

		int nLen = WideCharToMultiByte(CP_ACP, 0, wszBuffer, -1, NULL, 0, NULL, NULL);
		if (nLen == 0) // 这里的nLen以一个字节为单位
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		char *pszBuffer = new char[nLen];
		nLen = WideCharToMultiByte(CP_ACP, 0, wszBuffer, -1, pszBuffer, nLen, NULL, NULL);
		if (nLen == 0)
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		} 

		printf("pszBuffer = %s\n", pszBuffer);
		delete []pszBuffer;
	} while (false);
}

/* 这个函数间接囊括了UNICODE到UTF8的转换和UTF8到UNICODE的转换,
   网上很多帖子对这个转换为什么要进行两次转换基本没有说明 */
void TestMultiToUTF8()
{
	do 
	{
		/* 这个方法里,要先把GB2312字符串转换成UNICODE编码,再用UNICODE转UTF8,
		因为没有一种CodePage可以直接将GB2312转换成UTF8,所以这里就要先转UNICODE,再
		通过CP_UTF8进行转换,UTF8可以视为一种变长的多字节编码,虽说UTF8是对UNICODE字符集
		执行的一种编码形式,但其编码是采用1~6字节变长编码,所以可以视为多字节编码 */
		char szBuffer[32] = "赵武涛";
		int nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, NULL, 0);
		if (nLen == 0) // nLen is in WCHAR values
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		WCHAR *pwszBuffer = new WCHAR[nLen];
		nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, pwszBuffer, nLen);
		if (nLen == 0)
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		wprintf(L"pwszBuffer = %s\n", pwszBuffer);

		// 再转换成UTF-8编码
		// 刚开始用这两个API时,对这个CodePage的认识很模糊,为什么有的地方用CP_UTF8,有的用CP_ACP
		nLen = WideCharToMultiByte(CP_UTF8, 0, pwszBuffer, -1, NULL, 0, NULL, NULL);
		if (nLen == 0) // nLen is in bytes values
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		char *pszBuffer = new char[nLen];
		nLen = WideCharToMultiByte(CP_UTF8, 0, pwszBuffer, -1, pszBuffer, nLen, NULL, NULL);
		if (nLen == 0)
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		} 

		/* 下面的代码只是测试,再将此UTF-8字符串转换成Unicode,看看输出结果, 注意
		这里用的CodePage还是CP_UTF8,因为只有这个CodePage能在UTF8和Unicode间进行互转换,它
		表示的意思并不是转换目标的编码,而是当前转换需要用到这个CodePage */
		nLen = MultiByteToWideChar(CP_UTF8, 0, pszBuffer, -1, NULL, 0);
		if (nLen == 0) // nLen is in bytes values
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		WCHAR *pwszBuf2 = new WCHAR[nLen];
		nLen = MultiByteToWideChar(CP_UTF8, 0, pszBuffer, -1, pwszBuf2, nLen);
		if (nLen == 0) // nLen is in bytes values
		{
			printf("errorCode = %d\n", GetLastError());
			break;
		}

		wprintf(L"pwszBuf2 = %s\n", pwszBuf2);
		delete []pwszBuf2;
		delete []pwszBuffer;
	} while (false);
}

int _tmain(int argc, _TCHAR* argv[])
{
	// 这里设置locale是为了wprintf能正确的输出宽字符类型的中文
	setlocale(LC_ALL, "chs");
	
	TestMultiToWideChar();

	TestWideToMultiChar();

	TestMultiToUTF8();

	return 0;
}




  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值