今天遇到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
#include
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
#include
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<
虽然从网上使用了这种转化的办法,但是在自己函数上实现的过程中,还是遇到了问题:就是转化之后还是出现了乱码。
这是我函数中接收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