多字节 unicode和utf-8的转换

来源:互联网 发布:c语言字符运算 编辑:程序博客网 时间:2024/05/16 10:05

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

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

下面是我写的测试程序:

[cpp] view plaincopy
  1. #include "stdafx.h"  
  2. #include <windows.h>  
  3. #include <locale.h>  
  4.   
  5. /* MultiByteToWideChar和WideCharToMultiByte每个都调用了两次, 
  6.    第一次转换是为了得到转换后所需的长度 */  
  7. void TestMultiToWideChar()  
  8. {  
  9.     do   
  10.     {  
  11.         /* 这里的szBuffer中的内容在中文Windows下默认用的是GB2312编码,也可以说是MBCS编码, 
  12.         有几个概念一直让人模糊,今天算是搞清楚了,GB2312编码,MBCS编码,ANSI编码, 
  13.         其实这三种编码是同一种编码格式,GB2312是专门针对中文的,是ANSI编码在中文系统下 
  14.         的别称,在日文系统下,ANSI就叫JIS了,而MBCS意思就是多字节编码,对于ASCII码,采用一个字节, 
  15.         对于中文采用两个字节,所以也叫MBCS,还有DBCS,在中文Windows下,就是GB2312,双字节编码。 
  16.         哎,名字太多了 */  
  17.         char szBuffer[32] = "赵武涛";   
  18.         printf("szBuffer = %s\n", szBuffer);  
  19.   
  20.         /* MSDN关于CP_ACP的阐释: The current system Windows ANSI code page. 
  21.          注意这里的CP_ACP表示转换要用到的CodePage类型,因为这里的szBuffer在中文Windows下 
  22.         是GB2312编码,所以这里用ANSI这个codePage就行了,GB2312就是ANSI编码的一种,  
  23.         MultiByteToWideChar和WideCharToMultiByte这两个API的参数意义参考MSDN即可 */  
  24.   
  25.         /* 第四个参数设为-1,MSDN里的解释为If this parameter is -1, the function processes the entire  
  26.         input string, including the null terminator. Therefore, the resulting wide character string  
  27.         has a null terminator, and the length returned by the function includes the terminating null character. 
  28.         也就是说,如果设为-1, 表示系统处理整个szBuffer里的内容,包括NULL结束符,并且返回值包括一个NULL结束符占的长度。 
  29.         最后一个参数设为0,MSDN里的解释为If this parameter is set to 0, the function returns the required buffer 
  30.         size for lpMultiByteStr and makes no use of the output parameter itself.  
  31.         也就是说,设为0表示返回值是转换所需的WCHAR缓冲区长度,包括NULL结束符*/  
  32.   
  33.         int nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, NULL, 0);  
  34.         if (nLen == 0) // 这里的nlen的长度以WCHAR为单位,及两个字节为单位  
  35.         {  
  36.             printf("errorCode = %d\n", GetLastError());  
  37.             break;  
  38.         }  
  39.   
  40.         WCHAR *pwszBuffer = new WCHAR[nLen];  
  41.         nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, pwszBuffer, nLen);  
  42.         if (nLen == 0)  
  43.         {  
  44.             printf("errorCode = %d\n", GetLastError());  
  45.             break;  
  46.         }  
  47.   
  48.         // pwszBuffer在内存中的字节序为75 8d 66 6b 9b 6d 00 00,结尾的NULL字符也占两个字节  
  49.         wprintf(L"pwszBuffer = %s\n", pwszBuffer);  
  50.   
  51.         delete []pwszBuffer;  
  52.     } while (false);  
  53. }  
  54.   
  55. void TestWideToMultiChar()  
  56. {  
  57.     do   
  58.     {  
  59.         WCHAR wszBuffer[32] = L"赵武涛";  
  60.   
  61.         int nLen = WideCharToMultiByte(CP_ACP, 0, wszBuffer, -1, NULL, 0, NULL, NULL);  
  62.         if (nLen == 0) // 这里的nLen以一个字节为单位  
  63.         {  
  64.             printf("errorCode = %d\n", GetLastError());  
  65.             break;  
  66.         }  
  67.   
  68.         char *pszBuffer = new char[nLen];  
  69.         nLen = WideCharToMultiByte(CP_ACP, 0, wszBuffer, -1, pszBuffer, nLen, NULL, NULL);  
  70.         if (nLen == 0)  
  71.         {  
  72.             printf("errorCode = %d\n", GetLastError());  
  73.             break;  
  74.         }   
  75.   
  76.         printf("pszBuffer = %s\n", pszBuffer);  
  77.         delete []pszBuffer;  
  78.     } while (false);  
  79. }  
  80.   
  81. /* 这个函数间接囊括了UNICODE到UTF8的转换和UTF8到UNICODE的转换, 
  82.    网上很多帖子对这个转换为什么要进行两次转换基本没有说明 */  
  83. void TestMultiToUTF8()  
  84. {  
  85.     do   
  86.     {  
  87.         /* 这个方法里,要先把GB2312字符串转换成UNICODE编码,再用UNICODE转UTF8, 
  88.         因为没有一种CodePage可以直接将GB2312转换成UTF8,所以这里就要先转UNICODE,再 
  89.         通过CP_UTF8进行转换,UTF8可以视为一种变长的多字节编码,虽说UTF8是对UNICODE字符集 
  90.         执行的一种编码形式,但其编码是采用1~6字节变长编码,所以可以视为多字节编码 */  
  91.         char szBuffer[32] = "赵武涛";  
  92.         int nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, NULL, 0);  
  93.         if (nLen == 0) // nLen is in WCHAR values  
  94.         {  
  95.             printf("errorCode = %d\n", GetLastError());  
  96.             break;  
  97.         }  
  98.   
  99.         WCHAR *pwszBuffer = new WCHAR[nLen];  
  100.         nLen = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, pwszBuffer, nLen);  
  101.         if (nLen == 0)  
  102.         {  
  103.             printf("errorCode = %d\n", GetLastError());  
  104.             break;  
  105.         }  
  106.   
  107.         wprintf(L"pwszBuffer = %s\n", pwszBuffer);  
  108.   
  109.         // 再转换成UTF-8编码  
  110.         // 刚开始用这两个API时,对这个CodePage的认识很模糊,为什么有的地方用CP_UTF8,有的用CP_ACP  
  111.         nLen = WideCharToMultiByte(CP_UTF8, 0, pwszBuffer, -1, NULL, 0, NULL, NULL);  
  112.         if (nLen == 0) // nLen is in bytes values  
  113.         {  
  114.             printf("errorCode = %d\n", GetLastError());  
  115.             break;  
  116.         }  
  117.   
  118.         char *pszBuffer = new char[nLen];  
  119.         nLen = WideCharToMultiByte(CP_UTF8, 0, pwszBuffer, -1, pszBuffer, nLen, NULL, NULL);  
  120.         if (nLen == 0)  
  121.         {  
  122.             printf("errorCode = %d\n", GetLastError());  
  123.             break;  
  124.         }   
  125.   
  126.         /* 下面的代码只是测试,再将此UTF-8字符串转换成Unicode,看看输出结果, 注意 
  127.         这里用的CodePage还是CP_UTF8,因为只有这个CodePage能在UTF8和Unicode间进行互转换,它 
  128.         表示的意思并不是转换目标的编码,而是当前转换需要用到这个CodePage */  
  129.         nLen = MultiByteToWideChar(CP_UTF8, 0, pszBuffer, -1, NULL, 0);  
  130.         if (nLen == 0) // nLen is in bytes values  
  131.         {  
  132.             printf("errorCode = %d\n", GetLastError());  
  133.             break;  
  134.         }  
  135.   
  136.         WCHAR *pwszBuf2 = new WCHAR[nLen];  
  137.         nLen = MultiByteToWideChar(CP_UTF8, 0, pszBuffer, -1, pwszBuf2, nLen);  
  138.         if (nLen == 0) // nLen is in bytes values  
  139.         {  
  140.             printf("errorCode = %d\n", GetLastError());  
  141.             break;  
  142.         }  
  143.   
  144.         wprintf(L"pwszBuf2 = %s\n", pwszBuf2);  
  145.         delete []pwszBuf2;  
  146.         delete []pwszBuffer;  
  147.     } while (false);  
  148. }  
  149.   
  150. int _tmain(int argc, _TCHAR* argv[])  
  151. {  
  152.     // 这里设置locale是为了wprintf能正确的输出宽字符类型的中文  
  153.     setlocale(LC_ALL, "chs");  
  154.       
  155.     TestMultiToWideChar();  
  156.   
  157.     TestWideToMultiChar();  
  158.   
  159.     TestMultiToUTF8();  
  160.   
  161.     return 0;  
  162. }  


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 奶奶出钱由孙子抓奖中奖后怎么办 我不想学车了驾校不同意退学怎么办 2017年大学挂科面临退学怎么办 微信重新登录后东西全没了怎么办 宝宝吃鸡蛋过敏全身起红疹怎么办 180在产蛋鸡因断鸡减产怎么办 住友39熔接机熔接损耗大怎么办 支付宝实名认证刷脸失败怎么办 支付宝注册刷脸不是本人怎么办 小学科学只考88分中学怎么办 收银机关机时才上传数据是怎么办 刚做的系统玩cf卡屏怎么办 办健康证的资料掉了怎么办 刚刚办得的健康证掉了怎么办 房子都过户了银行贷不了款怎么办 我要办大病迁出应该怎么办啊? 遗产继承后户口没地迁出怎么办 安徽蒙城怎么办去韩国的签证的 夜间有人私自收停车费应该怎么办 上次摸不到环尾丝这次摸到了怎么办 法院判决书下来后对方不给钱怎么办 法院判决书下来了钱还保全么怎么办 深圳路边泊车不知道泊车编号怎么办 当事人进拘留所了我的工资怎么办 昆明公租房住满5年后怎么办 昆明公租房房子到期缴纳金怎么办 看守所犯人银行卡里钱没用完怎么办 中国邮政迟迟没有把信件寄到怎么办 拘留15天放出来还不肯还钱怎么办 人死在拘留所不让看监控怎么办 家人吸毒可他又不愿强戒怎么办 容留他人吸毒时签了强戒怎么办 拘留后发现被拘留是人大代表怎么办 执行局要拘留人找不到人怎么办 开设赌场罪拘留37天了该怎么办 对治安处罚光罚款不拘留怎么办 打架和解后警察不给消案怎么办 12个人片诈骗刑拘了28天怎么办 交警拘留几天后还是没钱赔偿怎么办 平安车主信用卡车牌号填错了怎么办 起诉借钱的人逮起来了怎么办