• Windows编程 Windows下Unicode编码


    我们知道在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进制格式地址最长也就15                                                       
    wsprintf(tempBuf,L"%s说:%s",wIp,recvBuf);
    ::PostMessageA(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);

    参考:http://blog.163.com/zui_qingbei/blog/static/20957123620126252567489/

    关于MFC的CString就先说到这儿吧 !

    接下来看下使用

    TCHAR

    #ifndef _TCHAR_DEFINED
    typedef WCHAR TCHAR, *PTCHAR;
    typedef WCHAR TBYTE , *PTBYTE ;
    #define _TCHAR_DEFINED
    #endif /* !_TCHAR_DEFINED */
    
    #ifndef _MAC
    typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
    #else
    // some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
    typedef unsigned short WCHAR;    // wc,   16-bit UNICODE character
    #endif

    可以看出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("Hello");

    以上两句使得无论是在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 _tcslen         wcslen

    仔细点还可以找到另一个定义

    #define _tcslen     strlen

    呵呵 ,我想大家已经明白其意思了吧!

    在Unicode编码下会使用上面那个宏,当然多字节编码就会使用下面那个了。

    的确,Microsoft这样一处理,我们使用起来就方便多了,很容易在项目里面实现统一。

    使用和处理都说了 最后说一下转换吧!

    有时候项目是采用多字节编码,但是一些windows函数不支持宽字节,比如上面说到了网络编程中的收发数据的函数,这时候就需要我们转换一下:

    int WINAPI MultiByteToWideChar(
        _In_ UINT CodePage,
        _In_ DWORD dwFlags,
        _In_NLS_string_(cbMultiByte) LPCCH lpMultiByteStr,
        _In_ int cbMultiByte,
        _Out_writes_to_opt_(cchWideChar, return) LPWSTR lpWideCharStr,
        _In_ int cchWideChar
        );
    
    int WINAPI WideCharToMultiByte(
        _In_ UINT CodePage,
        _In_ DWORD dwFlags,
        _In_NLS_string_(cchWideChar) LPCWCH lpWideCharStr,
        _In_ int cchWideChar,
        _Out_writes_bytes_to_opt_(cbMultiByte, return) LPSTR lpMultiByteStr,
        _In_ int cbMultiByte,
        _In_opt_ LPCCH lpDefaultChar,
        _Out_opt_ LPBOOL lpUsedDefaultChar
        );

    这里是我常用的两个函数,当然肯定还有其他方法,这个视编程的情况而定吧。

    其他方法请参考:http://www.cnblogs.com/coderlee/archive/2008/01/25/1053311.html

    到这里就差不多了吧,最后看几个常用字符串指针

    LPSTR:32bit指针指向一个字符串,每个字符占1字节

    LPCSTR:32-bit指针指向一个常字符串,每个字符占1字节

    LPCTSTR:32-bit指针指向一个常字符串,每字符可能占1字节或2字节,取决于Unicode是否定义

    LPTSTR:32-bit指针字符可能占1字节或2字节,取决于Unicode是否定义

    都与这里内容较多,各位可以自己把这几个指针类型输入编译器,按F12转到代码,看看这几个类型Windows是如何定义的。

    还是简单的说下吧,'L'代表Long,'P'代表Pointer(指针),'STR'表示这个变量是一个字符串,'C'表示Const,'T'表示_T宏,呵呵  说到这儿相信大家以后也能够见名知其意思了吧!

    这篇就到底就结束了!希望以后有机会写更精彩的内容呈现给大家。。手好软。。。

  • 相关阅读:
    Spark Scala当中reduceByKey(_+_) reduceByKey((x,y) => x+y)的用法
    Spark和Scala当中的collect方法的用法和例子
    Win7 Eclipse 搭建spark java1.8(lambda)环境:WordCount helloworld例子
    System memory 259522560 must be at least 4.718592
    Win7 Eclipse 搭建spark java1.8环境:WordCount helloworld例子
    Win7 Eclipse 搭建spark java1.8编译环境,JavaRDD的helloworld例子
    indows Eclipse Scala编写WordCount程序
    Spark Scala当中reduceByKey的用法
    Spark Scala当中reduce的用法和例子
    Scala当中parallelize并行化的用法
  • 原文地址:https://www.cnblogs.com/Aion/p/3424139.html
Copyright © 2020-2023  润新知