每个程序员的都应该了解的字符编码


作者:科言君
链接:https://www.zhihu.com/question/20152853/answer/95576659
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

在开发过程中,字符编码始终是程序猿和程序媛们绕不开的一个话题。这里简要整理下有关字符编码的知识,供列位看官茶余饭后消遣:)

本回答尽量直观地介绍相关概念,不纠缠相关规定的细节,以使读者能对字符编码有着更直观的理解。当然,这样很容易挂一漏万,难免出现纰漏,也望各位批评指正。

众所周知,在计算机的世界,所有的信息都是0/1组合的二进制序列,计算机是无法直接识别和存储字符的。因此,字符必须经过编码才能被计算机处理。字符编码是计算机技术的基础,也是程序猿/媛需要的基本功之一。

在展开具体介绍之前,首先要强调一下几个概念,这对理解字符编码非常重要,也将贯穿在后文的介绍之中:

1)
理解字符集字符编码的区别

2)
“系统/终端/文件/程序”不同概念上的编码

3)
常见操作系统、文本编辑器对字符编码的处理


1 、字符集与字符编码

如前所述,字符只有按照一定规则编码,最终表示为0/1二进制序列的形式,才能被计算机处理。那么,怎么定义这种编码映射呢?其实很简单,只要大家都按照相同的规则,规定好字符与二进制序列(表现为某个数值)之间的对应关系即可。比如,我们规定英语大写字母A对应数字65,那么我们只要将65的二进制形式(01000001)保存即可。

那么,问题又来了。如果大家使用的规则不一致怎么办,那岂不全乱套了?这时候,字符集就粉墨登场了。所谓字符集,直观上讲,就是人们统计预先规定好的一系列字符与二进制序列(数字)之间的映射关系。只要大家都遵循这个规则,并且计算机也按照这种方式处理,那么这个世界不就很美好了!然而,全世界的语言实在太多了,由于历史和地域的原因,也就形成了多套应用于不同场合、语言的字符集,如ASCII、GBK、Unicode等。

需要注意的是,我们规定好了字符与数字之间的对应关系,但这并不代表计算机一定要按照字符对应的数字将数字本身直接存储!有时候,我们按照一定的规则,将字符的码元再次处理,以更加适应计算机存储、网络传输的需要。字符编码便是规定了如何编码、存储这些字符对应的二进制序列。

因此,某种意义上,可以理解为,字符集是一种协议,而字符编码是对字符集的一种实现。当然,既然称之为“实现”,也说明对同一种字符集可能有不同的编码方式。可以想到,最直接的编码方式,便是直接使用字符对应的二进制序列,这就导致了字符集和字符编码看起来像是一个东东,长期受此思维影响,可能就会对Unicode和UTF的区别有些困惑。


2 、祖先:ASCII编码

再次回顾,在计算机内部,所有的信息最终都表示为一个二进制的序列。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256(2^8)种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态可以对应一个符号,就是256个符号,从0000_0000到1111_1111。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定,这就是ASCII(American Standard Code for Information Interchange,美国信息交换标准代码),一直沿用至今。

ASCII码一共规定了128个字符的编码,包含常见的英语字符和一些控制符号。比如空格(Space)对应32(二进制0010_0000),大写字母A对应65(二进制0100_0001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0,没有使用。

需要强调的是,ASCII便是字符集与字符编码相同的情况,直接将字符对应的8位二进制数作为最终形式存储。因此,当我们提及ASCII,既表示了一种字符集,也代表了一种字符编码,即常说的“ASCII编码”。

ASCII表如下图所示。

<img src="https://pic1.zhimg.com/bd3b6c7e4f432b6dfbf5838f8e62cd14_b.png" data-rawwidth="535" data-rawheight="377" class="origin_image zh-lightbox-thumb" width="535" data-original="https://pic1.zhimg.com/bd3b6c7e4f432b6dfbf5838f8e62cd14_r.png">


1 ASCII编码表(摘自百度)


3 、扩展:扩展ASCII

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。同时,1byte中我们不是还有最高位没有使用么?这能够再编码128个符号啊!于是,一些欧洲国家就决定,利用闲置的最高位编入新的符号。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。从128到255这些字符集被称“扩展字符集”。基于此,ISO 组织在ASCII码基础上又制定了一系列标准用来扩展ASCII编码,它们是ISO-8859-1~ISO-8859-15,其中ISO-8859-1(又称Latin-1)涵盖了大多数西欧语言字符,所有应用的最广泛。ISO-8859-1仍然是单字节编码,它总共能表示256个字符。

但是,问题又来了。。。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。但是不管怎样,所有这些编码方式中,0-127表示的符号是一样的,不一样的只是多了128-255的这一段,因此它们都向下兼容ASCII编码。

同样,对于扩展ASCII,它也是既表示了字符集,也代表一种字符编码。


4 、中文:GB系列

字符型语言的字符数量较少,因此用一个byte(8bit)基本就够用了,这就难为了我们博大精深的中文汉字——中文常用字就有好几千呢!但这也难不倒我们勤劳勇敢的中国人,为此,我们设计了GB2312字符集,意气风发走进那新时代。

GB2312的思想其实很简单——既然1个byte不够用,那咱们用2个呀!正所谓,“没有1byte解决不了的问题,如果有,就2byte”。理论上,2个字节便可以表示2^16=65536的字符。不过,GB2312最初被设计时,只规定了中文常见字,很多特殊字符还没有包含。GB2312一共收录了7445个字符,包括6763个汉字和682个其它符号。除了GB2312,还有用于中文繁体的Big5。

人们逐渐发现,GB2312规定的字符太少,甚至有些国家领导人名字中的汉字都表示不出来,这还了得!于是1995年的汉字扩展规范GBK1.0(《汉字内码扩展规范》)收录了21886个符号,它分为汉字区和图形符号区。GBK编码是GB2312编码的超集,向下完全兼容GB2312,同时GBK收录了Unicode基本多文种平面中的所有CJK汉字。GBK还收录了GB2312不包含的汉字部首符号、竖排标点符号等字符。

2000年的GB18030是取代GBK1.0的正式国家标准。GB18030编码向下兼容GBK和GB2312
GB18030收录了所有Unicode3.1中的字符,包括中国少数民族字符。GB18030虽然是国家标准,但是实际应用系统中使用的并不广泛。目前使用最广的仍是GBK编码。

GBK和GB2312都是双字节等宽编码,如果算上为与ASCII兼容所支持的单字节,也可以理解为是单字节和双字节混合的变长编码。GB18030编码是变长编码,采用单字节、双字节和4字节方案,其中单字节、双字节和GBK是完全兼容的,4字节编码的码位就是收录了CJK扩展A的6582个汉字。

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理,区分中文编码的方法是高字节的最高位不为0。GB2312、GBK都属于双字节字符集 (DBCS)。

最后,不严格的说,GB系列编码也可以认为是具有字符集的意义,又有字符编码的意义。实际上,GB系列编码中有“区位码”的概念(由于采用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为“位”,所以也称为区位码),实际上, 区位码更应该认为是字符集的定义,定义了所收录的字符和字符位置,而GB2312是实际计算机环境中支持这种字符集的编码。区位码和GB2312编码的关系有点像 Unicode和UTF-8,正是最开始介绍的字符集与字符编码的区分。


5、 统一:Unicode

介绍完ASCII、Latin和GBK,想必各位会有这样的想法:为什么不规定一种字符集、编码方式,直接能够囊括全世界所有语言文字的符号呢?

由于科技发展不同步等历史原因,多种编码方式并存是不可避免的现象,但大一统的工作实际上人们也在做,这就是大名鼎鼎的Unicode。

这里面也有段有趣的历史。实际上,最早是由两个独立的组织都在设计一种通用字符集,但两家很快意识到,这个世界并不需要两套不同的通用字符集存在,否则所谓的“通用”便失去了意义。于是,后期的Unicode工作被有组织的统一了起来。

Unicode是为了整合全世界的所有语言文字而诞生的,全称是Universal Multiple-Octet Coded Character Set,它所规定的字符集也被称为Universal Character Set (UCS)。

再次提醒,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。也即,UCS规定了怎么用多个字节表示各种文字,而怎样存储、传输这些编码,则是由UTF (UCS Transformation Format)规范规定的。UTF会在后文介绍。


5.1 UCS

UCS有两种不同的规定版本:UCS-2和UCS-4。顾名思义,UCS-2就是用2个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。因此,UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。目前UCS-2已经足够用了,UCS-4估计都可以把Asgard和氪星的文字(传说都是英语?)也收录进来了……具体的符号对应表,可以查询unicode.org,或者相关的字符对应表。

UCS-4根据最高位为0的最高字节分成2^{7} =128个Group,每个Group再根据次高字节分为256个Plane,每个Plane根据第3个字节分为256行 (Rows),每行包含256个Cells。同一行的Cells只是最后一个字节不同,其余都相同。


<img src="https://pic4.zhimg.com/e372ce8d8d819bc20b72d3490e07314b_b.png" data-rawwidth="577" data-rawheight="43" class="origin_image zh-lightbox-thumb" width="577" data-original="https://pic4.zhimg.com/e372ce8d8d819bc20b72d3490e07314b_r.png">

其中,Group 0的Plane 0被称作Basic Multilingual Plane,即BMP,或者说UCS-4中,高两个字节为0的码位被称作BMP。将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。


那么,新的问题又来了:

1)
如何才能区别Unicode和ASCII?计算机怎么知道2个字节表示1个符号,而不是分别表示2个符号呢?

2)
我们已经知道,英文字母只用1个字节表示就够了(ASCII),如果Unicode统一规定,每个符号用2个或4个字节表示,那么每个英文字母前都必然有许多字节是0,这对于存储来说是极大的浪费,是无法接受的。

这些问题造成的结果是:

1)
出现了Unicode的多种存储方式,也就是说有许多种不同的格式,可以用来表示Unicode。

2)
Unicode在很长一段时间内无法推广,直到互联网(UTF-8)的出现。


5.2 UTF

UTF(Unicode/UCS Transformation Format),即Unicode字符集的编码标准,可以理解为对Unicode字符集的具体使用/实现方式,主要有UTF-16、UTF-32和UTF-8。

UTF-16

UTF-16由RFC2781协议规定,它使用2个字节来表示1个字符。不难猜到,UTF-16是完全对应于UCS-2的(实际上稍有区别),即把UCS-2规定的代码点通过Big Endian(下文介绍)或Little Endian方式直接保存下来。UTF-16包括三种:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian)。

UTF-16BE和UTF-16LE不难理解,而UTF-16就需要通过在文件开头以名为BOM(Byte Order Mark,下文介绍)的字符来表明文件是Big Endian还是Little Endian。BOM为\uFEFF这个字符。其实BOM是个小聪明的想法。由于UCS-2没有定义\uFFFE,因此只要出现 FF FE 或者 FE FF 这样的字节序列,就可以认为它是\uFEFF,并且据此判断出是Big Endian还是Little Endian。


例:“ABC”这三个字符用各种方式编码后的结果如下:


<img src="https://pic4.zhimg.com/fb3a32debb446172d99dddc0d0a5fc73_b.png" data-rawwidth="779" data-rawheight="156" class="origin_image zh-lightbox-thumb" width="779" data-original="https://pic4.zhimg.com/fb3a32debb446172d99dddc0d0a5fc73_r.png">

另外,UTF-16还能表示一部分的UCS-4字符——\u10000~\u10FFFF,表示算法就不再详细介绍了。

总结来说,UTF-16以2、4字节存储一个Unicode编码,对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为UTF-16和UCS-2基本相同(前提是明白UTF和UCS的差别)


UTF-32

UTF-32用4个字节表示字符,这样就可以完全表示UCS-4的所有字符,而无需像UTF-16那样使用复杂的算法。与UTF-16类似,UTF-32也包括UTF-32、UTF-32BE、UTF-32LE三种编码,UTF-32也同样需要BOM字符。仍以“ABC”为例:


<img src="https://pic1.zhimg.com/45a04ca95881e82755ff6adab07f3ae0_b.png" data-rawwidth="671" data-rawheight="137" class="origin_image zh-lightbox-thumb" width="671" data-original="https://pic1.zhimg.com/45a04ca95881e82755ff6adab07f3ae0_r.png">

UTF-16和UTF-32的一个缺点就是它们固定使用2个或3个字节,这样在表示纯ASCII文件时会有很多零字节,造成浪费。RFC3629定义的UTF-8则解决了这个问题,下面介绍UTF-8。


UTF-8

随着互联网的普及,强烈要求出现一种统一的编码方式,UTF-8就是在互联网上使用最广的一种Unicode的实现(传输)方式。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1-4个字节表示一个符号,根据不同的符号而变化字节长度。为什么采用边长的机制,实际上和字符出现的概率分布有关,其中蕴含着Huffman编码的思想——最常出现的字符编码尽量的短。

UTF-8的编码规则很简单,如下:

1) 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的Unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2) 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的Unicode码。

下表总结了编码规则,字母x表示可用编码的位。


<img src="https://pic4.zhimg.com/bbed856237e597044df7987bb3607d27_b.png" data-rawwidth="672" data-rawheight="163" class="origin_image zh-lightbox-thumb" width="672" data-original="https://pic4.zhimg.com/bbed856237e597044df7987bb3607d27_r.png">

可见,ASCII字符(\u0000~\u007F)部分完全使用一个字节,避免了存储空间的浪费,而且UTF-8可以不再需要BOM字节。

另外,从上表中可以看出,单字节编码的第一字节为00-7F,双字节编码的第一字节为C2-DF,三字节编码的第一字节为E0-EF,这样只要看到第一个字节的范围就可以知道编码的字节数,可以大大简化算法(感兴趣的话可以自己实现编码、解码的算法)。

例:以汉字“严”为例。

已知“严”的Unicode(UCS-2)码是\u4E25(0100_1110_0010_0101),根据上表,可以发现\u4E25处在第三行的范围内(0000 0800 ~ 0000 FFFF),因此“严”的UTF-8编码需要3个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“111001001011100010100101”,转换成十六进制就是E4 B8 A5。

可以看到“严”的Unicode码是\u4E25,而UTF-8编码是E4 B8 A5,两者是不一样的。它们之间的转换可以通过程序或一些编辑器实现。


5.3 大端、小端与字节序标记

UTF-8以单字节为编码单元,没有字节序的问题。UTF-16以2个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚编码单元的字节序。例如,当我们收到6A7C时,它到底代表\u6A7C还是\u7C6A?

仍以汉字“严”为例,Unicode(UCS-2)码是\u4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

因此,第一个字节在前,就是“大头/大端方式”(Big endian),第二个字节在前就是“小头/小端方式”(Little endian)。那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode编码规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做“零宽度非换行空格”(Zero Width No-Break Space),它的编码是FEFF。其实FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中,UCS规范建议我们在传输字节流前,先传输字符"Zero Width No-Break Space",这正好是2个字节,而且FF比FE大1。如果一个文本文件的头2个字节是FE FF,就表示该文件采用大头方式;如果头2个字节是FF FE,就表示该文件采用小头方式。字符"Zero Width No-Break Space"又被称作BOM(Byte Order Mark,字节序标记)。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"Zero Width No-Break
Space"的UTF-8编码是EF BB BF,所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。Windows就是使用BOM来标记文本文件的编码方式的,但实际上并不建议UTF-8格式的文件使用BOM。


6 、各种环境下的编码

简单介绍完字符编码相关知识后,我们需要理解不同环境下的字符编码问题,这对程序猿/媛们来说更为重要。谈及具体环境下的编码,我们实际上有以下四个层次:

1)
操作系统默认编码方式。这是操作系统的内部属性,比如大多Linux系统、Mac OS默认UTF-8编码,中文版Windows系统默认GBK编码

2)
终端编码方式。终端包括cmd、shell、terminal等,在与终端交互时,字符是要在终端显示的,这必然涉及到终端采用的编码方式,事实上有不少bug是在这个层面产生的。对于单机系统而言,终端编码与操作系统编码一般是一致的,但在远程登录时,可能会遇到一些问题。

3)
文本文件的编码方式。这是我们接触最多的概念,即一个文本文件(如源代码文件)是以什么编码格式保存的。大多数编辑器可以显示文本的编码格式,以及更改编码方式重新存储。以下图中的Notepad++编辑器为例,在格式选项卡中显示了可以进行编码转换的选项。

4)
程序中的字符、字符串变量的编码方式。这与具体的编程语言相关,涉及到程序运行时变量在内存中的状态。Python典型的encode/decode就是这个鬼。

<img src="https://pic3.zhimg.com/aa4ead31d2e48a79fdebfc3be32369ea_b.png" data-rawwidth="224" data-rawheight="221" class="content_image" width="224">


2 Notepad++中的编码选项

以Java和Python编程语言为例。

Java和Python3里,字符均采用Unicode编码(Java.lang.String 采用 UTF-16 编码方式存储所有字符),因此可以很好地支持中文。但是,Python2中Unicode不是字符默认编码格式(Python从2.2才开始支持Unicode),因此需要进行编码的转换。函数decode( char_set )可以实现其它编码到Unicode的转换,函数encode( char_set )可以实现Unicode到其它编码方式的转换,这里所讲的Unicode String是指 UCS-2或者UCS-4 编码的Code Points。

比如, ("你好").decode(
"GB2312") 将得到 u'\u4f60\u597d',即“你”和“好"的 Unicode 码分别是0x4f60 和 0x597d,再用
(u'\u4f60\u597d').encode("UTF-8") 就可以得到“你好”的UTF-8编码结果:'\xe4\xbd\xa0\xe5\xa5\xbd'。【请注意,这些运行结果跟具体的操作平台有关,读者可以思考为什么,相关解答可以参考知乎(Python2.7 中文字符编码,使用Unicode时,选择什么编码格式? - Kenneth 的回答)对此的解释,本小节也是受到该回答的启发整理而成】


<img src="https://pic4.zhimg.com/adca7b41a0e6c24897111ca9dcffb627_b.png" data-rawwidth="396" data-rawheight="206" class="content_image" width="396">

图 3 Unicode decode/encode in Python (摘自Nature Language Processing with Python, 2 edition)

实际上,Python 3和2很大区别就是Python本身改为默认用Unicode编码。字符串不再区分"abc"和u"abc",字符串"abc"默认就是Unicode,不再代表本地编码,由于有这种内部编码,与C#和Java类似,没有必要在语言环境内做类似设置编码,也因此Python 3的代码和包管理上打破了和2.x的兼容。

再次提醒:只有字符到字节或者字节到字符的转换才存在编码转码的概念


7、 编码总结

总结一下上述内容:

1、编码界最初只有ASCII码,只用了1byte中的7bit(0~127);

2、欧洲人发现128个不够了,就把1byte中没用的最高位给用上了,出现了Latin系列(ISO-8859系列)编码;

3、中国人民通过对ASCII编码进行中文扩充改造,产生了GB2312编码,可以表示6000多个常用汉字;

4、汉字实在太多了,还有繁体、各种字符呀,于是加以扩展,有了GBK;

5、GBK还不够,少数民族的字还木有呀,于是GBK又扩展为GB18030;

6、每个国家、语言都有自己的编码,彼此无法交流,迫切需要大一统局面的出现;

7、Unicode诞生,可以容纳全世界的任何文字。Unicode分为UCS-2和UCS-4,分别是2字节和4字节,实际2字节就够用了;

8、为了Unicode能实际应用(存储、传输),制定了Unicode的编码方式,即UTF,有UTF-8、UTF-16、UTF-32,其中UTF-8应用广泛;

9、UTF-16、UTF-32均是多字节传输,存在字节顺序的问题,于是有了大头还是小头的概念,为了解决这个问题,引入了BOM。UTF-8是单字节传输,不存在这个问题,也就不需要BOM,但可以有,仅用来表明编码格式;

10、要从“环境/终端/文本/程序”等不同层次去理解编码,并尝试解决遇到的问题;


8 、最后的叨叨念

各种编码方式的不一致,环境平台的不一致,会导致在编程中遇到各种头疼的bug。如果对这些相关的概念有一定的了解,至少在解决问题时会从容很多。

为了最大程度上减少可能产生的问题,可以在平时多注意一些细节,一方面方便个人开发,另一方面减少对二次开发用户的干扰。比如:

1)
可以的话,文本尽量以UTF-8(无BOM)方式存储。对于Windows用户,强烈建议弃用默认的文本编辑器,采用一款更专业的编辑器,并将默认编码格式设置为UTF8(无BOM)。

2)
跨平台开发时,如果需要在terminal输出,注意terminal的编码方式,有时采用重定向到文件会是一个更加通用的选择。

3)
对于Python用户,如果不是相关依赖项只有py2版本,强烈建议采用py3开发,会减少很多中文相关的问题。

4)
路径、文件、变量等按照规范命名。比如,听说Java支持用中文命名变量了,因此可能会出现这样的代码,String 哈哈 = "2333333"; 为了减少后续可能遇到的问题,奉劝还是不要这样,不做死就不会死。


跋 · 示儿

死去元知字符崩,但悲不见编码同。

Unicode一统日,家祭无忘告乃翁。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C、C++语言是IT行业的主流编程语言,也是很多程序员必备的软件基本功,是软件开发行业招聘考查的重点。本书以流行的面试题讲解为主要内容,介绍了C、C++语言基本概念,包括保留字、字符串、指针和引用、结构体、库函数等各个方面的基础知识,介绍了面向对象编程基本概念,包括如何实现继承、多态和封装等。还介绍了排序算法及数据结构的实现,包括链表、堆栈、队列和树。此外,本书开始用两章篇幅详细介绍了中英文面试的注意事项、常见问题及程序员的职业规划等软件工程师的常识。最后四章详细讲解了现在流行的智力测试题。 第一篇 求职 第1章 应聘求职 1.1 企业与人才 1.1.1 企业需要什么样的人才 1.1.2 如何成为企业需要的人才 1.2 做好面试的准备 1.2.1 面试衣着 1.2.2 简历 1.3 面试 1.3.1 面试注意事项 1.3.2 面试问题分析 问题一:“请自我介绍一下。” 问题二:“谈谈你的家庭情况。” 问题三:“你有什么业余爱好?” 问题四:“你最崇拜谁?” 问题五:“谈谈你的缺点。” 问题六:“谈一谈你的一次失败经历。” 问题七:“你为什么选择我们公司?” 问题八:“对这项工作,你可预见到哪些困难?” 问题九:“如果我们录用你,你将怎样开展工作?” 问题十:“与上级意见不一致,你将怎么办?” 问题十一:“我们为什么要录用你?” 问题十二:“你能为我们做什么?” 问题十三:“你是应届毕业生,缺乏经验,如何能胜任这项工作?” 问题十四:“你希望与什么样的上级共事?” 问题十五:“你在前一家公司的离职原因是什么?” 1.4 为明天做好计划 第2章 英文面试 2.1 英文电话面试 2.1.1 英文电话面试注意事项 2.1.2 英文电话面试常见   问题 问题一:When will you graduate? 问题二:How do you normally handle criticism? 问题三:Why should we hire you? 问题四:Please tell me something unreflected at your resume/about yourself/ your experience/your activities. 2.1.3 英文电话面试常用词汇 2.2 英文面试 2.2.1 英文简历 2.2.2 英文面试流程 2.2.3 英文面试注意事项 2.2.4 英文面试常见问题 问题一:What is your strongest trait? 问题二:How would your friends or colleagues describe you? 问题三:What personality traits do you admire? 问题四:What leadership qualities did you develop as an administrative personnel? 问题五:How do you normally handle criticism? 问题六:What do you find frustrating in a work situation? 问题七:How do you handle your failure? 问题八:What kinds of people do you like to work with? 2.2.5 英文面试常用词汇 2.3 计算机专业英语面试常用词汇 第二篇 C/C++面试题 第3章 C/C++程序基础 3.1 基本概念 面试题1:什么是C语言语句 面试题2:变量的声明和定义有什么区别 面试题3:下列字符中,哪些不是C语言关键字 面试题4:下列变量定义中,哪些是合法的 面试题5:如何以最简单的方式让电脑蜂鸣器发出声音 3.2 编程规范 面试题6:谈谈你对编程规范的理解或认识 面试题7:函数、变量等命名都有哪些规则 面试题8:写出bool、int、float、指针变量与“零值”比较的if语句 3.3 数据类型 面试题9:写出代码的输出结果 面试题10:C语言中不合法的整型常数 面试题11:short i = 0; i = i + 1L;这两句有错吗 面试题12:char x[] = {"abcd"}和 char y[] = {'a','b','c','d'} 有不同吗 面试题13:char型数据在内存中的存储形式 3.4 运算符 面试题14:请写出下列代码的输出内容 面试题15:运算符的优先级问题 面试题16:&&和&,||和|有什么区别 面试题17:什么是左值,什么是右值 面试题18:请写出程序的运行结果 面试题19:sizeof和strlen的区别 3.5 结构体 面试题20:结构体是什么样的数据类型 面试题21:结构体可以直接赋值吗 面试题22:组织WAV文件头,并解析WAV格式的各项信息 面试题23:计算学生不及格的人数打印他们的性别、姓名和成绩 面试题24:结构体内存对齐问题 3.6 C和C++的区别 面试题25:关键字static在C和C++中的区别 面试题26:C语言的结构体和C++的有什么区别 面试题27:C中的malloc和C++中的new有什么区别 面试题28:C++的引用和C语言的指针有什么区别 第4章 预处理、保留字 4.1 预处理 面试题1:简述#ifdef、#else、#endif和#ifndef的作用 面试题2:宏定义和函数 面试题3:用#define声明一个常数 面试题4:写一个“标准”宏MIN 面试题5:typedef和define有什么区别 面试题6:#define CHAR char*和typedef char* CHAR各有什么优劣 面试题7:谈谈你对typedef的认识 4.2 const(常量) 面试题8:关键字const是什么 面试题9:说明以下a声明的含义 面试题10:const、define定义常量的区别 4.3 static(静态)和extern 面试题11:static有什么作用 面试题12:extern有什么作用 面试题13:简述变量存储类型 4.4 volatile 面试题14:volatile有什么作用 面试题15:一个参数可以既是const又是volatile吗 面试题16:一个指针可以是volatile吗 第5章 引用和指针 5.1 引用 面试题1:什么是引用 面试题2:常引用有什么作用 面试题3:流操作符重载为什么返回引用 5.2 指针 面试题4:说明以下声明的含义 面试题5:简述指针常量与常量指针区别 面试题6:写出以下代码的输出结果 面试题7:找出代码的错误 5.3 指针和数组 面试题8:写出代码的输出结果 面试题9:请问这段程序有问题吗 面试题10:a和&a有什么区别 面试题11:请问代码有什么问题 面试题12:数组名和指针的区别 5.4 函数指针 面试题13:请解析(*(void (*)())0)()的含义 面试题14:指出程序的错误 5.5 “野指针” 面试题15:如何避免“野指针” 面试题16:程序是否正确 面试题17:指出程序的错误 5.6 动态内存 面试题18:简述C、C++程序编译的内存分配情况 面试题19:以下四段代码中哪段没有错误 第6章 字符串 6.1 数字字符串 面试题1:编码实现数字转化为字符串 面试题2:编码实现字符串转化为数字 6.2 字符串函数 面试题3:编写一个标准strcpy函数 面试题4:简述strcpy、sprintf与memcpy的区别 6.3 字符串与数组 面试题5:找出程序的错误之处 面试题6:判断程序会出现什么问题 第7章 嵌入式编程 面试题1:编码实现某一变量某位清或置 面试题2:用C编写一个死循环程序 面试题3:用变量a给出下面的定义 面试题4:设置地址为0x67a9的整型变量的值为0xaa66 面试题5:评论下面这个中断函数 面试题6:评价一个代码片段 第8章 面向对象 8.1 面向对象的基本概念 面试题1:谈谈你对面向对象的认识 面试题2:面向对象的三大特征 面试题3:面向过程和面向对象有什么区别 8.2 类的成员变量和成员函数 面试题4:简述类public、protected、private的作用 面试题5:写出代码的打印结果 面试题6:写出程序的打印结果 面试题7:C++的空类有哪些成员函数 8.3 构造函数和析构函数 面试题8:构造函数能否为虚函数 面试题9:简述子类与父类的析构、构造函数的调用顺序 面试题10:编写类String 的构造函数、析构函数和赋值函数 8.4 拷贝构造函数 面试题11:谈谈对拷贝构造函数和赋值运算符的认识 面试题12:写出当定义#define _INMAIN 0和不定义时代码打印结果 第9章 继承与多态 9.1 继承 面试题1:指出程序的错误 面试题2:用C++设计一个不能被继承的类 9.2 虚函数和纯虚函数 面试题3:下面说法中正确的是哪个 面试题4:写出程序的打印结果 面试题5:访问基类的私有虚函数 9.3 多态 面试题6:简述类成员函数的重写、重载和隐藏的区别 面试题7:简述多态实现的原理 第10章 数据结构 10.1 链表 面试题1:链表和数组有什么区别 面试题2:寻找单链表中间结点 面试题3:怎样把一个单链表反序 10.2 单循环链表 面试题4:根据需求建立一个单向循环链表 面试题5:检测一个较大的单向链表是否带环 10.3 双向链表 面试题6:按要求构造一个双向链表 面试题7:编程实现双链表插入新结点 面试题8:编程实现双链表删除指定结点 10.4 栈和队列 面试题9:简述队列和栈的异同 面试题10:建立一个链式栈 面试题11:建立一个链式队列 面试题12:能否用两个栈实现一个队列的功能 10.5 二叉树 面试题13:建立一个二叉树 面试题14:计算一棵二叉树的深度 面试题15:在二元树中找出和为某一值的所有路径 第11章 排序 11.1 插入排序 面试题1:编码实现直接插入排序 面试题2:编码实现希尔(Shell)排序 11.2 交换排序 面试题3:编码实现冒泡排序 面试题4:编码实现快速排序 11.3 选择排序 面试题5:编码实现直接选择排序 面试题6:编程实现堆排序 11.4 基数排序 面试题7:编程实现基数排序 第三篇 智力测试 第12章 基本方法 面试题1:斯密斯夫妇握手问题 面试题2:5个强盗分100颗宝石 面试题3:分牛 面试题4:谁在说谎 面试题5:是亏了还是赚了 面试题6:小虫分裂问题 面试题7:飞机绕地球环行问题 第13章 数学能力 面试题1:用一笔画出经过9个点的4条直线 面试题2:在9个点上画10条线 面试题3:100盏灯 面试题4:找出不同的球 面试题5:时针、分针和秒针重合问题 面试题6:可以喝多少瓶汽水 面试题7:怎样拿到第100号球 面试题8:烧绳计时 面试题9:分金条 面试题10:至少有多少人及格 面试题11:如何取3升水 面试题12:将16升水平均分给四个人 面试题13:如何将140克的盐分成50、90克各一份 面试题14:蜗牛几天能爬到井口 面试题15:100美元的差额到哪里去了 面试题16:点击鼠标比赛 面试题17:小猴最多能运回多少根香蕉 面试题18:算出小张买了几瓶啤酒、几瓶饮料 面试题19:牧场有多少匹马 面试题20:找出不同的苹果 面试题21:如何穿越沙漠 第14章 推理能力 面试题1:怎么少了100元 面试题2:村里有多少条病狗 面试题3:他们都在做什么 面试题4:躯体与灵魂 面试题5:小明一家能否安全过桥 面试题6:过河   问题 面试题7:这是张什么牌 面试题8:说谎岛上的两个部落 面试题9:谁是特尔斐城的预言家 面试题10:哪个政党获胜 面试题11:每个护士星期几休息 面试题12:每个人系的圆牌都是什么颜色的 面试题13:帽子问题 面试题14:谁是凶手 面试题15:他们的头发是什么颜色的 面试题16:谁是漂亮的青年 面试题17:哪个袋子里有金子 面试题18:他们星期几在说谎 面试题19:剩下的是什么牌 面试题20:老李的儿子们是做什么的 面试题21:史密斯家的门牌号 面试题22:尤克利地区的电话 面试题23:乡村庙会的15点游戏 面试题24:各家的孩子得了第几名 面试题25:经理应该带谁出差 面试题26:法官的判决 面试题27:张老师的生日是哪一天 面试题28:谁是M小姐的情人 面试题29:他们分别是哪国人 面试题30:他们分别是做什么的 面试题31:他们都会说什么语言 面试题32:怎么把马匹从甲村拉到乙村 面试题33:谁打碎了花瓶 面试题34:分机票 面试题35:石头有多重 面试题36:该释放谁 面试题37:谁打碎的玻璃 面试题38:谁是最优秀的医生 面试题39:今天星期几 面试题40:五个人进行汽车竞赛 面试题41:下一行是什么 面试题42:三筐水果各是什么 面试题43:最后剩下的是谁 第15章 反应能力 面试题1:下水道的井盖 面试题2:30秒答题 面试题3:一分钟答题 面试题4:镜子中的你 面试题5:埃及古币 面试题6:投硬币 面试题7:他在撒谎吗 面试题8:制造零件 面试题9:不喜欢正方形窗户的人 面试题10:孩子租房 面试题11:重男轻女的国度 面试题12:分遗产 面试题13:栽果树 面试题14:聪明的农民 面试题15:聪明的死刑犯 面试题16:幼儿园中奇怪的人 面试题17:奇怪的城镇 面试题18:聪明的商人 面试题19:渡船过河 面试题20:愚蠢的长工 面试题21:红球和白球 面试题22:小明坐在了哪里 面试题23:乌龟赛跑 面试题24:老师的爱恋 面试题25:爬楼梯 面试题26:马丁先生的约会 面试题27:巧入房间 面试题28:管子中的球 面试题29:女儿的错
XML越来越热,关于XML的基础教程网络上也随处可见。可是一大堆的概念和术语往往让人望而生畏,很多朋友问我:XML到底有什么用,我们是否需要学习它?我想就我个人学习过程的心得和经验,写一篇比较全面的介绍文章。首先有两点是需要肯定的:   第一:XML肯定是未来的发展趋势,不论是网页设计师还是网络程序员,都应该及时学习和了解,等待只会让你失去机会;   第二:新知识肯定会有很多新概念,尝试理解和接受,您才可能提高。不要害怕和逃避,毕竟我们还年轻。   本文共分五大部分。分别是XML快速入门,XML的概念,XML的术语,XML的实现,XML的实例分析。最后附录介绍了XML的相关资源。作者站在普通网页设计人员的角度,用平实生动的语言,向您讲述XML的方方面面,帮助你拨开XML的神秘面纱,快速步入XML的新领域。 • 第一章:XML快速入门 • 一. 什么是XML? • 二. XML是新概念吗? • 三. 使用XML有什么好处? • 四. XML很难学吗? • 五. XML和HTML的区别 • 六. XML的严格格式 • 七. 关于XML的更多 • 第二章:XML概念 • 一. 扩展性 • 二. 标识 • 三. 语言 • 四. 结构化 • 五. Meta数据 • 六. 显示 • 七. DOM • 第三章:XML的术语 • 导言 • 一.XML文档的有关术语 • 二.DTD的有关术语 • 第四章:XML的语法 • 一.XML语法规则 • 二.元素的语法 • 三.注释的语法 • 四.CDATA的语法 • 五.Namespaces的语法 • 六.entity的语法 • 七.DTD的语法 • 第五章:XML实例解释 • 一.定义新标识 • 二.建立XML文档 • 三.建立相应的HTML文件 • 第六章:XML相关资源 五. XML和HTML的区别 XML和HTML都来自于SGML,它们都含有标记,有着相似的语法,HTML和XML的最大区别在于:HTML是一个定型的标记语言,它用固有的标记来描述,显示网页内容。比如表示首行标题,有固定的尺寸。相对的,XML则没有固定的标记,XML不能描述网页具体的外观,内容,它只是描述内容的数据形式和结构。 这是一个质的区别:网页将数据和显示混在一起,而XML则将数据和显示分开来。 我们看上面的例子,在myfile.htm中,我们只关心页面的显示方式,我们可以设计不同的界面,用不同的方式来排版页面,但数据是储存在myfile.xml中,不需要任何改变。 (如果你是程序员,你会惊讶的发现,这与模块化面向对象编程的思想极其相似!其实网页何尝不是一种程序呢?) 正是这种区别使得XML在网络应用和信息共享上方便,高效,可扩展。所以我们相信,XML做为一种先进的数据处理方法,将使网络跨越到一个新的境界。 六. XML的严格格式 吸取HTML松散格式带来的经验教训,XML一开始就坚持实行"良好的格式"。 我们先看HTML的一些语句,这些语句在HTML中随处可见: 1. sample 2.sample 3.sample 4.samplar 在XML文档中,上述几种语句的语法都是错误的。因为: 1.所有的标记都必须要有一个相应的结束标记; 2.所有的XML标记都必须合理嵌套; 3.所有XML标记都区分大小写; 4.所有标记的属性必须用""括起来; 所以上列语句在XML中正确的写法是 1. sample 2.sample 3.sample 4.samplar   另外,XML标记必须遵循下面的命名规则: 1.名字中可以包含字母、数字以及其它字母; 2.名字不能以数字或"_" (下划线) 开头; 3.名字不能以字母 xml (或 XML 或 Xml ..) 开头; 4.名字中不能包含空格。 在XML文档中任何的差错,都会得到同一个结果:网页不能被显示。各浏览器开发商已经达成协议,对XML实行严格而挑剔的解析,任何细小的错误都会被报告。你可以将上面的myfile.xml修改一下,比如将改为,然后用IE5直接打开myfile.xml,会得到一个出错信息页面: XML轻松学习手册 ajie <E
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值