一. 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
etc
参考:
《 VC 中的 __T 宏》 http://www.diybl.com/course/3_program/vc/vc_js/2008830/138819.html