先说ASCII
ASCII 字符集在 0x00 到 0x7F 的范围内定义字符。还有其他一些字符集(主要是欧洲字符),它们在 0x00 到 0x7F 的范围内定义与 ASCII 字符集相同的字符,还在 0x80 到 0xFF 的范围内定义了扩展字符集。因此,8 位的单字节字符集 (SBCS) 足以表示 ASCII 字符集以及许多欧洲语言的字符集。但是,一些非欧洲字符集(如汉字)包含许多单字节代码方案无法表示的字符,因此要求使用多字节字符集 (MBCS) 编码。
再说Unicode
Unicode 是为所有语言提供足够编码的 16 位字符编码。所有 ASCII 字符都作为“加宽”字符包含在 Unicode 中。宽字符是双字节多语言字符代码。在当今的全球计算业内使用的大多数字符(包括技术符号和特殊的发布字符),都可以根据 Unicode 规范表示为宽字符形式。
宽字符字符串表示为一个 wchar_t[] 数组并由 wchar_t* 指针指向它。可以通过用字母 L 作为字符的前缀将任何 ASCII 字符表示为宽字符形式。例如,L'\0' 是终止宽(16 位)NULL 字符。同样,可以通过用字母 L 作为 ASCII 字符串的前缀 (L"Hello") 将任何 ASCII 字符串表示为宽字符字符串形式。
通常,宽字符在内存中占用的空间比多字节字符多,但处理速度更快。另外,在多字节编码中一次只能表示一个区域设置,而世界上的所有字符集都同时以 Unicode 表示形式表示。
除数据库类外,MFC 框架完全支持 Unicode。(ODBC 不支持 Unicode。)MFC 通过始终使用可移植的宏来实现对 Unicode 的支持,如下表所示:
不可移植的数据类型 | 由该宏替换 |
---|---|
char | _TCHAR |
char*, LPSTR(Win32 数据类型) | LPTSTR |
const char*, LPCSTR(Win32 数据类型) | LPCTSTR |
CString 类使用 _TCHAR 作为基,并提供构造函数和运算符以方便转换。可以通过使用与处理 Windows ANSI 字符集相同的逻辑来编写大多数 Unicode 的字符串操作(只是基本操作单位是 16 位字符,而非 8 位字节)。与使用多字节字符集 (MBCS) 不同,不必(也不应)将 Unicode 字符视为两个不同的字节。
多字节字符集MBCS (其实主要是DBS,双字节)
代替 Unicode 的最佳方法是 MBCS!!
在 MBCS 下,字符被编码为单字节或双字节。在双字节字符中,第一个字节(即前导字节)表示它和下一个字节将被解释为一个字符。第一个字节来自留作前导字节的代码范围。哪个范围的字节可以用作前导字节取决于所使用的代码页。例如,日文代码页 932 使用 0x81 到 0x9F 范围内的字节作为前导字节,而朝鲜语代码页 949 则使用其他范围的字节。
让你的代码既支持UNICODE又支持MBCS
方法:#include "tchar.h"
为简化代码传输以方便国际使用,Microsoft 运行时库为许多数据类型、例程和其他对象提供 Microsoft 特定的“一般文本”映射。您可以使用 Tchar.h 中定义的这些映射,根据使用#define 语句定义的清单常数,编写可以为单字节、多字节或 Unicode 编译的一般代码。一般文本映射是与 ANSI 不兼容的 Microsoft 扩展。
使用 Tchar.h 可以从同一个源中生成单字节、MBCS 和 Unicode 应用程序。Tchar.h 定义以 _tcs 为前缀的宏,这些宏根据正确的预处理器定义映射到适当的 str、_mbs 或 wcs 函数。若要生成 MBCS,请定义 _MBCS 符号。若要生成 Unicode,请定义 _UNICODE 符号。若要生成单字节应用程序,请不进行任何定义(默认)。默认情况下,为 MFC 应用程序定义的是 _MBCS。
在 Tchar.h 中根据条件定义 _TCHAR 数据类型。如果为您的版本定义了 _UNICODE 符号,则 _TCHAR 被定义为 wchar_t;否则,对于单字节和 MBCS 版本,_TCHAR 被定义为 char。((wchar_t 是基本的 Unicode 宽字符数据类型,它是 8 位有符号 char 的 16 位对等项。)对于国际应用程序,使用以 _TCHAR(而非字节)为单位进行操作的 _tcs 函数族。例如,_tcsncpy 复制 n 个 _TCHAR,而不是 n 个字节。
由于某些 SBCS 字符串处理函数采用(有符号的)char* 参数,因此定义 _MBCS 时将产生类型不匹配的编译器警告。有三种方法避免此警告,按效率高低的顺序依次为:
-
在 Tchar.h 中使用类型安全内联函数 thunk。这是默认行为。
-
通过在命令行上定义 _MB_MAP_DIRECT,在 Tchar.h 中使用直接宏。如果这样做,必须手动匹配类型。这是最快的方法,但不是类型安全的方法。
-
在 Tchar.h 中使用“类型安全”静态链接库函数 thunk。若要这样做,请在命令行上定义 _NO_INLINING 常数。这是最慢的方法,但却是类型安全性最高的方法。
# define | 编译版本 | 示例 |
---|---|---|
_UNICODE | Unicode(宽字符) | _tcsrev 映射到 _wcsrev |
_MBCS | 多字节字符 | _tcsrev 映射到 _mbsrev |
无(默认:既未定义 _UNICODE 也未定义 _MBCS) | SBCS (ASCII) | _tcsrev 映射到 strrev |
例如,如果在程序中定义了 _MBCS,则 Tchar.h 中定义的一般文本函数 _tcsrev 映射到 _mbsrev。或者如果在程序中定义了 _UNICODE,则 _tcsrev 映射到 _wcsrev。否则 _tcsrev 映射到 strrev。在 Tchar.h 中还提供了其他数据类型映射以方便编程,但 _TCHAR 是最有用的。
一般文本 数据类型名称 | _UNICODE 和 _MBCS 未定义 | _MBCS 已定义 | _UNICODE 已定义 |
---|---|---|---|
_TCHAR | char | char | wchar_t |
_TINT | int | int | wint_t |
_TSCHAR | signed char | signed char | wchar_t |
_TUCHAR | unsigned char | unsigned char | wchar_t |
_TXCHAR | char | unsigned char | wchar_t |
_T 或 _TEXT | 无效(由预处理器移除) | 无效(由预处理器移除) | L(将后面的字符或字符串转换成相应的 Unicode 形式) |
有关例程、变量和其他对象的一般文本映射的完整列表,请参见“运行时库参考”中的一般文本映射。
注意 |
---|
Unicode 字符串有可能包含嵌入空字节,所以不要在 Unicode 字符串中使用 str 函数族。同样道理,不要在 MBCS(或 SBCS)字符串中使用 wcs 函数族。 |
下列代码片段阐释了有关映射到 MBCS、Unicode 和 SBCS 模型的 _TCHAR 和 _tcsrev 的用法。
_TCHAR *RetVal, *szString;
RetVal = _tcsrev(szString);
如果已定义 _MBCS,则预处理器将此片段映射到下列代码:
char *RetVal, *szString;
RetVal = _mbsrev(szString);
如果已定义 _UNICODE,则预处理器将此片段映射到下列代码:
wchar_t *RetVal, *szString;
RetVal = _wcsrev(szString);
如果既未定义 _MBCS 也未定义 _UNICODE,则预处理器将此片段映射到单字节 ASCII 代码:
char *RetVal, *szString;
RetVal = strrev(szString);
因此可以编写、维护和编译与三种字符集中任何一种的特定例程一起运行的单个源代码文件。