日志分类:计算机科学与编程

一道 C 语言指针访存题目的引申

2009/11/08 | 13:41 | 分类:计算机科学与编程 | 标签: | 4,618次阅读

  毕业生求职的时节,非毕业生接触到各种面试、笔试题目的几率也会相应地增加。下面请看一道经典的 C 语言指针访存题目,稍有些经验的朋友应该很快可以看出这个题目考查的是字节序、内存布局等知识点。然后在大脑中略排列一下,就能够给出答案(2000000)。

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.     int a[5] = {1, 2, 3, 4, 5};
  6.     int *pa = (int)(&a) + 1;
  7.     printf("%x\n", *pa);
  8.     return 0;
  9. }

  不过,这个答案是否绝对正确,还要看题目所处的上下文了。如果题目明确说是在常见的 32 位 x86 平台上运行,那就无可厚非;但如果没有指明机器架构,那就要小心一点了,也许命题者真想考查一下求职者对非 x86 平台的了解程度呢。如果考虑机器架构,这个题目应当如何作答呢?粗想一下,我们需要考虑的是字长、字节序和对齐(alignment)访问规则。不过真要做实验看看,会发现这里面还是有一些花样的。如果没有实际经验,只凭教条加推测,很可能想不到其它平台上的一些细节之处。
  我们换用一段信息量更丰富的程序来进行后续的实验。在不同的平台上,均使用未加特殊参数的 gcc 来编译这段程序——

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.     int x;
  6.     int a[5] = {0x11121314, 0x21222324, 0x31323334, 0x41424344, 0x51525354};
  7.     for (x = 0; x < 20; x++) {
  8.         printf("%02x ", *(char *)((int)(&a) + x));
  9.     }
  10.     printf("\n");
  11.     for (x = 0; x < 8; x++) {
  12.         printf("%08x ", *(int *)((int)(&a) + x));
  13.     }
  14.     printf("\n");
  15.     return 0;
  16. }

  在 32 位 x86 下的结果不需要多解释。

  1. uname -a
  2. Linux ubuntu 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009 i686 GNU/Linux
  3. ./a.out
  4. 14 13 12 11 24 23 22 21 34 33 32 31 44 43 42 41 54 53 52 51
  5. 11121314 24111213 23241112 22232411 21222324 34212223 33342122 32333421

  而在 64 位的 x86_64 下,由于 8 字节的指针被截断到了 4 字节的整型长度,故会引发段错误。同样的情况出现在 64 位的 Alpha 机器下。解决办法自然是把运算地址时的 int 修改成 long 或某种显式的 64 位类型。修改后的结果应该与 32 位 x86 一致。

  1. uname -a
  2. Linux ubuntu 2.6.24-22-generic #1 SMP Mon Nov 24 19:35:06 UTC 2008 x86_64 GNU/Linux
  3. ./a.out
  4. Segmentation fault
  1. uname -a
  2. NetBSD sdf 2.1.0_STABLE NetBSD 2.1.0_STABLE (sdf) #0: Fri Mar 30 02:24:32 UTC 2007  root@ol:/var/sys/arch/alpha/compile/sdf alpha
  3. ./a.out
  4. Memory fault (core dumped)

  有趣的是在 XScale(Intel 实现的 ARMv5)下,虽然同属 little-endian,但非对齐取数时出现了在字内按字节循环的移位的结果。查查 ARM 的官方文档,这确实是 ARMv5 的特性;而在 ARMv6 以后,非对齐访问则是完全支持的。

  1. uname -a
  2. Linux zaurus 2.4.18-rmk7-pxa3-embedix #1 Sat, 06 Aug 2005 12:22:55 +0000 armv5tel unknown
  3. ./a.out
  4. 14 13 12 11 24 23 22 21 34 33 32 31 44 43 42 41 54 53 52 51
  5. 11121314 14111213 13141112 12131411 21222324 24212223 23242122 22232421

  接下来看看 PowerPC,它是 big-endian 的代表,允许 32 位以内的非对齐访问,结果是容易理解的。有关 PowerPC 非对齐访问的一些细节可以参考这篇文章

  1. uname -a
  2. AIX aix 3 5 00C97AC04C00 powerpc unknown AIX
  3. ./a.out
  4. 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 51 52 53 54
  5. 11121314 12131421 13142122 14212223 21222324 22232431 23243132 24313233

  同样是 big-endium 的 SPARC 则不允许非对齐访问。它会对非对齐访问抛出 SIGBUS。

  1. uname -a
  2. SunOS t1000 5.10 Generic_118833-33 sun4v sparc SUNW,Sun-Fire-T1000 Solaris
  3. ./a.out
  4. 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 51 52 53 54
  5. Bus Error (core dumped)

  最后看看我们中科院计算所的龙芯(Loongson)2E,它是兼容 MIPS 架构的处理器。很多教科书告诉我们说通常的 MIPS 是不允许非对齐访问的(部分 MIPS 实现提供了非对齐访问指令,并申请了专利),但我们在龙芯下却得到了和 x86 相同的、允许非对齐访问的结果,这又是为什么呢?初步查到的原因是“(针对龙芯修改过的 Linux)内核里确实有一个异常处理函数负责处理 lw 访问非对齐地址引起的异常”。这也许是龙芯绕开 MIPS 专利的一种办法?我会向龙芯团队的同学求证一下,也希望熟悉 MIPS 或龙芯的朋友给我一个确切的答案。

  1. uname -a
  2. Linux Loongson-1 2.6.18.1lemote #1 Sat Jan 13 16:02:26 CST 2007 mips GNU/Linux
  3. ./a.out
  4. 14 13 12 11 24 23 22 21 34 33 32 31 44 43 42 41 54 53 52 51
  5. 11121314 24111213 23241112 22232411 21222324 34212223 33342122 32333421

  不过用心思考的朋友也许会发现上面一系列实验存在的一个疏漏:没有考虑编译器的影响。一方面,编译器可能对整型的字长有不同的规定(例如 Windows 下的某些编译器即使在 32 位 x86 上也会把 int 定义为 16 位);另一方面,编译器可以对不支持非对齐访问的处理器生成一定的指令序列、通过多次访存来模拟非对齐访问。我们看下面的例子:还是在 SPARC 平台上,改用 Solaris 自带的 Sun CC 来编译实验程序,这时就不会出现“Bus Error”,而会输出和 PowerPC 一样的结果。因为 SunCC 默认会使用“-xmemalign”参数来生成适当的访存指令序列。

  1. uname -a
  2. SunOS t1000 5.10 Generic_118833-33 sun4v sparc SUNW,Sun-Fire-T1000 Solaris
  3. cc data.c
  4. ./a.out
  5. 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 51 52 53 54
  6. 11121314 12131421 13142122 14212223 21222324 22232431 23243132 24313233

  这样看来,在不指定机器架构和编译器等上下文的情况下,要正确且完美地回答一开始的那道题目还是需要一定知识积累的。答案省略,留给大家自己求解。在面试、笔试诸如 Sun SPARC、IBM PowerPC、中科院计算所微处理器中心等部门或者做 ARM 等嵌入式开发的公司时,最好先了解清楚它们的产品常识。
  (部分实验环境来源于 Unix-Center.Net,在此致谢)

对“为人民计算”的几点思考

2009/06/30 | 23:30 | 分类:计算机科学与编程 | 标签: | 2,652次阅读

对“为人民计算”的几点思考

(本文为本人“先进计算机和软件技术系列讲座”课程作业)

 
  “为人民计算”(Computing for the Masses)是近年来计算机科学技术和产业发展的目标之一。而究竟什么是“为人民计算”,出于国情、技术水平和个人认识的差异,不少学者提出过不同的理解。我国人口众多,农村人口占56%(国家统计局2007年10月数据),城乡经济和区域发展尚不协调,正处于信息化带动工业化的发展时期。在这种历史条件下,如何使得信息化的成果真正惠及人民,实现计算机行业所谓“普惠计算”的目标,是业界出于其社会责任感有必要思考的一个问题。针对我的导师徐志伟研究员在“为人民计算”方面的提出的一些观点,我浅谈一下我对几个相关问题的思考。
对“为人民计算”的几点思考
 
  消费动机不在信息化本身
  在受益于信息化且面向大众服务的行业当中,近几年来增长较为显著的是移动通信产业。中国的移动电话用户数量由1999年底的4330万户发展到2009年中期的6.87亿户。城市手机用户已经趋于饱和,但运营商对农村移动通信市场仍有信心。移动通信之所以得到了市场的认可,与其明确的消费目的息息相关。绝大多数消费者购买手机,其基本动机就是为了享受通信的便利;对于相当一些职业的人士,实时的通信可能已经不是“方便”而是“必须”。对于农村新市场的开拓,其难点可能在经济方面,而不在于人民对手机的基本功能和作用的认知。类似的案例还有银行卡。截至2009年6月,全国累计发行银行卡18.88亿张,银行卡的主要用户也分布在城市,农村和欠发达地区受制于经济条件和消费意识,对银行卡产品也许有所误解,但这不能说明银行卡本身的定位有问题,至少它们的功能是相对单一和明确的,满足了人民群众的特定需求。
  然而,计算机与网络技术对人民大众来说,其直接的消费目的性并不如移动通信、银行卡那样显而易见。在目前阶段,计算机与网络更多地扮演着工具和桥梁的角色。购买计算机、接入互联网,并不能直接解决什么具体问题,计算机和网络解决的问题是通过运行在其上的应用体现出来的。“上网”、“获得信息”、“学习”都是一些相对抽象的动机,不能直接满足低端用户具体一项生活需求。因此在商业化推广中,这些空虚的目标可能不会对低端消费者产生太大的吸引力。即便通过财政支持来发展信息化,这些成果也很可能沦落为地方政绩的象征或闲人娱乐的工具,对生产生活不会有实质的影响。要在2040年建成惠及至少12亿人的信息化社会,我认为不能把民用计算机、网络定位为移动通信那种具有明显消费目的性的产品,而必须改变现有中低端计算机和网络相关产品或服务的社会定位,在应用层面寻找“为人民计算”的突破口。
  信息化被作为工具的现状令很多从业者,特别是计算机科学研究人员不满:业界不愿意让信息技术变成像楼宇保洁一样必不可少但几乎不能创造价值的服务业,学界不也甘心计算机科学停滞不前,最终被其它学科以工具和技术的名义吞并。上世纪末本世纪初,网格计算的理念曾十分风行,研究人员力图建立一种像电网一样即插即得的信息基础设施,但至今网格技术只在部分专业研究领域发挥了功效,而那种惠及全民的“Great Glocal Grid”还未见雏形。其中主要的原因,我认为是信息资源缺乏像电力资源那样的同质性,抛开技术层面的因素,难以同质化的信息本身就使得潜在的用户无法建立明确的消费动机。但信息的同质化正是一个值得研究的科学问题,这个问题的解决,将使得计算机、网络由独立的工具进化为信息基础设施的地位。我们需要这样的基础设施在社会的后台像电网一样默默无闻地“为人民计算”,而用来明确消费动机、创造商业价值、进而构建信息社会的,不是计算机和网络的实体,而是这一基础设施之上的、像家用电器一样的、但目前尚未被发明的具体应用。
 
  比“脱贫”更难的是“第二跳”
  目前我国大多数人口仍处于“信息贫困线”以下,“脱贫”是产业界、学术界和决策层正在着力解决的问题。“脱贫”的方向相对明确。对于产业界,主要需要考虑机器生产和网络运营的成本,让计算机和网络对所有人来说由奢侈品变成日用品;对于学术界,需要摒弃一味追求性能的老路,从功耗、易用性等贴近用户的角度考虑体系结构的设计;决策层则需要提供政策扶持,对相关产业采取优惠措施,对人民群众加以合理引导。但我认为有可能出现困难的,并不在于“脱贫”的“第一跳”,而在于由基本价值向商品价值提升的“第二跳”。
  还是以银行卡为例,我国银行卡发行数量虽然已经超过人口总量,但真正用卡的人群并不大,相当一部分银行卡是通过任务摊派的方式进入低端市场的,这些卡大都成了没有任何交易记录的“死卡”。即使是使用银行卡的人,他们中的多数也只享受了其商品价值,把它当作一张可以自助取款的存折,从未使用甚至从未听说过银行卡所关联的高级金融服务。
  纵观我国计算机网络用户,其层次分化较为明显。IT界的精英人士、具有探索精神的专业人士早已享受到了信息产业的泛在价值、专业价值乃至个性价值,他们甚至可以在软件开发商与网络运营商尚未提供相关服务的情况下发扬自主创新的DIY精神,主动地让信息化为自己创造价值。而目前数目最庞大的用户群是将计算机、网络作为工具的人群,他们虽然享受了信息化带来的基本价值和商品价值,但只是在工作和生活中为了特定的目的有意去使用计算机和网络,计算机和网络更多地作为间接、高效实现传统生产模式价值的途径,而不是直接为这些用户提供新的价值。在农村和欠发达地区也有一定数量的计算机、网络用户,网吧是他们接触信息化成果的主要场所。这些用户缺乏自主探索的意识,他们通常使用仅仅使用网吧预置的网站、软件与游戏。即使是这些地区的一些官员,对信息产业的理解也有可能过于狭隘,甚至可能因为未成年人沉迷网游等问题对计算机、网络建立负面的印象,进而抵制信息化进程。然而要达到“普惠计算”的目标,必须把这类人群作为未来市场的潜在用户。目前我国的信息化还没有像工业化那样彻底地改变大多数人的生活方式;在相当一部分地区,工业化的成果甚至还没有全面应用到生产中,在这些地区谈信息化的价值,确实不容易为当地政府和人民大众所接受。单纯的基础设施建设所带来的基本价值就像提供给毫无养殖经验的农户的良种牲畜,他们只能一吃了之,不懂得通过繁殖子代、获取副产品来增值。既然信息化带动工业化已经是中国特色的跨越式发展模式,我们就应该在“脱贫”的同时完成“第二跳”的工作,提供一系列能够直接服务于生产、生活的应用。只有完成“第二跳”,信息化才不再是软硬件堆叠的花架子,其价值才能使个人用户受益。如何让人民群众真正从“为人民计算”中得到实惠,让计算机科学的成果成为人民群众喜闻乐见的事物,而不是像银行卡市场那样徒有虚名,这才是比信息“脱贫”更重要的任务。
 
  对“计算透镜”半保守半超前的认识
  Richard M. Karp提出的“计算透镜”(Computational Lens)理念被认为是未来二十年计算机科学可能的发展方向之一。其核心理念是将计算作为一种通用的思维方式,通过这种广义的计算(涉及信息、执行算法、关注复杂度)来描述各类自然过程和社会过程,从而解决各个学科的问题。Karp给出了计算透镜理论在生物科学中的成功应用。这一理论试图将计算机科学由最初的数值计算工具、仿真与可视化技术以及后来基于网络、面向多学科的e-Science平台,变成普遍适用于自然和社会领域的通用思维模式。从这一点上看,计算透镜的思路也似乎是要将计算机从传统的“为军事计算”、“为科学计算”、“为商业计算”过渡到“为人民计算”、“为人类计算”,只是这一思维工具并不一定直接为人民所使用,而是要借助学界和业界之手将计算透镜带来的好处通过生产力的发展来施惠与人。
  世界真的可以用计算过程来表达吗?在初次接触到计算透镜的概念时,我首先想到的是近代机械唯物主义的自然观,试图用力学和机械的观点来解释并分析自然与社会现象。进而联想到了人工智能发展史上的符号主义、连接主义和行为主义等学派的基本观点,它们都力图用一种简单的形式化模型来解释智慧和思维。计算透镜是不是在走这些老路呢?我个人感觉,在图灵机模型和现行的可计算性理论本身是否符合自然规律尚未被证实的前提下,不要指望计算透镜能在短期内给一般大众的工作和生活带来什么影响。但对计算透镜的研究是有意义的,其意义可能不在于用计算改造自然,而在于更好地认识自然,从而改造现有的计算模型,使之能够像一些自然过程一样高效。也许到那个时候,人、机、物界限因为思维方式的统一而变得模糊,“为人民计算”的理念演化为对人类思维能力的直接扩展,届时作为中介的信息化工具、应用可能反而变得不重要了。
  回到现实,这方面已经存在的一些问题需要引起我们的关注。计算透镜理论中包含“社会计算”。尽管社会计算的概念目前还没有精确的定义,无论是用计算机的方法研究社会还是用社会学的方法研究计算机,统统被一些机构打上了“社会计算”的标签。从“社会”二字可以看出,这一计算的执行也并非人民的个体可以完成的,要做到社会计算,仍需要掌握着社会数据和社会决策权的机构来完成。但在法治完善程度赶不上技术发展速度的情况下,如何保证社会计算的成果真正服务于民,成为“为人民计算”的理念与实践需要面对的一个重要的非技术问题。例如当前舆情计算技术的发展确实为政府机关提供了迅速准确的决策支持,但一些社会团体对舆情计算中的个人隐私保护问题仍存在争议,认为这对网民存在侵权。舆情计算技术还被某些搜索引擎公司或网络公关公司所利用,通过推送正面信息、屏蔽负面评价的方式从不法商家手中谋利,直接侵害了消费者的知情权,损害了市场的公平竞争。从这一点可以看出,“为人民计算”不是一两个新理论、新技术就可以实现的,它需要完善的法治框架、良好的业界环境,以及官、产、学、研各方对人民利益高度负责的态度。
 
  总之,我心中的“为人民计算”应该是由有价值的应用所导向的、带来明确消费动机的、架构在信息基础设施之上的信息化发展模式。它应该像电网和电器一样易用,让人民受益的同时却感觉不到信息基础设施的存在;它应该突破城乡与区域差异,惠及全民,为信息化带动工业化带来历史契机;它应该兼顾可用性、保密性与可控性,在具有社会负责感的机构的运营下真正代表人民群众的利益。
 
参考文献
[1] 徐志伟.为人民计算的三个问题.中国计算机学会通讯,2008(10).
[2] 江泽民.新时期我国信息技术产业的发展.上海交通大学学报,2008(10).
[3] 李国杰.创新求索录.电子工业出版社,2008.
[4] Richard M. Karp. Computer Science as a Lens on the Sciences. ICDCS 2008.

《程序员的自我修养》是有学习价值的

2009/05/23 | 14:20 | 分类:计算机科学与编程 | 标签: | 4,429次阅读

  不久前收到了博文视点寄来的新书——《程序员的自我修养——链接、装载与库》。比较巧的是,我这段时间正在从事一个涉及多语言互操作的项目,那些天还在看一些有关C++语言设计和实现原理的文献,这本《程序员的自我修养》和我最近的工作还是多多少少有点联系的。
  有的人可能认为读博士的人不应该再去关注这些面向程序员、纠结于技术细节的书了,而要专心于自己的研究领域,做偏科学、偏理论的事。这是有道理的,博士教育和硕士教育的差异即在此,漂泊在茫无涯际的技术海洋很可能让本应该专注于一个方向的人不知所向。但是我们也要反思,自己的基础是否足够扎实?对计算机原理的理解是否超越了那些具体技术的层面?自己是否真的具备了从事科研的素质?我的导师在他的科普作品《电脑启示录》(中篇 硅谷的秘密)中曾提到作为计算机科研人员应该具备的基本素质,并例举了几个用来考察这些素质的问题,诸如:从计算机开机到操作系统等待用户输入,经历的一系列流程是什么?在浏览器里敲入一个网址到网页呈现给用户,期间又有哪些工作细节?这些过程看似稀疏平常,其中的大道理在本科计算机课程中也都或多或少地介绍过,然而要精确地表达每个步骤,更重要地是说明每个步骤为什么要这样设计、为什么会这样实现、其中的科学依据是什么,往往不是每个计算机专业毕业生都能说清楚的。这类问题常常能从侧面反映一个从业人员的理论功底及实践经验。《程序员的自我修养》所阐述的也正是同一类的问题:一个程序由硬盘上目标文件、可执行文件变成内存中的进程体、CPU中的指令流,整个过程的来龙去脉是什么,有什么原理、诀窍、讲究和因果联系。
  在计算机领域从事不同具体工作的科研、技术人员,静下心来分析一下这些平时被各种层面的接口掩盖了的机制是有好处的。初用VC++编程的时候,也许你会奇怪,监视窗口为什么要输出一串“烫”字;干Linux工程时,仅仅链接了几个标准库文件就把程序搞崩溃了,你会认为这是链接器或标准库的bug,还是自己没有弄明白它们的机理?如果你在计算机学科的其它方面有过一些细致的了解,你又会发现,像自举引导、延迟绑定等共性的方法,时间与空间转换、策略与机制分离等共性的原则在编译、链接、装载过程中也都有生动的体现。而即使你是做研究的,方向与程序原理相隔甚远,看看这些计算机领域内实现相对成熟、应用相对普遍的、原理相对通用的问题,对自己的工作也很有启发意义。
  尽管这本书有待市场的考验,但它研究的问题确属计算机学科中的经典。把理解链接、装载与库作为程序员的自我修养是否合适?我想,它算不上充分条件,不过确实是一个必要条件。不仅对程序员来说必要,对任何一个从事计算机研究与开发的人来说都是有价值的。

C和C++处理register关键字的一处差异

2009/04/19 | 23:08 | 分类:计算机科学与编程 | 标签: | 10,430次阅读

  C++并不是完全兼容C语言的,上次提到的sizeof('a')等于几的问题就是一例。今天我在编码时又无意中发现了一处不同:
  用register关键字修饰的变量,在C语言中是不可以用&操作符取地址的,这是我已有的经验。因为编译器如果接受了程序员的建议把变量存入寄存器,它是不存在虚拟地址的。但在C++中,用register修饰的变量可以用&操作符取地址,这是我在一段代码中发现的。如果程序中显式取了register变量的地址,编译器一定会将这个变量定义在内存中,而不会定义为寄存器变量。
  我在C99(ISO/IEC 9899:1999)和ISO C++(ISO/IEC 14882:2003)标准中得到了确认,C和C++标准对register遇到&的处理确实有不同的明确定义。但为什么要这样定义?我只能从标准的字里行间猜测。K&R C1中如何描述register我尚未查证,K&R C2(ANSI C)中说明了“register variables are to be placed in machine registers ... but compilers are free to ignore the advice ”。但在C99和ISO C++中,措辞分别变成:“suggests that access to the object be as fast as possible”、“a hint to the implementation that the object so declared will be heavily used”,不再特别提及“machine registers”。可见历史上register关键字在强调尽可能地把变量保存到寄存器,而现在的register关键字不再强调具体手段,只是建议编译器通过各种可行的方式优化该变量的访问(不过很多编译器会忽略这一关键字,而采用自身的优化策略)。C99可能是为了保持对K&R C的兼容而不允许取地址操作;而C++也许是因为没有历史包袱才放宽了这个限制吧。猜测而已,希望知道内幕的朋友告诉我更精确的答案。

有关计算机汉字编码的一些国家标准

2009/04/05 | 21:00 | 分类:计算机科学与编程 | 标签: | 4,543次阅读

  有关计算机汉字编码方案,Unicode 系列的资料相对清晰一些,UnicodeUCSUTF 这些概念,看看 Wikipedia 是容易弄明白的。当然,其中也有复杂的版本演进问题以及 Unicode 与 ISO 10646 标准的微妙差异。而我国的 GB 系列汉字编码标准,网上的资料相对零散,故我通过 Wikipedia 的相关页面收集了一些信息,加以整理和注释,希望对大家有所帮助。如有差错敬请指出。

  更新于 2009-05-26。


一、现行计算机系统中使用的 GB 字符集与编码

  现行计算机系统中使用的 GB 编码是指 GB 2312-80 —— GBK —— GB 18030-2000/2005 这一系列。标准文件中定义了编码(区位)的方案,并且有计算机中实现的规范(内码,EUC-CN)。

● GB 2312-80 信息交换用汉字编码字符集·基本集(又称 GB0)

  包含常用的一级汉字、二级汉字、符号等。每个汉字以双字节表示,高位字节使用0xA1-0xF7(0xA1-0xA9是符号,0xAA-0xAF保留,0xB0-0xF7是汉字),低位字节使用0xA1-0xFE。

● GBK 汉字扩展内码规范

  在 GB 2312-80 基础上增加了来自 GB 13000.1-93 等标准中的一些罕用字与繁体字。为容纳新字,扩大了编码范围,高位字节使用0x81-0xFE,低位字节使用了0x40-0x7E及0x80-0xFE,新字填补在与 GB 2312-80 汉字无冲突的空位。
  注意,GBK 并非国家标准。它最初是微软对 GB 2312-80 做的扩展。鉴于其使用的普遍性,国家技术监督局标准化司、电子工业部科技与质量监督司于1995年12月将其作为技术规范指导性文件发布。

● GB 18030-2000 信息交换用汉字编码字符集·基本集的扩充

  向下基本兼容 GBK,补全了 ISO 10646.1:2000 中的 CJK 统一汉字(Main、Extension A)。为容纳新字,在保留原有双字节编码的同时引入了四字节编码,第一字节使用0x81-0xFE,第二字节使用0x30-0x39,第三字节使用0x81-0xFE,第四字节使用0x30-0x39。

● GB 18030-2005 中文编码字符集

  在 GB 18030-2000 的基础上,补全了 ISO 10646.1:2003 中的 CJK 统一汉字(Extension B)。编码空间同上。其中双字节编码部分是现行的强制性国家标准。

二、现行计算机系统中未作为汉字编码的字符集

● GB/T 12345-90 信息交换用汉字编码字符集·第一辅助集(又称 GB1)

  GB 2312-80 的繁体版,区位安排与 GB 2312-80 一致,但替换为繁体字。同时增加了一些竖排标点符号。

● GB/T 7589-87 信息交换用汉字编码字符集·第二辅助集(又称 GB2)

  对 GB 2312-80 的增补,增加一些简体罕用字。每个汉字以双字节表示,高位字节使用0xA1-0xFE(0xA1-0xAF保留,0xB0-0xFE是汉字),低位字节使用0x21-0x7E。

● GB 13131-91 信息交换用汉字编码字符集·第三辅助集(又称 GB3)

  GB/T 7589-87 的繁体版。

● GB/T 7590-87 信息交换用汉字编码字符集·第四辅助集(又称 GB4)

  对 GB 2312-80 的增补,增加一些简体罕用字。每个汉字以双字节表示,高位字节使用0x21-0x7E(0x21-0x2F保留,0x30-0x7E是汉字),低位字节使用0xA1-0xFE。

● GB 13132-91 信息交换用汉字编码字符集·第五辅助集(又称 GB5)

  GB/T 7590-87 的繁体版。

● GB/T 16500-1998 信息交换用汉字编码字符集·第七辅助集(又称 GE)

  信息交换用汉字编码字符集基本集及其第一至第五辅助集中没有收录的,但在 GB 13000.1-93(ISO 10646-1:1993)中通过其它途径收录的汉字。

  以上标准文件定义了一系列罕用字的编码和区位,但在主流计算机系统中没有实现(GB2、GB4 标准文件中使用的都是手写字体)。这些字最终被 ISO 10646-1:1993 和 GB 13000.1-93 标准化之后,由 GBK 重新引入,做了与 GB 2312-80 兼容的内码实现。其中 GB1、GB3、GB5 连同 GB0 作为提交给 ISO 制定 ISO 10646-1:1993 的依据的一部分;GB2、GB4 中不少是“类推简化汉字”,实用性不高,故没有被 ISO 采纳;第七辅助集是在 GB 13000.1-93(ISO 10646-1:1993) 制定之后,对“信息交换用汉字编码字符集”系列国标的完整性的补充。它之所以不简称为 GB7,是因为此前中国向 ISO 提交制定 ISO 10646-1:1993 的依据时,将1988年出版的《现代汉语通用字表》简称为 GB7 了。在 ISO 10646 后期修订时,GE 又被反向引用为标准依据之一。之所以不存在“第六辅助集”,我个人猜测的原因是:第六辅助集留作第七辅助集的“类推简化汉字”版本,没有实用意义。

  备注:GBK 之前的这些标准中,{高[0xA1-0xFE]-低[0xA1-0xFE]}、{高[0xA1-0xFE]-低[0x21-0x7E]}、{高[0x21-0x7E]-低[0xA1-0xFE]}都安排了汉字,那么{高[0x21-0x7E]-低[0x21-0x7E]}是用来做什么的?参考 GB 12052-89《信息交换用朝鲜文字编码字符集》以及 GB 13134-91《信息交换用彝文编码字符集》等,它们用来安置一些少数民族文字(重叠,互不兼容)。GB 2311-90《七位和八位编码字符集代码扩充技术》规定了一系列方案使得它们不会和 7 位 ASCII 冲突。这些少数民族文字编码标准最终也没有被大规模采用,取而代之的也是 ISO 10646 以及等价的一些中文版标准(如 GB 16959-1997《信息交换用藏文编码字符集基本集》)。

三、ISO 10646 / Unicode 的中文等价标准

● GB 13000.1-93 通用多八位编码字符集(UCS) 第一部分:体系结构与基本多文种平面

  相当于 ISO 10646-1:1993 中文版,基本等价于 Unicode 1.1。编码方式(Unicode / UCS)与内码实现方式(UTF)分离。目前这一标准并没有随 ISO 10646 或 Unicode 的更新而更新。

四、其它汉字编码标准

● GB 8565.2-88 信息处理文本通讯用编码字符集 第二部分(又称 GB8)

  主要用于电讯,没有作为计算机汉字内码实现。它是提交给 ISO 制定 ISO 10646-1:1993 的依据的一部分。


  最后说一点个人理解:GB 18030-2005 是目前阶段兼容遗留系统(更主要的是遗留文档)的权宜之计。尽管从技术角度说,它也是一种 UTF(基于码表映射而非简单的公式组合),但它毕竟在国际化环境中不能与其它语言编码共存,编码转换的空间开销大,有其局限性。ISO 10646 / Unicode 应该是国际化的大方向,我国相关技术人员也在也积极参与 ISO 10646 / Unicode 的修订,未来版本的 GB 13000 应该会向这个方向努力。

页面: 上页(较新) 1 2 3 下页(较旧)