在MFC应用程序中遇到的字符集问题(整理总结)

来源:互联网 发布:武汉买房 知乎 编辑:程序博客网 时间:2024/05/22 10:35

最近在写Socket通信的Demo,涉及到几种字符集之间的转换问题,也顺便整理和总结一下


1)关于字符集

      字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。中文文字数目大,而且还分为简体中文和繁体中文两种不同书写规则的文字,而计算机最初是按英语单字节字符设计的,因此,对中文字符进行编码,是中文信息交流的技术基础。

      标准的ANSI字符一共有128个,后来扩充到255个,而ANSI使用8位(1个字节)标识每个字符,最多也只能表示255个字符。C语言中的char类型就是用来储存ANSI编码的字符的。Char类型有signed char 和unsigned char两种char,默认的char是有符号的signed char ,可以表示的字符编码范围是-128~127,无符号的unsigned char 可以表示0~255.也就是说,ANSI只能表示最多256个字符(即ASCII值为0-255之间的字符),每个字符用一个字节的空间来存储,对于英文,的确足够,可是对于其他的复杂语言,如汉语,这是远远不够的。

      为了统一全世界都可以使用的字符编码,Unicode产生了。UNICODE可以表示65,536(2的16次方) 个字符,长度为ANSI的两倍,囊括了世界上所有的字符,每一个字符都有一个单一的UNICODE值,当然也包括ANSI码表示的字符,不同的是:ANSI字符只占用一个字节,UNICODE会自动在ANSI值后加入一个值为0的字节。简单的来说,通常Unicode使用两个字节表示每个字符,即每个字符为16位二进制长度。而ANSI编码使用一个字节表示每个字符,即8个二进制位。

      在Windows的API函数中,每一个涉及到了字符串传递的函数,如最基本的MessageBox(用来显示一个消息框),都有两个版本,MessageBoxA和MessageBoxW,前者是ANSI版本,后者是宽字符版本,通常就是UNICODE。C++中的char是对应ANSI字符的,C++中还有一个基本类型wchar_t就是对应UNICODE字符的。编程的时候应该首先决定使用更加通用的宽字符UNICODE,还是占用空间较少的ANSI,个人认为应用软件可以使用UNICODE好一些。

      除了UNICODE和ANSI,还有和UNICODE关系比较近的几种编码,比如UTF-8等,不过桌面软件应用不是很广泛,而网络上用的稍微多一些,侧重网络开发的.Net框架对各种编码都有很好的支持,VB.net(包括2002、2003、2005)和C#等都默认使用UNICODE 编码文本文件和字符串。VC6、7默认使用ANSI编码,VC2005及以上版本默认使用UNICODE。

     在定义中,常用到以下的宏

     LPSTR:     一个32位指向字符串的指针,相当于char*
     LPCSTR:   一个32位指向字符串常量的指针,相当于const char*
     LPWSTR:  一个32位指向Unicode字符串的指针,相当于wchar_t*
     LPCWSTR: 一个32位指向Unicode字符串常量指针,相当于const wchar_t*

 

2)几种关于字符(字符串)的转换

  • 宽字符到短字符(Unicode和ANSI多字节字符串之间转换)

       WideCharToMultiByte

  函数功能:该函数映射一个unicode字符串到一个多字节字符串。

  函数原型:int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPWSTR lpWideCharStr, int cchWideChar, LPCSTR lpMultiByteStr, int cchMultiByte, LPCSTR lpDefaultChar, PBOOL pfUsedDefaultChar );

  参数:

  CodePage:指定执行转换的代码页,这个参数可以为系统已安装或有效的任何代码页所给定的值。你也可以指定其为下面的任意一值:

  CP_ACP:ANSI代码页;

      CP_MACCP:Macintosh代码页;

      CP_OEMCP:OEM代码页;

  CP_SYMBOL:符号代码页(42);

      CP_THREAD_ACP:当前线索ANSI代码页;

  CP_UTF7:使用UTF-7转换;

      CP_UTF8:使用UTF-8转换。

    dwFlags确定Windows如何处理“复合” Unicode字符,它是一种后面带读音符号的字符。如è就是一个复合字符。

      WC_COMPOSITECHECK使得这个API检查非映射复合字符。

      WC_SEPCHARS使得Windows将字符分为两段,即字符加读音,如e`。
      WC_DISCARDNS使得Windows丢弃读音符号。
      WC_DEFAULTCHAR使得Windows用lpDefaultChar参数中说明的缺省字符替代复合字符。
缺省行为是WC_SEPCHARS

      另外,MSDN上提示Caution  Using the WideCharToMultiByte function incorrectly can compromise the security of your application. Calling this function can easily cause a buffer overrun because the size of the input buffer indicated by lpWideCharStr equals the number of characters in the Unicode string, while the size of the output buffer indicated by lpMultiByteStr equals the number of bytes. To avoid a buffer overrun, your application must specify a buffer size appropriate for the data type the buffer receives.

      lpWideCharStr:指向将被转换的unicode字符串。
  cchWideChar:指定由参数lpWideCharStr指向的缓冲区的字符个数。如果这个值为-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度。
  lpMultiByteStr:指向接收被转换字符串的缓冲区。
  cchMultiByte:指定由参数lpMultiByteStr指向的缓冲区最大值(用字节来计量)。若此值为零,函数返回lpMultiByteStr指向的目标缓冲区所必需的字节数,在这种情况下,lpMultiByteStr参数通常为NULL。
  lpDefaultCharpfUsedDefaultChar:只有当WideCharToMultiByte函数遇到一个宽字节字符,而该字符在uCodePage参数标识的代码页中并没有它的表示法时,WideCharToMultiByte函数才使用这两个参数。如果宽字节字符不能被转换,该函数便使用lpDefaultChar参数指向的字符。如果该参数是NULL(这是大多数情况下的参数值),那么该函数使用系统的默认字符。该默认字符通常是个问号。这对于文件名来说是危险的,因为问号是个通配符。pfUsedDefaultChar参数指向一个布尔变量,如果Unicode字符串中至少有一个字符不能转换成等价多字节字符,那么函数就将该变量置为TRUE。如果所有字符均被成功地转换,那么该函数就将该变量置为FALSE。当函数返回以便检查宽字节字符串是否被成功地转换后,可以测试该变量。
  返回值:如果函数运行成功,并且cchMultiByte不为零,返回值是由 lpMultiByteStr指向的缓冲区中写入的字节数;如果函数运行成功,并且cchMultiByte为零,返回值是接收到待转换字符串的缓冲区所必需的字节数。如果函数运行失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。它可以返回下面所列错误代码:
  ERROR_INSUFFICIENT_BJFFER;ERROR_INVALID_FLAGS;
  ERROR_INVALID_PARAMETER;ERROR_NO_UNICODE_TRANSLATION。
  注意:指针lpMultiByteStr和lpWideCharStr必须不一样。如果一样,函数将失败,GetLastError将返回ERROR_INVALID_PARAMETER的值。

 wchar_t wText[20] = {L"宽字符转换实例!OK!"};  DWORD dwNum = WideCharToMul多字节字符tiByte(CP_OEMCP,NULL,wText,-1,NULL,0,NULL,FALSE);  char *psText;  psText = new char[dwNum];  if(!psText)  {   delete []psText;  }  WideCharToMultiByte (CP_OEMCP,NULL,wText,-1,psText,dwNum,NULL,FALSE);  delete []psText;

  • 短字符到宽字符(Unicode和ANSI多字节字符串之间转换)

相似地,可以使用MultiByteToWideChar函数进行转换

  char sText[20] = {"多字节短字符串"};  DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, sText, -1, NULL, 0);  wchar_t *pwText  = new wchar_t[dwNum];  if(!pwText)  {   delete []pwText;  }  MultiByteToWideChar (CP_ACP, 0, sText, -1, pwText, dwNum);  //OK  delete []pwText;

  • 其他转换(以后补充详尽)

1 string to CString   

    CString.format("%s",string.c_str()); 

CString to string

   string str(CString.GetBuffer());

   CString.ReleaseBuffer()

3 string to char *

   char *p=string.c_str();

4 char * to string

   string str(char*);

5 CString to char *

   strcpy(char,CString,sizeof(char));

6 char * to CString

   CString.format("%s",char*);

 

       参考的几篇网文:

         http://blog.csdn.net/geeeeeeee/archive/2008/12/12/3504078.aspx

         http://zhaoweizhuanshuo.blog.163.com/blog/static/14805526220106313429444/

         http://blog.csdn.net/norains/archive/2006/12/25/1461174.aspx

         http://apps.hi.baidu.com/share/detail/695339

         http://msdn.microsoft.com/en-us/library/dd374130(VS.85).aspx

         http://my.chinaunix.net/space.php?uid=25407816&do=blog&id=314336

 

 


原创粉丝点击