[转载]字节码问题--wchar和char的区别以及wchar和char之间的相互转换字符编码转换等方法及函数介绍

本文主要是介绍[转载]字节码问题--wchar和char的区别以及wchar和char之间的相互转换字符编码转换等方法及函数介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://www.cnblogs.com/MichaelOwen/articles/2128771.html

--------------------------------------------------------------------------------------------------------------------------------------------------------------

收集了一些关于字符/宽字符的一些资料,在此与大家一起分享。

win2下wchar占2个字节   linux下wchar占4个字节

wchar_t的高位字节应该存储在char数组的低位字节。

在 C 语言中, char 类型永远都是一个字节, 双字节字符类型是 wchar_t;但它不是内置类型, 定义在 stddef.h.

给 wchar_t 类型的字符或字符数组(也就是字符串)赋值要冠以 L;

格式化输出(如 printf) wchar_t 类型的字符串, 要用 %S(而非 %s)。(我更多的是看到用ls输出);

而且 要注意一点,printf和wprintf不能混用,否则不会打印。如:

setlocale(LC_ALL,"zh_CN.utf8");
printf("1 print chinese by wprintf test: \n");
wchar_t *wstr = L"中文";
wprintf(L"%ls",wstr);

上面先使用了printf,又使用了wprintf,所以后面的wprintf无法正常输出,只要把上面printf换成wprintf或是注释掉就可以了。


mbs: multi byte string, 用char作为存储类型, 一个字符可能对应1个或者多个char, 不能直接确定字符边界. charset不确定. 过去的程序都是采用mbs的.

wcs: wide character string, 用wchar_t作为存储类型, 一个字符对于一个wchar_t. 使用unicode编码, charset与OS相关, 在windows平台中为UTF16(UCS-2), 在大多数unix平台中为UTF32(UCS-4).

国际化的程序都应该在内部使用wcs, 在输入输出时做mbs与wcs的转换.

#include <stdlib.h>
#include <stdio.h>
#include <locale.h> int main()
{FILE* fp ;setlocale(LC_ALL,"");             //要先设置语言环境wchar_t wchar[5] = L"相等相等";    //定义一个宽字节的变量,初始为"相等"fp = fopen("1.txt", "w+");        //打开文件称奥做fwprintf(fp, L"%ls\n", wchar);    //输出到文件.此处一定要为%ls,不能用%sfclose(fp);                       //关闭文件wchar_t wc2[5];                   //定义第二个宽字节变量int i = 0;//wc开始的有很多宽字节的操作。都和str相对应。wcscpy(wc2, wchar);                //复制。int n = wcscmp(wc2, wchar);        //比较if (n == 0){wprintf(L"相等\n");            }else{wprintf(L"不相等\n");}char str[10];                    //定义char字符。n = wcstombs(str, wc2, 9);       //宽字节转换为muiltycharprintf("1---: %s\n", str);       //输出结果for (i = 0; i < 5; ++i){wc2[i] = L'1' + i;}wc2[4] = 0;n = wcstombs(str, wc2, 9);        //宽字节转换为muiltycharprintf("2---:%s\n", str);         //输出结果return 0;
}

复制代码

mbs与wcs的转换函数:

#include <locale.h>
setlocale(LC_ALL, "");wcstombs(char * to,wchar_t * from,size_t _maxCount);
mbstowcs(wchar_t * to,char * from,size_t _maxCount);

wcstombs/mbstowcs是实现转换的一对函数. 这两个c的库函数其实内部也就是对刚刚windows的api和接下来我们要说的iconv的封装。使用时要注意,如果涉及到中文,要先setlocale,当设置好正确的locale,函数内部才能找到正确的字符集进行转换。

wcs的charset是固定不可变的, 但是mbs的charset是可变的, 可能是ASCII, 可能是gb2312, 也可能是big5. wcstombs/mbstowcs是根据locale环境设置来决定mbs采用的charset的, 在程序中可以用setlocale来设定locale, 例如 setlocale(LC_ALL, "chinese")

程序启动时, locale设定为 LC_ALL="C", 用 setlocale(LC_ALL, "") 就可以设置成操作系统的locale设定.

Locale决定了当前程序运行的本地化设置方式, 但是在程序中可能需要作其他charset的转换, 例如程序本身语言设定为简体中文, 需要做big5与unicode的转换, 或者是其他两种charset的mbstombs转换, 这时wcstombs/mbstowcs就不能胜任了.

/*
linux 下 wchar_t和char的相互转化和测试
win32下wchar_t占2个字节,linux下wchar_t占4个字节。wchar_t的高字节应该存放在char数组的低字节。
Linux下面的没有命名为 WideCharToMultiByte() 和 MultiByteToWideChar() 函数,WideCharToMultiByte,MultiByteToWideChar是windows下的函数,
在linux下也有类似的两个函数:
mbstowcs()
wcstombs() 
值得注意的是:
size_t mbstowcs(wchar_t *wcstr,const char *mbstr,size_t count);
这个函数的第三个参数count,大小一定要是mbstr长度的2倍,否则出来的中文也会是乱码。wcstombs和mbstowcs使用
#include <locale.h>
setlocale(LC_ALL, "");
wcstombs(char * to,wchar_t * from,size_t _maxCount);
mbstowcs(wchar_t * to,char * from,size_t _maxCount);还有呢,转码还可以使iconv函数族,包含以下三个函数(其具体实例可以见demo_iconv.c和code_convert.c):
iconv_t iconv_open(const char *tocode, const char *fromcode);
size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);
int iconv_close(iconv_t cd);
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>size_t get_wchar_size(const char *str)
{size_t len = strlen(str);size_t size=0;size_t i;for(i=0; i < len; i++){if( str[size] >= 0 && str[size] <= 127 ) //不是全角字符size+=sizeof(wchar_t);else //是全角字符,是中文{size+=sizeof(wchar_t);i+=2;}}return size;
}char *w2c(const wchar_t *pw)
{if(!pw)return NULL;size_t size= wcslen(pw)*sizeof(wchar_t);char *pc;if(!(pc = (char*)malloc(size))){printf("malloc fail");return NULL;}wcstombs(pc,pw,size);return pc;}wchar_t *c2w(const char *pc)
{if(!pc)return NULL;size_t size_of_ch = strlen(pc)*sizeof(char);size_t size_of_wc = get_wchar_size(pc);wchar_t *pw;if(!(pw = (wchar_t*)malloc(size_of_wc))){printf("malloc fail");return NULL;}mbstowcs(pw,pc,size_of_wc);return pw;}int main(void)
{setlocale(LC_ALL,"zh_CN.utf8");printf("1 print chinese by wprintf test: \n");wchar_t *wstr = L"中文";//wprintf(L"%ls",wstr); //此处不要使用wprintf,因为上面已经使用了printf,而他们使用的是不同的流,不能混用printf("%ls\n",wstr); //lsprintf("2 print chinese by printf test: \n");char *str = "汉字";printf("%s\n\n\n",str); //sprintf("3 char and wchar_t size of system test: \n");printf("%s%d\n","the size of wchar_t is : ",sizeof(wchar_t)); //4printf("%s%d\n\n\n","the size of char is : ",sizeof(char));   //1char *pc;wchar_t *pw = L"中文是abc一门语言abc";char *tmp = "中文是abc一门语言abc";printf("%s%s\n","input test wchar_t* ",tmp);pc = w2c(pw);printf("4 print char test after w2c (wchar to char):\n");printf("%s\n",pc);wchar_t *cw1 = c2w(pc);   //char to wcharchar *wc1 = w2c(cw1);   //wchar to charprintf("5 print char test after w2c c2w and w2c:\n");printf("%s\n\n\n",wc1);char *pmc = "abc中文abc";wchar_t *pmw;printf("%s%s\n","input test char* ",pmc);pmw = c2w(pmc);char *pmc1 = w2c(pmw);printf("6 print char test after c2w and w2c:\n");printf("%s\n",pmc1);printf("%ls\n",wstr);//cout<<wstr<<endl;return 0;} 

在unix平台中可以使用iconv来做这个转换(iconv lib也有windows版本), 在windows平台可以用MultiByteToWideChar/WideCharToMultiByte 函数.

iconv库的使用

利用iconv函数族进行编码转换(如GB2312转换为UTF-8)

iconv函数族的头文件是iconv.h,使用前需包含之。

#include <iconv.h>

iconv函数族有三个函数,原型如下:

(1) iconv_t iconv_open(const char *tocode, const char *fromcode);

       此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。

(2)size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);

       此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。参数cd必须是由iconv_open函数创建的转换描述符。

/*iconv库的使用GB2312字符串转换为UTF-8的字符串利用iconv函数族进行编码转换iconv函数族的头文件是iconv.h,使用前需包含之。#include <iconv.h>iconv函数族有三个函数,原型如下:(1) iconv_t iconv_open(const char *tocode, const char *fromcode);此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。(3) int iconv_close(iconv_t cd);此函数用于关闭转换句柄,释放资源。
*/
#include <stdio.h>
#include <stdlib.h>
#include <iconv.h>
#include <string.h>int main(void)
{unsigned char *src = "魅影追击和歌姬"; /* 需转换的字串 */unsigned char dst[256] = {0}; /* 转换后的内容 */unsigned char buf[1024] = {0}; /* 格式化转换后的字串 */size_t src_len = strlen(src);size_t dst_len = sizeof(dst);unsigned char *in = src;unsigned char *out = dst;iconv_t cd;int i; int j; cd = iconv_open("UTF-8", "GB2312"); /* 将GB2312字符集转换为UTF-8字符集 */if ((iconv_t)-1 == cd){return -1;}printf("src: %s\n", src);iconv(cd, &in, &src_len, &out, &dst_len); /* 执行转换 *//* 以下将转换后的内容格式化为: %XX%XX...形式的字串 */printf("dst: ");j = 0; for (i = 0; i < strlen(dst); i++){printf("%.2X ", dst[i]);buf[j++] = '%';snprintf(buf + j, 3, "%.2X", dst[i]);j += 2;}printf("\n");printf("buf: %s\n", buf);iconv_close(cd); /* 执行清理 */return 0;
}

大部分情形是inbuf 不为NULL,*inbuf也不为NULL。这种情况下,iconv函数将以*inbuf起始的多字节序列转换到以*outbuf起始的多字节序列。从*inbuf开始读取,最多*inbytesleft字节,转换后,从*outbuf开始写入,最多*outbytesleft字节。iconv函数一次转换一个多字节字符,每次字符转换,*inbuf增加已转换的字节数,*inbytesleft相应地减少已转换的字节数;对应地,*outbuf和*outbytesleft作相应的修改,同时修改cd的转换状态。

以下四种情况不能完成转换:

1.输入中含无效的多字节序列。此时,它将errno设置为EILSEQ并返回(size_t)(-1)。*inbuf指向无效序列的最左端。

2.输入的字节序列已经全部被转换过,也就是*inbytesleft减少至0。此时,iconv返回本次调用中完成转换的数目(可逆的转换不计入)。

3.输入中以不完整多字节序列作结尾。此时,它将errno设置为EINVAL并返回(size_t)(-1)。*inbuf指向不完整多字节序列的最左端。

4.输出缓存区没有足够空间来存储下一个字符。此时,它将errno设置为E2BIG并返回(size_t)(-1)。

另一种情形是inbuf 为NULL或*inbuf为NULL,但*outbuf 不为NULL,*outbuf也不为NULL。这种情况下,iconv函数试图将cd的转换状态设置为初始状态并store a corresponding shift sequence at *outbuf。从*outbuf开始,最多写入*outbytesleft字节。如果输出缓存区没有足够空间来存储这个重置后的序列,他将errno设置为E2BIG并返回(size_t)(-1)。反之,*outbuf增加写入的字节数和*outbytesleft减少写入的字节数。

第三种情形是inbuf 为NULL或*inbuf为NULL,*outbuf 为NULL或*outbuf为NULL。这种情况下,iconv函数试图将cd的转换状态设置为初始状态。


返回值

iconv函数返回本次调用中转换的字符数,可逆的转换不计入。出错时,它将修改errno并返回(size_t)(-1)。

错误

除了其它错误以外,出现以下错误:

E2BIG

*outbuf没有足够的空间。

EILSEQ

    输入含无效的多字节序列。

EINVAL

    输入含不完整多字节序列。

(3) int iconv_close(iconv_t cd);

       此函数用于关闭转换句柄,释放资源。

这个库使用很简单,使用举例:

int gbk2utf8(char *dst, int outlen,char *src,int inlen)
{static iconv_t  its_conv;char *p1;its_conv = iconv_open("UTF-8","GBK");const char*  p = src;p1 = dst;iconv(its_conv, &p, &inlen, &p1, &outlen);//printf("%s\n",out);iconv_close(its_conv);return 0;
}
网上一个人写的支持windows和linux的wchar_t与UTF-8编码之间的转换和UTF-16和wchar_t之间的转换代码
#ifdef WINDOWS  #include <windows.h>   #include <stdio.h>  #include <ctype.h>  
#else  #include <iconv.h>  #include <wctype.h>  #include <wchar.h>  #include <errno.h>  
#endif  //wchar_t转成UTF-8  
int FW2UTF8Convert( const wchar_t* a_szSrc, int a_nSrcSize, char* a_szDest, int a_nDestSize )  
{  #ifdef WINDOWS  return WideCharToMultiByte( CP_UTF8, 0, a_szSrc, -1, a_szDest, a_nDestSize, NULL, NULL );  #else  size_t result;  iconv_t env;  env = iconv_open("UTF-8","WCHAR_T");  if (env==(iconv_t)-1)  {  printf("iconv_open WCHAR_T->UTF8 error%s %d\n",strerror(errno),errno) ;  return -1;  }  result = iconv(env,(char**)&a_szSrc,(size_t*)&a_nSrcSize,(char**)&a_szDest,(size_t*)&a_nDestSize);  if (result==(size_t)-1)  {  printf("iconv WCHAR_T->UTF8 error %d\n",errno) ;  return -1;  }  iconv_close(env);  return (int)result;  #endif  
}  //UTF-8转成wchar_t  
int FUTF82WConvert( const char* a_szSrc, wchar_t* a_szDest, int a_nDestSize )  
{  #ifdef WINDOWS  return MultiByteToWideChar( CP_UTF8, 0, a_szSrc, -1, a_szDest, a_nDestSize );  #else  size_t result;  iconv_t env;  int size = strlen(a_szSrc)+1 ;  env = iconv_open("WCHAR_T","UTF-8");  if (env==(iconv_t)-1)  {  printf("iconv_open UTF8->WCHAR_T error %d\n",errno) ;  return -1;  }  result = iconv(env,(char**)&a_szSrc,(size_t*)&size,(char**)&a_szDest,(size_t*)&a_nDestSize);  if (result==(size_t)-1)  {  printf("iconv UTF8->WCHAR_T error %d\n",errno) ;  return -1;  }  iconv_close(env);  return (int)result;  #endif  
}//wchar_t转成utf16  
int FW2UConvert( const wchar_t* a_szSrc, int  a_nSize,char* a_szDest, int a_nDestSize )  
{  #ifdef WINDOWS  memcpy_s((wchar_t*)a_szDest,a_nDestSize,a_szSrc,a_nSize);  return a_nSize ;  #else  size_t result;  iconv_t env;  env = iconv_open("UCS-2-INTERNAL","UCS-4-INTERNAL");  if (env==(iconv_t)-1)  {  printf("iconv_open WCHAR_T->UTF16 error%s %d\n", strerror(errno),errno);  return -1;  }  result = iconv(env,(char**)&a_szSrc,(size_t*)&a_nSize,(char**)&a_szDest,(size_t*)&a_nDestSize);  if (result==(size_t)-1)  {  printf("iconv WCHAR_T->UTF16 error %s %d\n", strerror(errno), errno);  return -1;  }  iconv_close(env);  return (int)result;  #endif  
}  //utf16转成wchar_t  
int FU2WConvert( const  char* a_szSrc, int a_nSize, wchar_t* a_szDest, int a_nDestSize )  
{  #ifdef WINDOWS  memcpy_s(a_szDest,a_nDestSize,(const wchar_t*)a_szSrc,a_nSize);  return a_nSize ;  #else  size_t result;  iconv_t env;  env = iconv_open("UCS-4-INTERNAL","UCS-2-INTERNAL");  if (env==(iconv_t)-1)  {  printf("iconv_open error %d\n",errno) ;  return -1;  }  result = iconv(env,(char**)&a_szSrc,(size_t*)&a_nSize,(char**)&a_szDest,(size_t*)&a_nDestSize);  if (result==(size_t)-1)  {  printf("UTF16 -> WCHAR_T conv error %d\n",errno) ;  return -1;  }  iconv_close(env);  return (int)result;  #endif  
}

网上不错的资源:

C/C++ 编程中多国语言处理

http://www.ibm.com/developerworks/cn/linux/l-cn-ccppglb/index.html?ca=drs-

彻底解密C++宽字符:1、从char到wchar_t

http://blog.csdn.net/wallaceli1981/archive/2010/07/16/5740615.aspx

彻底解密C++宽字符:2、Unicode和UTF

http://blog.csdn.net/wallaceli1981/archive/2010/07/16/5740616.aspx

彻底解密C++宽字符:3、利用C运行时库函数转换

http://blog.csdn.net/wallaceli1981/archive/2010/07/16/5740618.aspx

彻底解密C++宽字符:4、利用codecvt和use_facet转换

http://blog.csdn.net/wallaceli1981/archive/2010/07/16/5740620.aspx

彻底解密C++宽字符:5、利用fstream转换

http://blog.csdn.net/wallaceli1981/archive/2010/07/16/5740621.aspx

彻底解密C++宽字符:6、国际化策略

http://blog.csdn.net/wallaceli1981/archive/2010/07/16/5740622.aspx

C 源文件内的中文(1)

http://hi.baidu.com/cyclone/blog/item/e48c76099b002ca22eddd4c3.html

C 源文件内的中文(2)

http://hi.baidu.com/cyclone/blog/item/25b262d973e9d72111df9bcf.html

UTF-8 and Unicode FAQ for Unix/Linux

http://blog.csdn.net/lovekatherine/archive/2007/08/30/1765903.aspx


这篇关于[转载]字节码问题--wchar和char的区别以及wchar和char之间的相互转换字符编码转换等方法及函数介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/642553

相关文章

Python进阶之Excel基本操作介绍

《Python进阶之Excel基本操作介绍》在现实中,很多工作都需要与数据打交道,Excel作为常用的数据处理工具,一直备受人们的青睐,本文主要为大家介绍了一些Python中Excel的基本操作,希望... 目录概述写入使用 xlwt使用 XlsxWriter读取修改概述在现实中,很多工作都需要与数据打交

关于@MapperScan和@ComponentScan的使用问题

《关于@MapperScan和@ComponentScan的使用问题》文章介绍了在使用`@MapperScan`和`@ComponentScan`时可能会遇到的包扫描冲突问题,并提供了解决方法,同时,... 目录@MapperScan和@ComponentScan的使用问题报错如下原因解决办法课外拓展总结@

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Window Server2016加入AD域的方法步骤

《WindowServer2016加入AD域的方法步骤》:本文主要介绍WindowServer2016加入AD域的方法步骤,包括配置DNS、检测ping通、更改计算机域、输入账号密码、重启服务... 目录一、 准备条件二、配置ServerB加入ServerA的AD域(test.ly)三、查看加入AD域后的变

Window Server2016 AD域的创建的方法步骤

《WindowServer2016AD域的创建的方法步骤》本文主要介绍了WindowServer2016AD域的创建的方法步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、准备条件二、在ServerA服务器中常见AD域管理器:三、创建AD域,域地址为“test.ly”

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动