wchar_t 宽字符集 研究 和COM的 BSTR VARIANT
wchar_t 是和 char 平等的地位,即 wchar_t 并非 typedef出来的,是原生的变量。
简单的说,它拥有两个字节,和short 占用空间一样。
比如:
字符串 "我们\n"
ANSI 的十六进制为:ce d2 c3 c7 0A 00
6个字节,其中包括字符串最后的\0
Unicode十六进制为:11 62 EC 4E 0A 00 00 00
8个字节,所有的字符 全部是2个字节,即使字母 数字 都是,当然换行\n 也是0A 00 了。
一般 程序中字符串 前面加个 L"" 就表示 是Unicode 字符串了。
windows下有一个 宏 _T("") 和上面的一样。
1.第一个简单的问题,如何打印出来 Unicode?
2个字节,可以按照 数字打印,但是如果要按照字符 打印,用普通的printf 是不行了。
可以使用wprintf打印,也就是 普通的 printf前面加一个 Wide的 W。类似的函数都是,比如 wsprintf。
char* lpszText = "我们\r\n";//ANSI:ce d2 c3 c7 //Unicode:11 62 EC 4E //回车 \r 0D \n 0A printf("char * text: %s 0x%08x 0x%08x \nANSI编码是 :", lpszText, lpszText, *lpszText ); print_hex_to_file(stdout,(const uint8_t *)lpszText,strlen(lpszText)+1,16);//此函数自己编写的 BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText); wprintf(L"BSTR text: %s 0x%08x 0x%08x \nUniCode编码是:", bstrText, bstrText, *bstrText); print_hex_to_file(stdout,(const uint8_t *)bstrText,wcslen(bstrText)*2+2,16);
的结果为:
char * text: 我们
0x013fbd80 0xffffffce ANSI编码是 :0x ce d2 c3 c7 0d 0a 00 BSTR text: 我们
0x007be5b4 0x00006211 UniCode编码是:0x 11 62 ec 4e 0d 00 0a 00 00 00
对了,开始我用wprintf始终无法打印中文,后来 添加了下面的两句 才可以了。
#include <locale.h> setlocale( LC_CTYPE, "chs" );
源码的编码 是 ANSI 或 UniCode 对结果 都没有什么影响。
对了 如果要打印单个 wchar_t 怎么打印呢?上面都是指针,都是字符串,那好好办。单个。。。
setlocale( LC_CTYPE, "chs" ); WCHAR wstr1; wchar_t wstr2; wstr1=L'我'; wstr2=L'们'; wprintf(L"我们 在宽字符集(%c,%c) 的每个大小为:%d 字节\n",wstr1,wstr2,sizeof(wstr1));
赋值的时候 始终记住 L ,结果正常。
我们 在宽字符集(我,们) 的每个大小为:2 字节
如果你将 '我' 赋值给 一个 char 类型,那么 你只能得到 '我' ce d2 的 前一个 字节。打印出来 肯定 就是乱码 ? 了。
char ss; ss='我'; printf("ss=%c\n",ss); 结果是: ss=?
并且 ? 后面是没有换行的,因为 \n 已经和 %c 融合 为 ? 了。。反正 ce 打印出来 或许 很诡异的。
2.第二个简单的问题,如何 与 char 类型 互相转换
int ConvertStringToBSTRDemo() { char* lpszText = "Test"; printf("char * text: %s\n", lpszText); BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText); wprintf(L"BSTR text: %s\n", bstrText); ::SysFreeString(bstrText); return 0; }; int ConvertBSTRToStringDemo() { BSTR bstrText = ::SysAllocString(L"Test"); wprintf(L"BSTR text: %s\n", bstrText); char* lpszText2 = _com_util::ConvertBSTRToString(bstrText); printf("char * text: %s\n", lpszText2); ::SysFreeString(bstrText); delete[] lpszText2; return 0; };
这个全局函数 SysFreeString() 发现 不加 貌似 也没有内存泄漏?(VLD检测)
我靠,我知道了,可能是VLD没有重载COM里的内存分配释放,所以 还是 去掉 SysFreeString前的注释。
经过实验 循环10 000 000次,会发生 300MB左右的内存泄漏。但是VLD确实无法检测。所以 千万得小心了!
COM编程里的 BSTR其实就是wchar_t* 类型,有BSTR的地方就是分配了指针的,一定要自己释放内存的!
BSTR和String(char *) 的转换,其实就是 wchar_t* 和 char * 的转换了。这是COM的方法
还可以使用stdlib里的方法:
wcstombs 和 mbstowcs wcs应该就是WideCString ,但是 mbs 怎么就表示 ansi普通的字符编码 我就不知道缩写了
wchar_t ws[10]; //sizeof(ws)=20字节 wsprintf(ws,L"我们"); char cs[50]; sprintf(cs,""); //清除数据 与初始化 //wchar_t * 转化为 char * int ret=0; printf("wcstombs前: cs=%4s ws=%%S=%S\n",cs,ws); ret=wcstombs(cs,ws,sizeof(ws)); printf("wcstombs后: ret=%d,cs=%4s ws=%%S=%S\n",ret,cs,ws); wsprintf(ws,L""); //清除数据 与初始化 //char * 转化为 wchar_t * wprintf(L"mbstowcs前: ws=%4s cs=%%S=%S\n",ws,(cs)); ret=mbstowcs(ws,cs,sizeof(ws)*2); wprintf(L"mbstowcs后: ret=%d,ws=%2s cs=%%S=%S\n",ret,ws,(cs));
运行结果
wcstombs前: cs= ws=%S=我们 wcstombs后: ret=4,cs=我们 ws=%S=我们 mbstowcs前: ws= cs=%S=我们 mbstowcs后: ret=2,ws=我们 cs=%S=我们
windows下也有另外的相同意思的API
//MultiByteToWideChar
最后 加上 我喜欢的 print_hex_to_file函数
void print_hex_to_file(FILE*fp,const uint8_t *array, int count/*aray的大小*/,int lineCount/*默认应该是16*/) { int i; fprintf(fp,"0x "); for(i = 0; i < count; ){ fprintf(fp,"%02x ", array[i]); i++; if ( !(i % lineCount) && i<count){ fprintf (fp,"\n0x "); } } fprintf(fp,"\n"); };
------------------------------------------------------------------------------------------------
一定要专业!本博客定位于 ,C语言,C++语言,Java语言,Android开发和少量的Web开发,之前是做Web开发的,其实就是ASP维护,发现EasyASP这个好框架,对前端后端数据库 都很感觉亲切啊。. linux,总之后台开发多一点。以后也愿意学习 cocos2d-x 游戏客户端的开发。