从char/wchar_t到TCHAR

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

 

注意:使用StrCatStrCmpStrCpy 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 默认TCHARwchar 而不是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/StrCatsprintf/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

以下是D3DVS2003 移植到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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值