风机iec等级:从char/wchar_t到TCHAR

来源:百度文库 编辑:偶看新闻 时间:2024/04/28 08:41:29
 

从char/wchar_t到TCHAR

分类: win32 SDK2010-09-09 13:39 108人阅读 评论(0) 收藏 举报

一. ANSI 和UNICODE

 

.为什么要使用 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

etc

五.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 类库。

六. 更安全的 语言字符串处理函数 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 

#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.