现在的位置: 首页 > 综合 > 正文

从char/wchar_t到TCHAR

2013年04月07日 ⁄ 综合 ⁄ 共 4552字 ⁄ 字号 评论关闭

一.ANSIUNICODE

1.为什么要使用UNICODE 

1) 可以很容易地在不同语言之间进行数据交换。

2) 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。

3) 提高应用程序的运行效率。

Windows 2000是使用UNICODE从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成UNICODE,然后将UNICODE字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将UNICODE字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用UNICODE来开发应用程序,就能够使你的应用程序更加有效地运行。

Windows 98只支持ANSI,只能为开发ANSI应用程序。 Windows CE 就是使用UNICODE的操作系统,完全不支持ANSI版函数。

MicrosoftCOMWin16转换成Win32时,所有COM接口方法都只能接受UNICODE字符串。

2ANSI字符和UNICODE字符

ANSI字符类型为CHAR,指向字符串的指针PSTR(LPSTR),指向一个常数字符串的指针PCSTR(LPCSTR);对应的Windows定义的UNICODE字符类型为WCHARtypedef WCHAR wchar_t),指向UNICODE字符串的指针PWSTR ,指向一个常数UNICODE字符串的指针PCWSTR

ANSI "ANSI";

UNICODE L"UNICODE";

ANSI/UNICODE _T("string") or _TEXT("string");

3ANSI字符和UNICODE字符串的操作

双字节(DBCS)字符集中,字符串的每个字符可以包含一个或两个字节。如果只是调用strlen()函数,那么你就无法知道字符串到底有多少个字符,它只能告诉你到达结尾的0之前有多少个字节。

标准c中的strcpy,strchr,strcat等只能用于ANSI字符串,不能正确处理UNICODE字符串,因此也提供了一组补充函数,功能等价,但用于UNICODE码。我们来看看string .h字符串头文件中是怎样处理char*wchar_t*两个字符串版本的:

// …/Microsoft Visual Studio 8/VC/include/string.h

char *strcat(char*,const char*);

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

类似的还有strchr/wcschrstrcmp/wcscmpstrlen/wcslen etc. ANSI 操作函数以str开头 strcpy UNICODE 操作函数以wcs开头 wcscpy

MBCS 操作函数以_mbs开头 _mbscpy

ANSI/UNICODE 操作函数以_tcs开头 _tcscpyC运行期库)

ANSI/UNICODE 操作函数以lstr开头 lstrcpyWindows API-KERNEL32.DLL

所有新的和未过时的函数在Windows2000中都同时拥有ANSIUNICODE两个版本。ANSI版本函数结尾以A表示;UNICODE版本函数结尾以W表示。操作系统根据是否定义了UNICODE宏来调用合适版本的API

    Windows XP默认字符集为gbk(包含gb2312)。wchar_t wcs[] = {0xCD, 0xCD, 0xEE, 0xFE, 0x00};表示汉字“屯铪”。参考在线汉字编码查询

 

二.ANSI/UNICODE通用字符/字符串类型TCHAR/LPTSTR/LPCTSTR

<1>_UNICODE宏用于C运行期头文件(如下_tprintf示例),UNICODE宏则用于Windows头文件(如上winnt.h),当编译代码模块时,通常必须同时定义这两个宏或都不定义。

winnt.h中定义了TEXT__TEXT)宏,用于做UNICODE环境的自适应。对于非UNICODE环境,__TEXT宏不对参数quote做任何处理;对于UNICODE环境,__TEXT宏在字符串quote前添加L宏,以表示宽字符串(wchar_t[])

// #include <winnt.h>

typedef CHAR char;

typedef WCHAR wchar_t;

 

#ifdef  UNICODE                    // r_winnt

typedef WCHAR TCHAR, *PTCHAR;

typedef WCHAR *LPWSTR;

typedef LPWSTR LPTSTR;

typedef CONST WCHAR *LPCWSTR;

typedef LPCWSTR LPCTSTR;

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

#else   /* UNICODE */             // r_winnt

typedef CHAR TCHAR, *PTCHAR;

typedef CHAR *LPSTR;

typedef LPSTR LPTSTR;

typedef CONST CHAR *LPCSTR,

typedef LPCSTR LPCTSTR;

#define __TEXT(quote) quote

#endif /* UNICODE */             // r_winnt

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

MicrosoftVC提供了tchar.h头文件用于字符集的自适应(To be used for compatibility between single-byte, multi-byte and Unicode text models)。对常用的函数做了T定义,例如_tprintf

// #include <tchar.h>

#ifdef  _UNICODE

#define __T(x)      L ## x

typedef wchar_t     TCHAR;

#define _tprintf    wprintf

#else   /* ndef _UNICODE */

#define __T(x)      x

#define _tprintf    printf

#endif /* _UNICODE */

#define _T(x)       __T(x)

#define _TEXT(x)    __T(x)

<2>如果定义了_UNICODE,若要生成一个UNICODE字符串,字符串前要加L宏,用于告诉编译器该字符串应该作为UNICODE字符串来编译处理。但是这样又有个问题就是如果没有定义_UNICODE则编译出错。为了解决这个问题我们必须用到_T(_TEXT)宏,同winnt.h中定义的TEXT__TEXT)宏。使用该宏后,无论源文件有没有定义_UNICODE都不会出现编译错误。

<3>ANSIUNICODE的一些互操作QA

Q1:如何判断一个文本文件是ANSI还是Unicode

A1:如果文本文件的开头两个字节是0xFF0xFE,那么就是Unicode,否则是ANSI

Q2:如何判断一段字符串是ANSI还是Unicode

A2:用IsTextUnicode进行判断。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此 IsTextUnicode有可能返回不正确的结果。

Q3:如何在UnicodeANSI之间转换字符串?

A3Windows函数MultiByteToWideChar/mbstowcs函数用于将多字节字符串转换成宽字符串,函数WideCharToMultiByte/wcstombs将宽字符串转换成等价的多字节字符串。

 

三.ANSI/UNICODE字符串通用函数lstrcpy/lstrcmp/lstrcat/lstrlen

ntdll.dll中实现了许多CRT基本函数:

strlen/wcslenstrcpy/wcscpystrncpy/wcsncpystrcat/wcscatstrncat/wcsncatstrcmp/wcscmpstrncmp/wcsncmpstrchr/wcschrstrrchr/wcsrchrstrstr/wcsstrsprintf/swprintfstrtol/wcstolstrtoul/wcstoul

kernel32.dll(依赖ntdll.dll)中实现了:

lstrlen(lstrlenA/lstrlenW)lstrcpy(lstrcpyA/lstrcpyW)lstrcpyn(lstrcpynA/lstrcpynW)lstrcat(lstrcatA/lstrcatW)lstrcmp(lstrcmpA/lstrcmpW)lstrcmpi(lstrcmpiA/lstrcmpiW)

// /Microsoft Visual Studio 8/VC/PlatformSDK/Include/Winbase.h(已包含在windows.h中)

WINBASEAPI

LPSTR

WINAPI

lstrcpyA(

    __out LPSTR lpString1,

    __in  LPCSTR lpString2

    );

WINBASEAPI

LPWSTR

WINAPI

lstrcpyW(

    __out LPWSTR lpString1,

    __in  LPCWSTR lpString2

    );

#ifdef UNICODE

#define lstrcpy  lstrcpyW

#else

#define lstrcpy  lstrcpyA

#endif // !UNICODE

 

四.使用shlwapi头文件中定义的函数StrCat/StrCmp/StrCpy

Shlwapi.dll(依赖kernel32.dll)是UNCURL地址动态链接库文件,用于注册键值和色彩设置。因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。这将有助于稍稍提高应用程序的运行性能。

注意:使用StrCatStrCmpStrCpy etc时要

#include <Shlwapi.h>

#pragma comment(lib, "Shlwapi.lib")

// …/Microsoft Visual Studio 8/VC/PlatformSDK/Include/Shlwapi.h

LWSTDAPI_(LPWSTR)   StrCatW(LPWSTR psz1, LPCWSTR psz2);

LWSTDAPI_(int)      StrCmpW(LPCWSTR psz1, LPCWSTR psz2);

LWSTDAPI_(LPWSTR)   StrCpyW(LPWSTR psz1, LPCWSTR psz2);

#ifdef UNICODE

#define StrCat      StrCatW

#define StrCmp      StrCmpW

#define StrCpy      StrCpyW

#else

#define

抱歉!评论已关闭.