• Windows程序设计--(二)Unicode 简介


    2.2 宽字符和C语言

    2.2.2 更宽的字符

    在C语言中的宽字符正是基于short型数据的, 这一数据类型在头文件WCHAR.H中的定义为:

    typedef unsigned short wchar_t ;

    所以C语言中的宽字符wchar_t数据类型与一个无符号短整形unsigned short一样, 都是16位宽。

    例如:

    wchar_t c = 'A' ;

    在计算机中保存为0x0041,显示为0x41 0x00

    2.2.3 宽字符库函数

    在使用strlen计算宽字符长度时:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
      wchar_t *p = L"Hello" ;
      printf( "%d
    ", strlen(p) ) ;
    
      return 0 ;
    }

    运行后显示的结果为1, 很显然, 它没有求出正确的长度, 这是因为, 宽字符字符串"Hello"在一段内存中存储的值如下:

    48 00 65 00 6C 00 6C 00 6F 00 21 00

    这是因为当strlen找到该字符串的第一个0时就认为该字符串已经结束了, 所以得到的长度为1, strlen统计到的这一个字符即为0x48表示的'H'。

    我们使用wcslen函数计算宽字符长度。同样的还有

    函数名

    函数原型

    函数功能

    返回值

    wcscat

    wchar_t *wcscat(wchar_t *s1, const wchar_t *s2);

    将s2所指的字符串连接到s1后面

    s1所指字符串的首地址

    wcschr

    wchar_t *wcschr(const wchar_t *s, wchar_t c);

    在s字符串中找到c字符第一次出现的位置

    若找到, 则返回该字符的地址, 否则返回NULL

    wcscmp

    int wcscmp(const wchar_t *s1, const wchar_t *s2);

    让字符串s1与字符串s2进行比较

    s1 < s2, 返回负数; s1 == s2, 返回0;s1 > s2, 返回正数

    wcscpy

    wchar_t *wcscpy(wchar_t *s1, const wchar_t *s2);

    将s2所指字符串覆盖方式复制到s1中

    s1所指的字符串的首地址

    wcslen

    size_t wcslen(const wchar_t *s);

    求s所指字符串的长度

    返回有效字符的个数

    wcsstr

    wchar_t * wcsstr(const wchar_t *s1, const wchar_t *s2);

    找出字符串s2在字符串s1中第一次出现的位置

    若找到, 则返回该位置的地址, 否则返回NULL

    2.2.4 维护一个源代码文件

    使用TEXT可以避免使用 L"hello"直接使用TEXT("hello")

    追溯定义TEXT的地方发现已经加了L

    #define TEXT(quote) __TEXT(quote)   // r_winnt
    
    #define __TEXT(quote) L##quote      // r_winnt

    因此使用TEXT或者_TEXT都可以不用谢L了

    2.3 宽字符和Windows

    2.3.1 Windows头文件的类型

    一个Windows程序包括表头文件WINDOWS.H。该文件包括许多其它表头文件,包括WINDEF.H,该文件中有许多在Windows中使用的基本型态定义,而且它本身也包括WINNT.H。WINNT.H处理基本的Unicode支持。

    WINNT.H的前面包含C的表头文件CTYPE.H,这是C的众多表头文件之一,包括wchar_t的定义。WINNT.H定义了新的数据型态,称作CHAR和WCHAR:

    typedef char CHAR ;        
    typedef wchar_t WCHAR ;    // wc     

    当您需要定义8位字符或者16位字符时,推荐您在Windows程序中使用的数据型态是CHAR和WCHAR。WCHAR定义后面的注释是匈牙利标记法的建议:一个基于WCHAR数据型态的变量可在前面附加上字母wc以说明一个宽字符。

    WINNT.H表头文件进而定义了可用做8位字符串指针的六种数据型态和四个可用做const 8位字符串指针的数据型态。这里精选了表头文件中一些实用的说明数据型态语句:

    typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;        
    typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;        

    前缀N和L表示「near」和「long」,指的是16位Windows中两种大小不同的指标。在Win32中near和long指标没有区别。

    类似地,WINNT.H定义了六种可作为16位字符串指针的数据型态和四种可作为const 16位字符串指针的数据型态:

    typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;        
    typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;        

    至此,我们有了数据型态CHAR(一个8位的char)和WCHAR(一个16位的wchar_t),以及指向CHAR和WCHAR的指标。与TCHAR.H一样,WINNT.H将TCHAR定义为一般的字符类型。如果定义了标识符UNICODE(没有底线),则TCHAR和指向TCHAR的指标就分别定义为WCHAR和指向WCHAR的指标;如果没有定义标识符UNICODE,则TCHAR和指向TCHAR的指标就分别定义为char和指向char的指标:

    #ifdef  UNICODE 
    typedef WCHAR TCHAR, * PTCHAR ;
    typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ; 
    typedef LPCWSTR LPCTSTR ;      
    #else
    typedef char TCHAR, * PTCHAR ;  
    typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ; 
    typedef LPCSTR LPCTSTR ;   
    #endif

    如果已经在某个表头文件或者其它表头文件中定义了TCHAR数据型态,那么WINNT.H和WCHAR.H表头文件都能防止其重复定义。不过,无论何时在程序中使用其它表头文件时,都应在所有其它表头文件之前包含WINDOWS.H。

    WINNT.H表头文件还定义了一个宏,该宏将L添加到字符串的第一个引号前。如果定义了UNICODE标识符,则一个称作 __TEXT的宏定义如下:

    #define __TEXT(quote) L##quote        

    如果没有定义标识符UNICODE,则像这样定义__TEXT宏:

    #define __TEXT(quote) quote        

    此外, TEXT宏可这样定义:

    #define TEXT(quote) __TEXT(quote)        

    这与TCHAR.H中定义_TEXT宏的方法一样,只是不必操心底线。我将在本书中使用这个宏的TEXT版本。

    这些定义可使您在同一程序中混合使用ASCII和Unicode字符串,或者编写一个可被ASCII或Unicode编译的程序。如果您希望明确定义8位字符变量和字符串,请使用CHAR、PCHAR(或者其它),以及带引号的字符串。为明确地使用16位字符变量和字符串,请使用WCHAR、PWCHAR,并将L添加到引号前面。对于是8位还是16位取决于UNICODE标识符的定义的变量或字符串,要使用TCHAR、PTCHAR和TEXT宏。

    2.3.2 Windows函数调用

    MessageBoxA:

    WINUSERAPI int WINAPI MessageBoxA (HWND hWnd, LPCSTR lpText, 
                               LPCSTR lpCaption, UINT uType) ;
            

    下面是MessageBoxW:

    WINUSERAPI int WINAPI MessageBoxW (HWND hWnd, LPCWSTR lpText,
            
                               LPCWSTR lpCaption, UINT uType) ;

    他们的第2,3个参数都是字符串常量指针

    MessageBox会根据参数类型来调用:

    #ifdef UNICODE
    #define MessageBox  MessageBoxW
    #else
    #define MessageBox  MessageBoxA
    #endif // !UNICODE

    2.3.3 Windows的字符串函数

    下面是Windows定义的一组字符串函数,这些函数用来计算字符串长度、复制字符串、连接字符串和比较字符串:

    ILength = lstrlen (pString) ;
            
    pString = lstrcpy (pString1, pString2) ;
            
    pString = lstrcpyn (pString1, pString2, iCount) ;
            
    pString = lstrcat (pString1, pString2) ;
            
    iComp = lstrcmp (pString1, pString2) ;
            
    iComp = lstrcmpi (pString1, pString2) ;

    这些函数与C链接库中对应的函数功能相同。如果定义了UNICODE标识符,那么这些函数将接受宽字符串,否则只接受常规字符串。宽字符串版的lstrlenW函数可在Windows 98中执行。

    2.3.4 在Windows中使用printf

    在Windows程序中不能使用printf函数,而是使用其他的函数:

    #include <Windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
        char szBuffer[100];
        sprintf(szBuffer, "The Sum of %i and %i is %i
    ", 5, 3, 5 + 3);
        MessageBox(NULL, szBuffer, TEXT("Hk_Mayfly"), 0x4L | 0x40L);
    
        return 0;
    }

    表列出了Microsoft的C执行时期链接库和Windows支持的所有sprintf函数。 

     

    ASCII

    宽字符

    常规

    参数的变数个数

         

    标准版

    sprintf

    swprintf

    _stprintf

    最大长度版

    _snprintf

    _snwprintf

    _sntprintf

    Windows版

    wsprintfA

    wsprintfW

    wsprintf

    参数数组的指针

         

    标准版

    vsprintf

    vswprintf

    _vstprintf

    最大长度版

    _vsnprintf

    _vsnwprintf

    _vsntprintf

    Windows版

    wvsprintfA

    wvsprintfW

    wvsprintf

    2.3.5 格式化的消息框

    #include <windows.h>      
    #include <tchar.h>          
    #include <stdio.h>   
            
    int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...)
            
    {
            
        TCHAR   szBuffer [1024] ;
            
        va_list pArgList ;
            
    
        // The va_start macro (defined in STDARG.H) is usually equivalent to:
            
        // pArgList = (char *) &szFormat + sizeof (szFormat) ;
            
    
        va_start (pArgList, szFormat) ;
            
    
        // The last argument to wvsprintf points to the arguments
            
    
        _vsntprintf ( szBuffer, sizeof (szBuffer) / sizeof (TCHAR),
            
                       szFormat, pArgList) ;
            
    
        // The va_end macro just zeroes out pArgList for no good reason
            
        va_end (pArgList) ;
            
        return MessageBox (NULL, szBuffer, szCaption, 0) ;
            
    }
            
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
            
                       PSTR szCmdLine, int iCmdShow)
            
    {
            
        int cxScreen, cyScreen ;
            
        cxScreen = GetSystemMetrics (SM_CXSCREEN) ;
            
        cyScreen = GetSystemMetrics (SM_CYSCREEN) ;
            
    
        MessageBoxPrintf (    TEXT ("ScrnSize"),
            
                       TEXT ("The screen is %i pixels wide by %i pixels high."),
            
                       cxScreen, cyScreen) ;
            
        return 0 ;
            
    }

  • 相关阅读:
    【随机过程】随机过程之泊松过程的直观理解
    【随机过程】随机过程之泊松过程的直观理解
    【读书笔记】程序员的自我修养总结(四)
    【读书笔记】程序员的自我修养总结(四)
    【编程开发】CMake相关注意事项
    【编程开发】CMake相关注意事项
    【随机过程】几种容易混淆的概率分布
    【随机过程】几种容易混淆的概率分布
    【DSP开发】DSP能用VS2010生成的链接库文件吗?
    【DSP开发】DSP能用VS2010生成的链接库文件吗?
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/11286296.html
Copyright © 2020-2023  润新知