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

原文地址:https://www.cnblogs.com/Mayfly-nymph/p/11286296.html