我们知道在ascii编码,每个字符占用一个字节,这样能够表示的字符数远远不够表示世界所有语言的符号,所以Unicode编码就是出现了,当然Unicode也有8位 16位 32位的编码,UTF-8、UTF-16、UTF-32分别以char、char16_t、char32_t作为编码单位,本文讨论16位 即UTF-16,(注: char16_t 和 char32_t 是 C++ 11 标准新增的关键字。如果你的编译器不支持 C++ 11 标准,请改用 unsigned short 和 unsigned long。)
当然本文着重讨论Unicode在Windows中的应用,至于具体细节以及原理上的东西,本人才疏学浅,不配在此谈论此问题,呵呵。还请各位到Google去寻找大牛吧。。由于个人能力有限,文中难免有错误之处,还请各位多多批评和指正,多多包涵才是。
许久以前我在学习MFC的过程中,用GetDlgItemText获取Edit Control的值,其得到的值是CString,,我们看下该函数的原型:
int GetDlgItemText( HWND hDlg , int nID, LPTSTR lpStr, int nMaxCount) const;int GetDlgItemText( int nID, CString& rString) const;
CString编码方式为TCHAR,即在定义了UNICODE和_UNICODE(前者是Windows风格后者是C语言风格,效果形同,通常同时定义)时,是wchar_t型,没有定义时是char型。那么在项目设置为多字节编码时,很好处理,比如在网络编程过程中
sendto(_In_ SOCKET s,_In_reads_bytes_(len) const char FAR * buf,_In_ int len,_In_ int flags,_In_reads_bytes_(tolen) const struct sockaddr FAR * to,_In_ int tolen);
sendto第二个参数为待发送数据的缓冲区,char类型的指针,这时CString的存储类型就为char ,那么可以直接使用CString的值。
但是当项目的编码方式设置为Unicode时,这时CString的存储类型就为wchar_t,就需要将CString进行类型转换,CString有一个成员函数GetBuffer,这个函数是为一个CString对象重新获取其内部字符缓冲区的指针,返回的LPTSTR为非const的,从而允许直接修改CString中的内容。然后就可以强制转换为(char *)类型了。
但是在接收端你必须还要劳烦一次,呵呵 有点啰嗦了,这不是我的风格,代码如下:
wchar_t recvBuf[200];SOCKADDR_IN addrFrom;int len=sizeof(SOCKADDR);recvfrom(sock,(char *)recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);
或者在进行一下处理:
char *ip=inet_ntoa(addrFrom.sin_addr);wchar_t *wIp=new wchar_t;memset(wIp,0,sizeof(wchar_t*));MultiByteToWideChar(CP_ACP,0,ip,-1,wIp,16);//点分10进制格式地址最长也就15wsprintf(tempBuf,L,wIp,recvBuf);::PostMessageA(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);
参考:
关于MFC的CString就先说到这儿吧 !
接下来看下使用
TCHAR :
#ifndef _TCHAR_DEFINEDtypedef WCHAR TCHAR, *PTCHAR;typedef WCHAR TBYTE , *PTBYTE ;#define _TCHAR_DEFINED#endif /* !_TCHAR_DEFINED */#ifndef _MACtypedef wchar_t WCHAR; typedef unsigned
可以看出TCHAR 实质就是wchar_t(在Unicode编码下)。
_T("")是一个宏,定义于tchar.h下。
#define _T(x)__T(x)#define _TEXT(x) __T(x)
他的作用是让你的程序支持Unicode编码,因为Windows使用两种字符集ANSI和UNICODE,前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。
Windows NT的所有与字符有关的函数都提供两种方式的版本,而Windows 9x只支持ANSI方式。
如果你编译一个程序为ANSI方式,_T实际不起任何作用。而如果编译一个程序为UNICODE方式,则编译器会把"Hello"字符串以UNICODE方式保存。_T和_L的区别在于,_L不管你是以什么方式编译,一律以UNICODE方式保存。
L是表示字符串资源为Unicode的。比如:
wchar_tStr[] = L"Hello World!"; 这个就是双字节存储字符了。
_T是一个适配的宏~ 当#ifdef _UNICODE的时候 ,_T就是L,没有#ifdef _UNICODE的时候,_T就是ANSI的。
LPTSTR lpStr = new TCHAR[32];TCHAR* szBuf = _T();
以上两句使得无论是在UNICODE编译条件下还是在ANSI编译条件下都是正确编译的。
_TEXT //同样定义于tchar.h下
#define _T(x)__T(x)#define _TEXT(x) __T(x)
看出来了吧 _TEXT和_T一样的作用。
TEXT //定义于winnt.h
#define TEXT(quote) __TEXT(quote) // r_winnt
#define __TEXT(quote) L##quote// r_winnt
呵呵 看到这儿,可能有些懵了吧,TEXT 和 _T功能一样?是的,功能一样,但是有了_T为什么还有TEXT呢,我们看他们定义的头文件,TEXT定义于winnt.h,以win开头的是Microsoft的头文件,根据宏内容,winnt.h是以UNICODE定义的,Tchar.h则是以_UNICODE定义的,是有区别的,至于Microsoft为什么这么做,应该是为了windows开发者能够方便统一吧!其实在winnt.h这个头文件中同样对TCHAR之类的类型进行了定义,有兴趣的童鞋可以去看看这两个问价的内容分。
TEXT 和 _T的区别解释的很不准确,欢迎大家指正,待本人理解在深刻一些在做修改吧 !
好吧,要回寝室了,今日就到这儿了,Unicode字符串的处理明日在叙!!!
继续。。。。
说完了使用 接下来说处理吧
先看_tcslen()这个函数 ,在tchar.h 这个头文件里面找到了其定义
#define _tcslenwcslen
仔细点还可以找到另一个定义
#define _tcslenstrlen
呵呵 ,我想大家已经明白其意思了吧!
在Unicode编码下会使用上面那个宏,当然多字节编码就会使用下面那个了。
的确,Microsoft这样一处理,我们使用起来就方便多了,很容易在项目里面实现统一。
使用和处理都说了 最后说一下转换吧!
有时候项目是采用多字节编码,但是一些windows函数不支持宽字节,比如上面说到了网络编程中的收发数据的函数,这时候就需要我们转换一下:
带着我的相机和电脑,远离繁华,走向空旷。