从char/wchar_t到TCHAR (单字节 双字节 ANSI 和UNICODE)

来源:互联网 发布:unity3d人物走动 编辑:程序博客网 时间:2024/05/16 07:42
从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
注意:使用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
原创粉丝点击