• 字符编码


      对于字符串,我想,第一想法是以0结尾的ANSI单字节字符数组。然而有些语言文字系统的字符集容量巨大,一个字节最多能表示256个符号,显得不够用。于是产生了DBCS,但其单双字节混用,犹如恶梦,我们鄙弃之,转而研究Unicode编码。

      在windows Vista中,每个Unicode字符都使用UTF-16编码,UTF的全称是Unicode Transformation Format。UTF-16将每个字符编码为2个字节。这是通用的。当然,有些语言,2个字节也不够,对此,对这些语言,UTF-16支持使用代理(surrogate),后者用4个字节表示一个字符。另外,还有一些其他标准,如UTF-8、UTF-32等。

      我们知道,c语言用char表示一个ANSI字符。默认下,编译器将字符串中的字符转化为8位char构成的一个数组,如:

    char c='a';
    
    char s[100]="hello world!';

      Microsoft的C/C++编译器定义了一个内建的数据类型wchar_t,它表示一个16位的Unicode字符。因为早期版本的Microsoft编译器没有提供这个内建的数据类型,所以编译器只有在指定了/Zc:wchar_t编译器开关时,才会定义这个数据类型。默认情况下,在Microsoft visual studio中新建一个c++项目时,这个编译器开关是指定的。建议始终指定这个编译器开关,这样才能更好地操纵Unicode字符。

      声明Unicode字符和字符串的方法如下:

    wchar_t c=L'a';
    
    wchar_t s[100]=L"hello world!";

    字符串之前的大写字母L通知编译器该字符串应该编译为一个Unicode字符串。

    为了与c语言稍微有些区分,windows开发团队希望自己定义数据类型,于是在WinNT.h中定义了以下数据类型:

    typedef char CHAR;
    typedef wchar_t WCHAR;

    除此之外,还有很多,比如:

    typedef CHAR *PCHAR;
    typedef CHAR *PSTR;
    typedef CONST CHAR *PCSTR;
    
    typedef WCHAR *PWCHAR;
    typedef WCHAR *PWSTR;
    typedef COSNT WCHAR *PCWSTR;

    自windows NT起,windows的所有版本都完全用Unicode来构建。但是如果函数传入一个ANSI字符串,那么就要进行ANSI到Unicode的转换,再把结果传给操作系统。这个转换工作,会产生时间和内存上的开销。

    如果一个windows函数的参数列表中有字符串,则该函数通常有两个版本。例如,一个CreateWindowEx接受Unicode字符串,另一个CreateWindowEx则接受ANSI字符串。虽然事实如此,但两个函数的原型为:

    CreateWindowExW这个版本接受Unicode字符串,函数名末尾的大写字母W代码wide。Unicode字符常常被称作宽字符。CreateWindowExA接受ANSI字符串。

    但在平时,我们只是在自己的代码中调用CreateWindowEx,不会直接调用CreateWindowExW或CreateWindowExA。在WinUser.h中,CreateWindowEx实际上是一个宏,它的定义如下:

    #ifdef UNICODE
    #define CreatewindowEx CreateWindowExW
    #else
    #define CreateWindowEx CreateWindowExA
    #endif

    用visual studio创建一个新项目时,它默认会定义UNICODE。所以,默认调用CreateWindowExW。

    在windows Vista中,CreateWindowExA的源代码只是一个转换层(translation layer),它负责分配内存,以便将ANSI字符串转换为Unicode字符串。然后,代码会调用CreateWindowExW,并向它传送转换后的字符串。CreateWindowExW返回时,CreateWindowExA会释放它的内存缓冲区,并将窗口句柄返回。所以,对于要在缓冲区中填充字符串的任何函数,在应用程序能够处理字符串之前,系统必须先将Unicode字符串转换为非Unicode形式。由于系统必须执行这些转换,故而应用程序需要更多内存,且运行速度缓慢。为避免这种情况,一开始就应该使用Unicode来开发程序。另外,目前已知的windows的这些转换函数中存在一些bug,所以避免使用它们还有助于消除一些潜在的bug。

    windows API中的一些函数存在的唯一意义就是为了向后兼容16位windows程序,因为后者只支持ANSI字符串。在开发的新程序中,应避免使用它们。如,在使用WinExec和OpenFile调用的地方,应该用CreateProcess和CreateFile函数调用来代替。

    Microsoft将COM从16位windows移植到win32时,做出一个重要决策:所有需要字符串作为参数的COM接口方法都只接受Unicode字符串。这是明智的。

    和windows函数一样,c运行库也提供了一系列函数处理ANSI字符,并提供了另一系列函数处理Unicode字符。然而,与windows不同的是,两个系列的函数是各自为政、自力更生的,即ANSI系列函数不会转换字符串为Unicode形式,同样Unicode系列函数不会内部调用ANSI版本。

    在c运行库中,strlen就是个返回ANSI字符串长度的函数,与之对应的是wcslen---返回Unicode字符串长度。他们的原型都在string.h中。为了使源码既能用ANSI编译,又能用Unicode编译,还必须包含TChar.h,该文件定义了以下宏:

    #ifdef _UNICODE
    #define _tcslen wcslen
    #else
    #define _tcslen strlen
    #endif

    现在,应该在代码中调用_tcslen。默认情况下,在visual studio中新建一个c++项目时,已经定义了_UNICODE。

    针对不属于c++标准一部分的标识符,c运行库始终会为他们附加下划线前缀。但是,windows团队并没有这样做。所以,在应用程序中,应确保要么同时定义了UNICODE和_UNICODE,要么一个都不要定义。CmnHdr.h头文件中定义了UNICODE和_UNICODE,可以避免这个问题。

  • 相关阅读:
    尝试MVP模式
    ERP框架开发中的License许可验证机制设计与实现 (包含源代码下载)
    25个增强iOS应用程序性能的提示和技巧
    BarCode条形码基于C# GDI+ 的实现
    Visual Studio ALM + Team Foundation Server Blog
    通过分析内存来优化.NET程序
    Zachman框架
    常用的微软软件和下载地址
    Windows Live Writer for cnblogs
    TDD:MS自带的单元测试 之 线程模型和执行顺序
  • 原文地址:https://www.cnblogs.com/jiu0821/p/4658462.html
Copyright © 2020-2023  润新知