预计阅读本页时间:-
C最初并没有被设计为一种国际化的编程语言。它的字符选择或多或少是基于标准的美国键盘的。但是C在国际上的流行导致产生了一些扩展来支持不同而且是更大的字符集。这部分参考内容提供了对这些附加功能的总览。
B.7.1 三元字符序列
有些键盘不提供C中使用的所有符号。因此C使用一组三字符序列为一些符号提供了可选的表示方法,这称为三元字符序列(trigraph sequence)。表B.54列出了这些三元字符。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
表B.54 三元字符序列
三 元 字 符 | 符 号 | 三 元 字 符 | 符 号 | 三 元 字 符 | 符 号 |
---|---|---|---|---|---|
??= | # | ??( | [ | ??/ | \ |
??) | ] | ?? ' | ^ | ??< | { |
??! | | | ??> | } | ??- | ~ |
C使用对应的符号来替换源代码文件中出现的所有这些三元字符,即使它们是在引用字符串中也是如此。这样:
就变成了下面的样子:
您可以通过开启一个编译器标志来激活这个特性。
B.7.2 二元字符
由于认识到了三元字符系统的笨拙,C99提供了称为二元字符(digraph)的双字符语言符号,可以使用它们来代替标准C中的某些标点。表B.55列出了这些二元字符。
表B.55 二元字符
二 元 字 符 | 符 号 | 二 元 字 符 | 符 号 | 二 元 字 符 | 符 号 |
---|---|---|---|---|---|
< : | [ | :> | ] | <% | { |
%< | } | %: | # | %: %: | ## |
与三元字符不同,引号中的字符串里的二元字符没有特别的含义。所以:
与下面的代码相同:
B.7.3 可选的拼写:iso646.h
使用三元字符序列,可以把||运算符写作??!??!,这可能看上去有些不大舒服。C99通过iso646.h头文件提供了表B.56中列出的可展开为运算符的宏。标准把这些宏称为可选的拼写(alternative spelling)。
表B.56 可选的拼写
宏 | 运 算 符 | 宏 | 运 算 符 | 宏 | 运 算 符 * |
---|---|---|---|---|---|
and | && | and_eq | &= | bitand | & |
bitor | | | compl | ~ | not | ! |
not_eq | ! = | or | || | or_eq | | = |
xor | ^ | xor_eq | ^= |
如果包含了iso646.h头文件,下面的语句:
就被展开成这样:
B.7.4 多字节字符
标准把多字节字符说明为一个单字节序列或多字节序列,它代表源环境或执行环境中扩展字符集的成员。源环境是您在其中准备源代码的环境,而执行环境是您在其中运行编译过的程序的环境。这两个可以不同,例如,您可以在一个环境中开发在另一个环境中运行的程序。扩展字符集是C所需的基本字符集的超集。
例如,一种实现可以提供一个扩展的字符集来允许您输入不对应于基本字符集的键盘字符。它们可以用在字符串或字符常量中,也可以出现在文件中。一种实现也可以提供基本字符集中字符的多字节等价物,可以使用它们来代替二元字符或三元字符。
例如,德国的一种实现也许会允许您在字符串中使用日尔曼语系字符:
B.7.5 通用字符名(UCN)
多字节字符可以用在字符串中,但是不能用在标识符中。通用字符名(UCN)是C99的增加功能,它允许您使用扩展字符集中的字符作为标识符名的一部分。系统扩展了转义序列的概念,允许对ISO/IEC 10646标准中的字符编码。这个标准是国际标准化组织(ISO)和国际电工委员会(IEC)共同制订的,它为大量的字符提供了数值编码。
有两种形式的UCN序列。第一种是\u hexquad,其中hexquad是4个十六进制数字的序列,例如\u00F6。第二种是\U hexquad hexquad,例如\U0000_AC01。因为每个十六进制数字都对应4个位,所以\u形式可以用作16位整数表示的编码,而\U形式可以用作32位整数表示的编码。
如果您的系统实现了UCN并包含了扩展字符集中想要的字符,您就可以在字符串、字符常量和标识符中使用UCN:
B.7.6 宽字符
C99通过wchar.h和wctype.h库中对宽字符的使用对更大的字符集提供了更多的支持。这些头文件把wchar_t定义为整数类型,确切的类型要依赖于实现。它用来保存扩展字符集中的字符,这个字符集是基本字符集的超集。根据定义,char类型已经足够处理基本字符集。wchar_t类型需要更多位数来处理更大范围的编码值。例如char可能是8位的字节,wchar_t可能是16位的unsigned short。
宽字符常量和字符串使用L前缀来表示,可以使用%1c和%1s修饰符来显示宽字符数据:
例如,如果wchar_t实现为2个字节单元,那么T的单字节编码就存储在wch的低位字节中。不是来自标准集的字符需要使用两个字节来存储字符编码。例如,可以使用通用字符编码来表示编码值超出char的范围的字符:
wchar_t数组可以保存宽字符的字符串,其中每个元素保存单个宽字符编码。编码值为0的wchar_t值是空字符的wchar_t等价字符,它被称为空的宽字符(null wide character)。它用来结束宽字符的字符串。
可以使用%1c和%1s修饰符读入宽字符:
wchar.h头文件提供了更多的宽字符支持。具体地,它提供了宽字符I/O函数、宽字符转换函数和宽字符字符串的操作函数。它们中大多数都是现有函数在宽字符中的对应。例如,可以使用fwprintf()和wprintf()函数进行输出,使用fwscanf()和wscanf()函数进行输入。主要的不同在于这些函数要求宽字符控制字符串,而且处理宽字符的输入输出流。例如,下列代码把信息作为宽字符序列显示:
与之类似,存在getwchar()、putwchar()、fgetws()和fputws()函数。这个头文件定义了一个WEOF宏,它与EOF在面向字节的I/O中所起的作用相同。要求它是一个不对应于合法字符的值。因为有可能所有wchar_t类型的值都是合法的字符,所以库中定义了一个wint_t类型,它包括所有的wchar_t值和WEOF。
也存在与string.h中的库函数对应的函数。例如,wcscopy(ws2, ws1)把ws1指向的宽字符字符串复制到ws2指向的宽字符数组中。类似地,也有用来比较宽字符串的wcscmp()函数,等等。
wctype.h头文件还为宽字符增加了字符分类函数。例如,如果参数是一个数字,iswdigit()函数就返回真;如果参数为空白,iswblank()函数就返回真。空白的标准值是空格和水平制表符,分别写作L‘’和L‘\t’。
B.7.7 宽字符和多字节字符
宽字符和多字节字符是处理扩展字符集的两种不同方法。例如,多字节字符可以具有一个、两个、三个或更多的字节,而所有的宽字符都只有一个宽度。多字节字符可以具有一个偏移状态,也就是一个用来确定后续字节如何解释的字节,而宽字符没有。一个多字节字符的文件可以使用标准的输入函数来读入到普通的char数组中,一个宽字符的文件也可以使用宽字符输入函数之一来读入到宽字符数组中。
C99通过wchar.h库提供了在这两种表示方法之间进行转换的函数。mbrtowc()函数把多字节字符转换成宽字符,而wcrtomb()函数把宽字符转换成多字节字符。类似地,mbstrtowcs()函数把多字节字符串转换为宽字符的字符串,而wcstrtombs()函数把宽字符的字符串转换为多字节字符串。