Prayer

在一般中寻求卓越
posts - 1256, comments - 190, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

从char/wchar_t到TCHAR(转)

Posted on 2011-12-13 10:28 Prayer 阅读(1580) 评论(0)  编辑 收藏 引用 所属分类: C/C++

一.ANSI和UNICODE

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版函数。

Microsoft将COM从Win16转换成Win32时,所有COM接口方法都只能接受Unicode字符串。

2.ANSI字符和Unicode字符

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

ANSI “ANSI”

Unicode L“UNICODE”

ANSI/Unicode T(“string”)或_TEXT(“string”)

3.ANSI字符和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(wchat_t*, const wchar_t*);

类似的还有strchr/wcschr,strcmp/wcscmp,strlen/wcslen etc. ANSI 操作函数以str开头 strcpy ,Unicode 操作函数以wcs开头 wcscpy

MBCS 操作函数以_mbs开头 _mbscpy

ANSI/Unicode 操作函数以_tcs开头 _tcscpy(C运行期库)

ANSI/Unicode 操作函数以lstr开头 lstrcpy(Windows API)

所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版 本函数结尾以W表示。

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

Neutral ANSI/UNICODE types

1.通用字符型TCHAR

ifdef UNICODE  it is wchar_t(WCHAR)for Unicode platforms;

else it is char for ANSI and DBCS platforms.

2.通用字符串指针LPTSTR

ifdef UNICODE it is LPWSTR(*wchar_t) for  Unicode platforms;

else it is LPSTR (*char) for ANSI and DBCS platforms.

3.通用通用常数字符串指针LPCTSTR

ifdef  UNICODE it is LPCWSTR(*const wchar_t) for Unicode platforms;

else it is LPCSTR (*const char) for ANSI and DBCS platforms.

typedef LPWSTR LP;

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

<1>_UNICODE宏用于C运行期头文件,UNICODE宏则用于Windows头文件,当编译代码模块时,通常必须同时定义这两 个宏。

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

<3>Unicode与ANSI字符串的转换:Windows函数MultiByteToWideChar/mbstowcs函数用于 将多字节字符串转换成宽字符串,函数WideCharToMultiByte/wcstombs将宽字符串转换成等价的多字节字符串。

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

// …\Microsoft Visual Studio 8\VC\PlatformSDK\Include\Winbase.h -- 已经包含在windows.h中。

lstrcmp(lstrcmpi)

WINBASEAPI

int

WINAPI

lstrcmpA(

    __in LPCSTR lpString1,

    __in LPCSTR lpString2

    );

WINBASEAPI

int

WINAPI

lstrcmpW(

    __in LPCWSTR lpString1,

    __in LPCWSTR lpString2

    );

#ifdef UNICODE

#define lstrcmp  lstrcmpW

#else

#define lstrcmp  lstrcmpA

#endif // !UNICODE

lstrcpy

WINBASEAPI

__out

LPSTR

WINAPI

lstrcpyA(

    __out LPSTR lpString1,

    __in  LPCSTR lpString2

    );

WINBASEAPI

__out

LPWSTR

WINAPI

lstrcpyW(

    __out LPWSTR lpString1,

    __in  LPCWSTR lpString2

    );

#ifdef UNICODE

#define lstrcpy  lstrcpyW

#else

#define lstrcpy  lstrcpyA

#endif // !UNICODE

另外还有lstrcat(W/A)和lstrlen(W/A),这里未列出其函数定义。

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

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

// …\Microsoft Visual Studio 8\VC\PlatformSDK\Include\shlwapi.h

注意:使用StrCat、StrCmp、StrCpy etc时要#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 StrCat                  lstrcatA

#define StrCmp                  lstrcmpA

#define StrCpy                  lstrcpyA

五.MFC动态字符串类CString

// …\Microsoft Visual Studio 8\VC\atlmfc\include\afx.h

一个CString对象由可变长度的一队字符组成。CString使用类似于Basic的语法提供函数和操作符。连接和比较操作符以及简化的内存管 理使CString对象比普通字符串数组容易使用。

CString是基于TCHAR数据类型的对象。如果在你的程序中定义了符号_UNICODE,则TCHAR被定义为类型wchar_t,即16位 字符类型;否则,TCHAR被定义为char,即8位字符类型。在UNICODE方式下,CString对象由16位字符组成。非UNICODE方式 下,CString对象由8位字符组成。 而VS2005默认TCHAR是wchar而不是char.

当不使用_UNICODE时,CString是多字节字符集(MBCS,也被认为是双字节字符集,DBCS)。注意,对于MBCS字符 串,CString仍然基于8位字符来计算,返回,以及处理字符串,并且你的应用程序必须自己解释MBCS的开始和结束字节。

CString 提供 operator LPCTSTR 来在 CString 和 LPCTSTR 之间进行转换。

有关CString的操作请参考MSDN MFC类库。

六.更安全的C语言字符串处理函数 Strsafe.h

// …\Microsoft Visual Studio 8\VC\PlatformSDK\Include\strsafe.h

注意:使用StringCchCopy /StringCchPrintf时要#include  "strsafe.h".

STRSAFEAPI是为了解决现有的 C 语言运行时函数的代码太容易产生的“内存溢出”问题。当我们引用 strsafe 系列函数时,原有的 C 语言字符串处理函数都将被自动进行 #undef 处理。调试过程中的警告或出错信息将会告诉我们哪些函数哪些不安全,哪些已经被相应的 strsafe 系列函数取代了。 

//1.不赞成使用不安全的函数,以避免产生编译错误

//2.如果你不要安全处理,你可以在包含strsafe.h头文件之前,

#define STRSAFE_NO_DEPRECATE

#ifdef DEPRECATE_SUPPORTED

// First all the names that are a/w variants (or shouldn't be #defined by now anyway).

#pragma deprecated(strcpy)

#pragma deprecated(wcscpy)

#pragma deprecated(lstrcpy)

#pragma deprecated(StrCpy)

类似的Strcat/wcscat/lstrcat/StrCat,sprintf/wsprintf

以下是D3D中预编译头文件dxstdafx.h

#pragma warning( disable : 4996 ) //将报警置为无效

#include <strsafe.h>

#pragma warning( default : 4996 ) //将报警置为默认

有关#pragma warning请参考:http://hi.baidu.com/iceland9/blog/item/5af9c0bfd334de0a18d81f33.html

以下是D3D从VS2003移植到VS2005时遇到的安全警告:

warning C4996: 'wcscpy' was declared deprecated

see declaration of 'wcscpy'

Message: 'This function or variable may be unsafe.

Consider using wcscpy_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.'

warning C4995: 'lstrcpy': name was marked as #pragma deprecated

warning C4995: 'wsprintf': name was marked as #pragma deprecated

推荐使用新的安全可靠的TRSAFEAPI:

STRSAFEAPI

StringCchCopyA(

    __out_ecount(cchDest) STRSAFE_LPSTR pszDest,

    __in size_t cchDest,

    __in STRSAFE_LPCSTR pszSrc);

STRSAFEAPI

StringCchCopyW(

    __out_ecount(cchDest) STRSAFE_LPWSTR pszDest,

    __in size_t cchDest,

    __in STRSAFE_LPCWSTR pszSrc);

#ifdef UNICODE

#define StringCchCopy  StringCchCopyW (W为Wide Unicode)

#else

#define StringCchCopy  StringCchCopyA (A为ANSI)

#endif // !UNICODE

#undef strcpy

#define strcpy      strcpy_instead_use_StringCbCopyA_or_StringCchCopyA;

#undef wcscpy

#define wcscpy      wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW;

#undef wsprintf

#define wsprintf    wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf;

// Then all the windows.h names - we need to undef and redef based on UNICODE setting

#undef lstrcpy //取消已定义的宏

#pragma deprecated(lstrcpy) //安全警告

#ifdef UNICODE //使用UNICODE编程

#define lstrcpy    lstrcpyW //重定义

#else

#define lstrcpy    lstrcpyA //重定义

#endif

类似的有对lstrcat/wsprintf/wvsprintf的#undef,#pragma deprecated,#define。

推荐使用新的安全可靠的TRSAFEAPI:

#undef lstrcpy

#define lstrcpy     lstrcpy_instead_use_StringCbCopy_or_StringCchCopy;

// Then the shlwapi names - they key off UNICODE also.

#undef  StrCpy

#pragma deprecated(StrCpy)

#ifdef UNICODE

#define StrCpy  StrCpyW

#else

#define StrCpy  lstrcpyA

#endif

类似的有#undef StrCpyA /StrCpy /StrCatA /StrCat /StrNCat /StrCatN

以及对StrCpy/StrCat/StrNCat的#undef,#pragma deprecated,#define。

推荐使用新的安全可靠的TRSAFEAPI:

#undef StrCpy

#define StrCpy      StrCpy_instead_use_StringCbCopy_or_StringCchCopy;

// Then all the CRT names - we need to undef/redef based on _UNICODE value.

参考:

《VC中的__T宏》

http://www.diybl.com/course/3_program/vc/vc_js/2008830/138819.html

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/phunxm/archive/2009/12/26/5082618.aspx


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理