目录
本篇原文为:C语言Unicode编码与多字节字符处理详解。
更多C++进阶、rust、python、逆向等等教程,可点击此链接查看:酷程网
1.Unicode 简介
C 语言诞生时,只考虑了英语字符,使用7位的 ASCII 码表示所有字符。ASCII 码的范围是0到127,也就是最多只能表示100多个字符,用一个字节就可以表示,所以char
类型只占用一个字节。
但是,如果处理非英语字符,一个字节就不够了,单单是中文,就至少有几万个字符,字符集就势必使用多个字节表示。
最初,不同国家有自己的字符编码方式,这样不便于多种字符的混用。因此,后来就逐渐统一到 Unicode 编码,将所有字符放入一个字符集。
Unicode 为每个字符提供一个号码,称为码点(code point),其中0到127的部分,跟 ASCII 码是重合的。通常使用“U+十六进制码点”表示一个字符,比如U+0041
表示字母A
。
Unicode 编码目前一共包含了100多万个字符,码点范围是 U+0000 到 U+10FFFF。完整表达整个 Unicode 字符集,至少需要三个字节。但是,并不是所有文档都需要那么多字符,比如对于 ASCII 码就够用的英语文档,如果每个字符使用三个字节表示,就会比单字节表示的文件体积大出三倍。
为了适应不同的使用需求,Unicode 标准委员会提供了三种不同的表示方法,表示 Unicode 码点。
- UTF-8:使用1个到4个字节,表示一个码点。不同的字符占用的字节数不一样。
- UTF-16:对于U+0000 到 U+FFFF 的字符(称为基本平面),使用2个字节表示一个码点。其他字符使用4个字节。
- UTF-32:统一使用4个字节,表示一个码点。
其中,UTF-8 的使用最为广泛,因为对于 ASCII 字符(U+0000 到 U+007F),它只使用一个字节表示,这就跟 ASCII 的编码方式完全一样,更加详细的介绍可以参考文章:编码。
C 语言提供了两个宏,表示当前系统支持的编码字节长度。这两个宏都定义在头文件limits.h
。
MB_LEN_MAX
:任意支持地区的最大字节长度,定义在limits.h
。MB_CUR_MAX
:当前语言的最大字节长度,总是小于或等于MB_LEN_MAX
,定义在stdlib.h
。
2.字符的表示方法
字符表示法的本质,是将每个字符映射为一个整数,然后从编码表获得该整数对应的字符。
C 语言提供了不同的写法,用来表示字符的整数号码。
\123
:以八进制值表示一个字符,斜杠后面需要三个数字。\x4D
:以十六进制表示一个字符,\x
后面是十六进制整数。\u2620
:以 Unicode 码点表示一个字符(不适用于 ASCII 字符),码点以十六进制表示,\u
后面需要4个字符。\U0001243F
:以 Unicode 码点表示一个字符(不适用于 ASCII 字符),码点以十六进制表示,\U
后面需要8个字符。
printf("ABC\n");
printf("\101\102\103\n");
printf("\x41\x42\x43\n");
上面三行都会输出“ABC”。
printf("\u2022 Bullet 1\n");
printf("\U00002022 Bullet 1\n");
上面两行都会输出“• Bullet 1”。
3.多字节字符的表示
C 语言预设只有基本字符才能使用字面量表示,其它字符都应该使用码点表示,并且当前系统还必须支持该码点的编码方法。
所谓基本字符,指的是所有可打印的 ASCII 字符,但是有三个字符除外:@
、$
、`
。
因此,遇到非英语字符,应该将其写成 Unicode 码点形式。
char* s = "\u6625\u5929";
printf("%s\n", s); // 春天
上面代码会输出中文“春天”。
如果当前系统是 UTF-8 编码,可以直接用字面量表示多字节字符。
char* s = "春天";
printf("%s\n", s);
注意,\u + 码点
和\U + 码点
的写法,不