若干编码说明

一、gb2312
现在我们大部分的中国程序员编译的程序可执行代码中包含的都是gb2312编码,这些编码通常体现在代码中的字符串里。编译器对于这些字符串的内容并不做特殊解释,因为gb2312中的常用英文字符是和ASCII码兼容的。
根据编码的约定,通常的前32个字符是作为控制字符,也就是无法在屏幕上直接对应一个可显示的字符,它们的范围在0x00-0x20之间,再往上的0x20到0x7f通常认为是可显示的字符。共96个字符,但是汉字编码中对于这个区间的第一个和最后一个都没有使用,也就是合法区间是从0x21--0xFE,共94个字符。大家可以看到,此时的ascii编码只是用了8个字节中的7个,0x80以上的没有在ascii码中定义,此时不同的编码就会对这些内容进行解释。
和低128编码大致分区类似,此时的0x80开始到0xA0依然作为非显示的控制字符使用,剩余的96个作为显示字符。gb2312编码时就使用了这些0xA)开始的编码,只是它们是由两个连续的字节组成一个汉字。这是ascii码的编码规则,而对于汉字来说,它的划分更偏重于逻辑的划分,它只是简单的将这些汉字划分为不同的区,每个区总共94个汉字。当用内码表示一个汉字时,只需将其区位编码和区内编码各自加上0xA0即可。它的优点是可以和ascii编码完全兼容。
二、utf-8编码
unicode编码的时候和IPV4到IPV6的扩展一样,使用了足够大的空间,优点是可以表示所有的字符,但是缺点就是对于ascii码,它存在大量的0字节,这些字节无论对存储还是传输来说都是极大的浪费,所以此时有了utf-8编码,它存在的意义同样是为了兼容ascii码编码不变,从而满足大部分英语语系国家的传输。
这个编码使用的是非常简单的前缀码编码格式,它通过开始的1的个数来确定自己包含的真正有效负载数量,并且保证不同的负载可以互相区分。
wiki中对于该编码的说明

Unicode和UTF-8之间的转换关系表
UCS-4编码    UTF-8字节流
U+00000000 – U+0000007F    0xxxxxxx
U+00000080 – U+000007FF    110xxxxx 10xxxxxx
U+00000800 – U+0000FFFF    1110xxxx 10xxxxxx 10xxxxxx
U+00010000 – U+001FFFFF    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U+00200000 – U+03FFFFFF    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U+04000000 – U+7FFFFFFF    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
可以看到,它完全兼容了ascii码,所有的编码最高位都不是零,从而区分了unicode的字符和常规ascii编码。第一个字节可以确定之后字节的长度,并且和ascii码(0开始字符)、中间码(10开始字符)均没有重合。
三、不同编码之间的转换
通常的文件并不在意字符的编码,但是在显示的过程中可能需要进行特殊的转换,这些转换在linux系统中通过一组iconv函数完成,基本的接口为iconv_open、iconv和iconv_close,这的确是一个经典的三元组组合,它们和正则表达式的三个基本操作语义相同。
这组转换和内核没有关系,C库完全可以独立完成,我们通过
strace iconv --list
可以大致知道这个库文件保存在
[root@Harry thiscast]# ll /usr/lib/gconv/
total 6264
-rwxr-xr-x. 1 root root  19840 2010-10-23 02:07 ANSI_X3.110.so
-rwxr-xr-x. 1 root root  11440 2010-10-23 02:07 ARMSCII-8.so
-rwxr-xr-x. 1 root root  11488 2010-10-23 02:07 ASMO_449.so

文件夹,其中有一个不同字符集合之间转换的配置文件gconv-modules,其中定义了可以转换的文件以及大量转换的so,它们这些so中一般包含了转换的函数和转换时映射的字库数据库,上层的iconv接口会通过特定的结构找到这些so中的函数并将用户输入的编码转换为目标格式编码。
四、glibc中相关实现
glibc-2.7\iconv文件中包含了iconv函数族实现及其它功能性代码,其它数据库性质的文件则保存在glibc-2.7\iconvdata文件夹下。这个转换的过程应该是由makefile完成,但是现在没有兴趣和时间来分析它的实现。但是可以摘录一下其中的一些片段glibc-2.7\iconvdata\gb2312.c:

/* The conversion table to UCS4 has almost no holes.  It can be generated with:

   egrep '^0x' /mnt/cdrom/unix/mappings/eastasia/gb/gb2312.txt |
   perl tab.pl

   where tab.pl is:
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   $n=0;
   while (<>) {
     local($gb, $ucs4, %rest) = split;
     local($u)=hex($ucs4);
     local($g)=hex($gb);
     printf ("\n ") if ($n % 4 eq 0);
     ++$n;
     printf (" [0x%04x] = 0x%04x,",
             int(($g - 0x2121) / 256) * 94 + (($g - 0x2121) & 0xff), $u);
   }
   printf ("\n");
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
const uint16_t __gb2312_to_ucs[] =
{
  [0x0000] = 0x3000, [0x0001] = 0x3001, [0x0002] = 0x3002, [0x0003] = 0x30fb,
  [0x0004] = 0x02c9, [0x0005] = 0x02c7, [0x0006] = 0x00a8, [0x0007] = 0x3003,
  [0x0008] = 0x3005, [0x0009] = 0x2015, [0x000a] = 0xff5e, [0x000b] = 0x2016,
  [0x000c] = 0x2026, [0x000d] = 0x2018, [0x000e] = 0x2019, [0x000f] = 0x201c,
  [0x0010] = 0x201d, [0x0011] = 0x3014, [0x0012] = 0x3015, [0x0013] = 0x3008,
  [0x0014] = 0x3009, [0x0015] = 0x300a, [0x0016] = 0x300b, [0x0017] = 0x300c,
  [0x0018] = 0x300d, [0x0019] = 0x300e, [0x001a] = 0x300f, [0x001b] = 0x3016,
  [0x001c] = 0x3017, [0x001d] = 0x3010, [0x001e] = 0x3011, [0x001f] = 0x00b1,
  [0x0020] = 0x00d7, [0x0021] = 0x00f7, [0x0022] = 0x2236, [0x0023] = 0x2227,
  [0x0024] = 0x2228, [0x0025] = 0x2211, [0x0026] = 0x220f, [0x0027] = 0x222a,
  [0x0028] = 0x2229, [0x0029] = 0x2208, [0x002a] = 0x2237, [0x002b] = 0x221a,
  [0x002c] = 0x22a5, [0x002d] = 0x2225, [0x002e] = 0x2220, [0x002f] = 0x2312,
  [0x0030] = 0x2299, [0x0031] = 0x222b, [0x0032] = 0x222e, [0x0033] = 0x2261,
  [0x0034] = 0x224c, [0x0035] = 0x2248, [0x0036] = 0x223d, [0x0037] = 0x221d,
  [0x0038] = 0x2260, [0x0039] = 0x226e, [0x003a] = 0x226f, [0x003b] = 0x2264,
  [0x003c] = 0x2265, [0x003d] = 0x221e, [0x003e] = 0x2235, [0x003f] = 0x2234,
  [0x0040] = 0x2642, [0x0041] = 0x2640, [0x0042] = 0x00b0, [0x0043] = 0x2032,
  [0x0044] = 0x2033, [0x0045] = 0x2103, [0x0046] = 0xff04, [0x0047] = 0x00a4,
  [0x0048] = 0xffe0, [0x0049] = 0xffe1, [0x004a] = 0x2030, [0x004b] = 0x00a7,
  [0x004c] = 0x2116, [0x004d] = 0x2606, [0x004e] = 0x2605, [0x004f] = 0x25cb,
  [0x0050] = 0x25cf, [0x0051] = 0x25ce, [0x0052] = 0x25c7, [0x0053] = 0x25c6,
  [0x0054] = 0x25a1, [0x0055] = 0x25a0, [0x0056] = 0x25b3, [0x0057] = 0x25b2,
  [0x0058] = 0x203b, [0x0059] = 0x2192, [0x005a] = 0x2190, [0x005b] = 0x2191,
  [0x005c] = 0x2193, [0x005d] = 0x3013, [0x006e] = 0x2488, [0x006f] = 0x2489,
  [0x0070] = 0x248a, [0x0071] = 0x248b, [0x0072] = 0x248c, [0x0073] = 0x248d,
  [0x0074] = 0x248e, [0x0075] = 0x248f, [0x0076] = 0x2490, [0x0077] = 0x2491,
  [0x0078] = 0x2492, [0x0079] = 0x2493, [0x007a] = 0x2494, [0x007b] = 0x2495,
  [0x007c] = 0x2496, [0x007d] = 0x2497, [0x007e] = 0x2498, [0x007f] = 0x2499,
  [0x0080] = 0x249a, [0x0081] = 0x249b, [0x0082] = 0x2474, [0x0083] = 0x2475,

posted on 2019-03-07 09:20  tsecer  阅读(137)  评论(0编辑  收藏  举报

导航