wchar和char的了解以及相互转化

来源:互联网 发布:网络最牛的对联 编辑:程序博客网 时间:2024/05/19 00:37

今天遇到wchar和char字符转换的问题,花费了不少的时间。

typedef struct tagSerialData{    nuWCHAR serialdata[10];    nuUINT  dataLength;}SERIAL_DATA, *pSERIAL_DATA;

这是我定义的结构体(nuWCHAR是公司自定义的,相当于WCHAR),但是另外公司的同事把结构体定义成了

struct tagSerialData{    char serialdata[10];    int  dataLength;}SERIAL_DATA, *pSERIAL_DATA;

所以导致我将自己定义的结构体的dataLength赋值成10时,联调的同事接收到的Length=0;或者我将自己定义的结构体的serialdata赋值成“1234567890”时,同事接收到的Length是一个无限大的数

这是我给自己定义的结构体赋值,获取长度SERIAL_DATA s_stcSerialData = {0};wcscpy(s_stcSerialData.serialdata,L"1234567890";s_stcSerialData.dataLength=wcslen(s_stcSerialData.serialdata)

后来发现定义的结构体不一样时,我只好修改自己的结构体,变成nuCHAR,但是在后面的功能上我要用的是WCHAR类型的数据。这就需要我将他后来传给我的char类型的数据转换成WCHAR .

我在网上搜的wchar转化成char的例子如下:

 int MultiByteToWideChar(     UINT uCodePage, //标识了与多字节字符串关联的一个代码值  一般不用  传0???     DWORD   dwFlags,          //允许我们额外的控制,它会影响带变音符号(比如重音) 一般不用 传0     PCSTR   pMultiByteStr,    //  源多字节字符串     int cbMulitByte,              //源多字节字符串的长度(字符)  如果传进-1,函数便可以自动判断源串长度     PWSTR   pWideCharStr, //转换后的串的指针 即缓冲区的首地址     int cchWideChar  );        //指定这个缓冲区的最大长度(字符数),如果传入0,则函数不会转换,而是返回一个宽字符数(包括终止字符'\0'),只有当缓冲区能够容纳该数量的宽字符时,转换才会成功。  1:  以下为将一个多字节串转化成Unicode形式的步骤:       (1)、调用MultiByteToWideChar,为pWideCharStr传入NULL,为cchWideChar传入0,为pMultiByteStr传入-1       (2)、假设上次调用的返回值为n ,开辟一块缓冲区,大小为  n *sizeof( wchar_t)       (3)、再调用一次MultiByteToWideChar,pWideCharStr为开辟的缓冲区的首地址,cchWideChar  为n       (4)、使用转换后的字符串       (5)、释放缓冲区代码:            char str1[100] = "1234567890";             int numChar = ::MultiByteToWideChar(0,0,str1,-1,NULL,0);             wchar_t *str2 = (wchar_t*)malloc( numChar*sizeof(wchar_t) );             ::MultiByteToWideChar(0,0,str1,-1,str2,numChar);             ::wprintf_s(str2);2:unicode转换为多字节字符串:int   WideCharToMultiByte(       UINT   nCodePage,        //标识了与多字节字符串关联的一个代码值  一般不用  传0???       DWORD   dwFlags,        //允许我们额外的控制,它会影响带变音符号(比如重音) 一般不用 传0       PCWSTR   pWideCharStr,//源unicode字符串       int cchWideChar,          //unicode字符数       PSTR   pMultiByteStr,   //缓冲区首地址       int   cbMultiByte,        //缓冲区最大的长度  防止溢出       PCSTR   pDefaultChar,//当有一个字符不能转换时,用该指针指向那个不能转换的字符       PBOOL   pfUesdDefultChar) ;//如果成功转换 该值为FALSE 如果有至少一个字符不能成功转换,该值为TURE                                                    用该值来检测能否转化成功,                              最后这两个参数只有在碰到有一个字符不能转化时才用到,一般传值NULL使用步骤和多字节转化为unicode差不多,不同的是第一次调用时返回直接就是所需缓冲区的大小(字节数)!!!代码:             wchar_t str1[100] = L"1234567890";              int numChar = ::WideCharToMultiByte(0,0,str1,-1,NULL,0,NULL,NULL);             char *str2 = (char*)malloc( numChar );             ::WideCharToMultiByte(0,0,str1,-1,str2,numChar,NULL,NULL);                printf(str2);             free(str2);这是写的一个小例子:#include <stdio.h>#include <Windows.h>int main(){    char *a = "ab";    wchar_t *b = (wchar_t *)a;    wprintf(L"%s %s\n", b, L"ab");    sleep(1000);//作用是为了使在屏幕上停留    return 0;}结果:? ab没有经过转化的wchar类型和char类型不能这样强制转换#include <stdio.h>#include <Windows.h>int main(){    char *a = "ab"int numChar = ::MultiByteToWideChar(0,0,a,-1,NULL,0);    wchar_t *b = (wchar_t*)malloc(numChar*sizeof(wchar_t));    ::MultiByteToWideChar(0,0,a,-1,b,numChar);    wprintf(L"%s %s\n", b, L"ab");    free(b);    Sleep(1000);    return 0;}结果:ab  ab成功将char转化成wchar类型。

WCHAR和CHAR的区别:

首先,说下窄字符char了,大家都很清楚,就是8bit表示的byte,长度固定。char字符只能表示ASII码表中的256个字符,包括前128个可见字符和后面的128个不可见字符。   而wchar_t则是因为char所能表示的字符数太少(256个)而应运而生的,它的长度可以8bit,16bit,32bit,长度是与不同平台上的c库相关的。其实这个长度是根据指定平台上想要用的encoding编码方式来设定的。   在win32 MSVC环境下,c库中wchar_t的长度是2个byte,定义如下:   typedef unsigned short wchar_t; /* 16 bits */   它是按照utf-16编码,但是因为wchar_t定义的长度只有2个字节,所以它不能表示utf-16编码长度为4个字节的字符。即wchar_t只表示了utf-16的一个子集。换句话话说,就是MSVC下,wchar_t是utf-16编码的,但是只能表示utf-16的一个子集。按utf-16编码时,大部分字符都以固定长度的字节 (2字节) 储存.    在Linux-x86的GCC环境下,c库中wchar_t的长度为四个字节,用UCS-4(即utf-32编码方式)。    wchar_t就是存储的字符的unicode码值的编码值,如windows下就是unicode码值的utf-16编码值:    TCHAR wide[] = L"态";    在vs中watch为:  [0] 24577 L'态' wchar_t,即对应的十进制为24577,而"态"unicode表中查到的码值为十六进制的6001,而0x6001对应的十进制值就是24577.    TCHAR wide[] = L"a"; 因为a的unicode值与ASCII值一样,为97. 如果unicode码值U小于0x10000,则U的UTF-16编码就是U对应的16位无符号整数。    所以可知,0x6001的utf-16编码值就是0x6001。           wchar_t   w1= L'中';  //Unicode 编码    wchar_t   w2= '中';   //Ansi编码    printf( "%0x   %0x ",w1,w2);    结果:    4e2d   d6d0    虽然同样是赋值给wchar_t,但是不同的编码则值是不同的。同时也说明了wchar_t不光是可以存储Unicode宽字符,也可以存储其它的编码。但是如果是存储的Ansi编码,则按照宽字符的格式输出的是什么呢?    wchar_t c= L'中';    wcout.imbue(locale("chs"));    wcout<<c<<endl;   上述代码能正常输出'中'字   wchar_t c= '中';   wcout.imbue(locale("chs"));   wcout<<c<<endl;  上述代码不能正常输出'中'字,结果是什么也没输出。  所以如果是需要宽字符参数的API里传入值为Ansi编码值的wchar_t可能会得到不可预测的结果。    c/c++标准只是声明wchar_t是一个可以表示字符集中的任意一个字符的足够宽的变量类型。wchar_t可以用任何encoding编码方式来存储这个字符,如ANSI, or UCS-2, or UCS- 4, 甚至是SCU-128,只不过我们通常是用unicode编码方式。wchar_t是与实现相关的。所以为了可移植性,我们不能假定wchar_t的编码方式,然后根据编码方式做一些相关性操作,我们只能理解它为一个足够宽的字符类型。

虽然从网上使用了这种转化的办法,但是在自己函数上实现的过程中,还是遇到了问题:就是转化之后还是出现了乱码。

这是我函数中接收wchar字符串,并且将wchar字符串显示在文本框中的函数:
vSetObjectText(ID_STATIC_SERIALDATA,CGnBaseDlg::SerialData);
vSetObjectText(ID_STATIC_MAINCTRL_VER,s_stcMainCtrlVer.wMainCtrl);
而后来才发现vSetObjectText()函数的第二个参数应该接收的是一个全局变量,而之前我在转化之前定义的都是静态的变量,所以才导致虽然多次写入到文件的s_stcSerialData.serialData能读取到正确的字符串,但是在文本框中却出现乱码的情况。

另外附上非常不错的文章链接:

http://club.topsage.com/thread-2227977-1-1.html
http://blog.sina.com.cn/s/blog_62714d6a0100ld9z.html

0 0
原创粉丝点击