多字节字符集 (MBCS) 是一种替代 Unicode 以支持无法用单字节表示的字符集(如日文和中文)的方法。为国际市场编程时应考虑使用 Unicode 或 MBCS,或使程序能够通过更改开关来生成支持两种字符集之一的程序。
最常见的 MBCS 实现是双字节字符集 (DBCS)。一般来说,Visual C++(尤其是 MFC)完全支持 DBCS。
有关示例,请参见 MFC 源代码文件。
对于语言使用大字符集的市场所使用的平台,代替 Unicode 的最佳方法是 MBCS。MFC 通过使用可国际化的数据类型和 C 运行时函数来支持 MBCS。您也应在自己的代码中这样操作。
在 MBCS 下,字符被编码为单字节或双字节。在双字节字符中,第一个字节(即前导字节)表示它和下一个字节将被解释为一个字符。第一个字节来自留作前导字节的代码范围。哪个范围的字节可以用作前导字节取决于所使用的代码页。例如,日文代码页 932 使用 0x81 到 0x9F 范围内的字节作为前导字节,而朝鲜语代码页 949 则使用其他范围的字节。
在 MBCS 编程中需考虑下列所有因素。
-
环境中的 MBCS 字符
-
MBCS 字符可以出现在文件名和目录名等字符串中。
-
编辑操作
-
MBCS 应用程序上的编辑操作应在字符上操作,而非在字节上操作。插入符号不应拆分字符,向右键应向右移动一个字符等。Delete 应删除一个字符;Undo 则应将字符重新插入。
-
字符串处理
-
在使用 MBCS 的应用程序中,字符串处理引起特殊问题。两种宽度的字符混合在一个字符串中;因此必须记住检查前导字节。
-
运行时库支持
-
C 运行时库和 MFC 支持单字节、MBCS 和 Unicode 编程。单字节字符串用 str 运行时函数族处理,MBCS 字符串用相应的 _mbs 函数处理,而 Unicode 字符串用相应的 wcs 函数处理。MFC 类成员函数的实现使用可移植运行时函数,这些可移植运行时函数在正常情况下映射到标准 str 函数族、MBCS 函数或 Unicode 函数,如“MBCS/Unicode 可移植性”中所述。
-
MBCS/Unicode 可移植性
使用 Tchar.h 头文件可以用同一个源生成单字节的 MBCS 应用程序和 Unicode 应用程序。Tchar.h 定义以 _tcs 为前缀的宏,这些宏根据相应的情况映射到 str、_mbs 或 wcs 函数。若要生成 MBCS,请定义 _MBCS 符号。若要生成 Unicode,请定义 _UNICODE 符号。默认情况下,为 MFC 应用程序定义的是 _MBCS。有关更多信息,请参见 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); |
因此可以编写、维护和编译与三种字符集中任何一种的特定例程一起运行的单个源代码文件。