文章目录
单字节和多字节字符集:SBCS vs MBCS单字节字符集(SBCS)多字节字符集(MBCS)SBCS和MBCS的数据类型
Unicode:宽字符集TCHAR.H中的通用文本映射通用文本映射的预处理程序指令通用文本数据类型的映射TCHAR映射举例
字符处理函数参考链接
单字节和多字节字符集:SBCS vs MBCS
单字节字符集(SBCS)
ASCII字符集定义的是0x00 - 0x7F范围内的字符。
还有许多其他字符集,主要是欧洲字符集,它们在与0x字符集相同的范围内定义0x00 - 0x7F范围内的字符,并且还定义了0x80 - 0xFF的扩展字符集。 因此,一个8位的单字节字符集(SBCS)足以表示ASCII字符集以及许多欧洲语言的字符集。但是,一些非欧洲字符集(如日语汉字)包含的字符数多于单字节编码方案中可以表示的字符数,因此需要多字节字符集(MBCS)编码。
多字节字符集(MBCS)
多字节字符集可以包含单字节和双字节字符。因此,多字节字符串可以包含单字节和双字节字符的混合。双字节多字节字符具有前导字节和跟踪字节。在特定的多字节字符集中,前导字节落在特定范围内,跟踪字节也是如此。当这些范围重叠时,可能需要评估特定上下文以确定给定字节是作为前导字节还是跟踪字节。
SBCS和MBCS的数据类型
处理字符串上下文中的多字节字节或字符的MBCS要求将多字节字符串表示为unsigned char指针。 多字节字符的每个字节可以用8位字符表示。但是,类型为char且值大于0x7F 的SBCS或MBCS单字节字符为负数。当这样的字符直接转换为int或long时,结果会被编译器进行符号扩展,因此会产生意外的结果。
最好将多字节字符的字节表示为8位unsigned char,以避免负的结果。 由于某些SBCS字符串处理函数采用(带符号)char *参数,因此在定义_MBCS时将产生类型不匹配编译器警告。 有三种方法可以避免此警告,按效率顺序列出:
在TCHAR.H中使用类型安全的内联函数。这是默认行为。通过在命令行上定义_MB_MAP_DIRECT,在TCHAR.H中使用直接宏。如果执行此操作,则必须手动匹配类型。这是最快的方法,但不是类型安全的。在TCHAR.H中使用类型安全的静态链接库函数。为此,请在命令行上定义常量_NO_INLINING。这是最慢的方法,但是最安全的类型。
Unicode:宽字符集
Unicode 是 16 位字符编码、 为适用于所有语言提供足够的编码。 所有的 ASCII 字符以 unicode 格式作为加宽字符包含在内。宽字符是2字节多语言字符代码。全世界现代计算中使用的任何字符,包括技术符号和特殊发布字符,都可以根据Unicode规范表示为宽字符。由包括Microsoft在内的大型联盟开发和维护,Unicode标准现已被广泛接受。支持多字节字符集 (MBCS) 的窗体在所有平台上称为双字节字符集 (DBCS)。 DBCS 字符由 1 或 2 个字节构成。 某些范围的字节将留出使用用作前导字节。 前导字节指定它和以下结尾字节构成单个的 2 个字节宽字符。 在特定的多字节字符集中,前导字节位于某个范围内,尾字节也是如此。 这些范围重叠时,可能需要计算上下文以确定某个给定的字节用作前导字节还是尾字节。
宽字符的类型为wchar_t。宽字符串表示为wchar_t []数组,并由wchar_t*指针指向。 可以通过在字符前添加L前缀来将任何ASCII字符表示为宽字符。例如,L’\ 0’是终止符的宽字符(16位)。类似地,也可以将任何ASCII字符串表示为宽字符串,只需在ASCII字符串前加上字母L(L“Hello”)。
通常,宽字符在内存中占用的空间比多字节字符多,但处理速度更快。此外,在多字节编码中一次只能表示一个语言环境,而世界上的所有字符集都由Unicode表示同时表示。
TCHAR.H中的通用文本映射
为简化各种国际市场的代码开发,Microsoft运行时库为许多数据类型和对象提供Microsoft特定的“通用文本”映射。这些映射在TCHAR.H中定义。 可以使用这些名称映射来编写ASCII(SBCS),MBCS或Unicode三种字符集中任何一种的通用代码,具体取决于使用#define语句定义的常量。通用文本映射是不兼容ANSI的Microsoft扩展。
通用文本映射的预处理程序指令
#define编译版例
_UNICODEUnicode(宽字符)_tcsrev 映射到 _wcsrev_MBCS多字节字符_tcsrev 映射到 _mbsrev无(默认值:既未定义_UNICODE,也未定义_MBCS)SBCS(ASCII)_tcsrev 映射到 strrev
例如,通用的文本功能_tcsrev,在TCHAR.H定义,如果MBCS已被定义则映射到mbsrev,如果_UNICODE已被定义则映射到_wcsrev,否则_tcsrev映射到strrev。
通用文本数据类型的映射
通用文本数据类型名称SBCS(_UNICODE,_MBCS未定义)_MBCS已定义_UNICODE已定义
_TCHARcharcharwchar_t_TINTintintwint_t_TSCHARsigned charsigned charwchar_t_TUCHARunsigned charunsigned charwchar_t_TXCHARcharunsigned charwchar_t_T 或 _TEXT没有效果没有效果L (将后续字符或字符串转换为Unicode项)
TCHAR映射举例
以下代码片段说明了使用_TCHAR和_tcsrev映射到MBCS,Unicode和SBCS模型。
_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);
因此,可以编写、维护和编译统一的源代码文件,实现三种字符集下的运行。
字符处理函数
常规使用setlocale类别设置依赖
atof,_atof_l,_wtof,_wtof_l将字符转换为浮点值LC_NUMERICatoi,_atoi_l,_wtoi,_wtoi_l将字符转换为整数值LC_NUMERIC_atoi64,_atoi64_l,_wtoi64,_wtoi64_l将字符转换为64位整数值LC_NUMERICatol,_atol_l,_wtol,_wtol_l将字符转换为长值LC_NUMERIC_atodbl,_atodbl_l,_atoldbl,_atoldbl_l,_atoflt,_atoflt_l将字符转换为double-long值LC_NUMERIC是常规针对特定条件测试给定整数。LC_CTYPEisleadbyte,_isleadbyte_l测试引导字节LC_CTYPElocaleconv读取用于格式化数字量的适当值LC_MONETARY, LC_NUMERICMB_CUR_MAX当前语言环境中任何多字节字符的最大长度(以字节为单位)(在STDLIB.H中定义的宏)LC_CTYPE_mbccpy,_mbccpy_l,_mbccpy_s,_mbccpy_s_l复制一个多字节字符LC_CTYPE_mbclen,mblen,_mblen_l验证并返回多字节字符的字节数LC_CTYPEstrlen,wcslen,_mbslen,_mbslen_l,_mbstrlen,_mbstrlen_l对于多字节字符串:验证字符串中的每个字符; 返回字符串长度LC_CTYPEmbstowcs,_mbstowcs_l,mbstowcs_s,_mbstowcs_s_l将多字节字符序列转换为相应的宽字符序列LC_CTYPEmbtowc,_mbtowc_l将多字节字符转换为相应的宽字符LC_CTYPEprintf函数写格式化输出LC_NUMERIC(确定基数字符输出)scanf功能读取格式化输入LC_NUMERIC(确定基数字符识别)setlocale,_wsetlocale选择程序的区域设置不适用strcoll,wcscoll,_mbscoll,_strcoll_l,_wcscoll_l,_mbscoll_l比较两个字符串的字符LC_COLLATE_stricmp,_wcsicmp,_mbsicmp,_stricmp_l,_wcsicmp_l,_mbsicmp_l比较两个字符串而不考虑大小写LC_CTYPE_stricoll,_wcsicoll,_mbsicoll,_stricoll_l,_wcsicoll_l,_mbsicoll_l比较两个字符串的字符(不区分大小写)LC_COLLATE_strncoll,_wcsncoll,_mbsncoll,_strncoll_l,_wcsncoll_l,_mbsncoll_l比较两个字符串的前n个字符LC_COLLATE_strnicmp,_wcsnicmp,_mbsnicmp,_strnicmp_l,_wcsnicmp_l,_mbsnicmp_l比较两个字符串的字符而不考虑大小写。LC_CTYPE_strnicoll,_wcsnicoll,_mbsnicoll,_strnicoll_l,_wcsnicoll_l,_mbsnicoll_l比较两个字符串的前n个字符(不区分大小写)LC_COLLATEstrftime,wcsftime,_strftime_l,_wcsftime_l根据提供的格式参数格式化日期和时间值LC_TIME_strlwr,_wcslwr,_mbslwr,_strlwr_l,_wcslwr_l,_mbslwr_l,_strlwr_s,_strlwr_s_l,_mbslwr_s,_mbslwr_s_l,_wcslwr_s,_wcslwr_s_l将给定字符串中的每个大写字母转换为小写LC_CTYPEstrtod,_strtod_l,wcstod,_wcstod_l将字符串转换为double值LC_NUMERIC(确定基数字符识别)strtol,wcstol,_strtol_l,_wcstol_l 将字符串转换为长值LC_NUMERIC(确定基数字符识别)strtoul,_strtoul_l,wcstoul,_wcstoul_l将字符串转换为无符号长值LC_NUMERIC(确定基数字符识别)_strupr,_strupr_l,_mbsupr,_mbsupr_l,_wcsupr_l,_wcsupr,_strupr_s,_strupr_s_l,_mbsupr_s,_mbsupr_s_l,_wcsupr_s,_wcsupr_s_l将字符串中的每个小写字母转换为大写LC_CTYPEstrxfrm,wcsxfrm,_strxfrm_l,_wcsxfrm_l根据区域设置将字符串转换为整理形式LC_COLLATEtolower,_tolower,towlower,_tolower_l,_towlower_l,_mbctolower,_mbctolower_l,_mbctoupper,_mbctoupper_l将给定字符转换为相应的小写字符LC_CTYPEtoupper,_toupper,towupper,_toupper_l,_towupper_l,_mbctolower,_mbctolower_l,_mbctoupper,_mbctoupper_l将给定字符转换为相应的大写字母LC_CTYPEwcstombs,_wcstombs_l,wcstombs_s,_wcstombs_s_l将宽字符序列转换为多字节字符的对应序列LC_CTYPEwctomb,_wctomb_l,wctomb_s,_wctomb_s_l将宽字符转换为相应的多字节字符LC_CTYPE
注意:
对于多字节代码,多字节代码页必须等同于使用setlocale设置的语言环境。_setmbcp,参数为_MB_CP_LOCALE,使多字节代码页与setlocale代码页相同。
参考链接
https://docs.microsoft.com/en-us/cpp/c-runtime-library/internationalization?view=vs-2019