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

今天遇到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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值