wchar_t 宽字符集 研究 和COM的 BSTR VARIANT

时间:2022-05-12 18:36:11

 

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");
};