<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>windam.log</title>
	
	<link>http://www.windameister.org/blog</link>
	<description>learn, think, share, communication</description>
	<lastBuildDate>Fri, 04 May 2012 03:46:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/windamlog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="windamlog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>[译]每个软件开发者必须绝对至少需要了解的Unicode和Character Sets的知识（没有借口！）</title>
		<link>http://www.windameister.org/blog/2012/05/03/translated-things-on-unicode-and-charset-each-developer-should-know-at-least/</link>
		<comments>http://www.windameister.org/blog/2012/05/03/translated-things-on-unicode-and-charset-each-developer-should-know-at-least/#comments</comments>
		<pubDate>Thu, 03 May 2012 15:48:45 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[字符集]]></category>
		<category><![CDATA[编码]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/?p=336</guid>
		<description><![CDATA[每个软件开发者必须绝对至少需要了解的Unicode和Character Sets的知识（没有借口！）   原文：http://www.joelonsoftware.com/articles/Unicode.html   by Joel Spolsky 译windam   2003.10.8 星期三 你是否曾经对那个神秘的Content-Type标记感到不解？ 译注：每个HTML页面的head块中都可能包含一个Content-Type标记，例如： &#60;meta http-equiv=&#8221;Content-Type&#8221; content=&#8221;text/html; charset=UTF-8&#8243; /&#62; 你知道这东西应该被放到HTML里，但是你从来都没有确切得弄清楚它到底应该是什么？   你是否曾经收到过你朋友从Bulgaria发来的Email，它的主题行是&#8220;???? ?????? ??? ????&#8221;？   当我发现还有那么多的软件开发者并没有真正领会关于字符集(Character sets)，编码(encoding)，Unicode以及相关知识的时候，我非常失望。几年前，FogBUGZ的一个beta测试者对于它是否能处理收到的日语邮件感到疑惑。日语？他们有日文的Email？我不知道。但当我仔细研究我们用来解析MIME email的商业ActiveX控件时，我们发现它恰恰正好对字符集做了完全错误的处理，于是，为了撤销控件中所做的错误转换，并正确的重新处理，我们不得不编写修正它的补救代码。而当我研究另一个商业库的时候，发现它有一样的完全错误的字符代码实现。我和那个代码库的开发者通信，发现他的想法是，他们“不能（对字符集）做任何事（正确的处理）”。就像很多程序员一样，他只是祈祷着，这一切麻烦事都可以被吹走。   但事实上不会！当我发现流行的web开发语言PHP几乎完全的忽略了字符编码的问题，没心没肺的用了8bit字符，这种傻逼的行为让开发好的国际化web应用变得几乎不可能的时候，我想，我受够了。   我在此声明：如果你是一个工作在2003年或之后的程序员（此文写于2003年10月），并且你还没有对字符，字符集，编码和Unicode有所了解，而且你被我我抓住了，我会罚你在潜艇里剥6个月的洋葱皮！我发誓我会这样做的！   此外还有一事：   这真的没那么难   在本文中，我将会告诉你每个在工作中的程序员所应知道的。所有关于&#8220;plain text = ascii = character就是8bit&#8221;的知识不仅仅是错误的，而且是错得令人绝望。如果你依然像这样编程，那么你真不比一个不信基因的医生好到哪里去。在读完本文之前，请不要再编写任何一行代码！   在我开始之前，我应该提醒你，如果你是那些少数懂得国际化的知识的程序员，那么你会发现我讨论的整个话题有那么一点过于简化。我仅仅只是希望在此设立一个门槛，使得每个人都理解关于字符编码究竟都发生了些什么事情，并有希望使写出的代码可以在任意语言下正常工作，而非仅仅只能工作在在不带方言词汇的英语环境中。我还要再提醒你，想创建可以在国际化语言环境下工作的软件，字符处理仅仅只是很小的一部分工作，但是我一次只能写一个主题，所以本文就是关于字符集的。   从历史的角度   理解一件事情的最简单的方法，就是回到它发生的时候去。   你可能以为我要在此谈论那些非常老旧的字符集如EBCDIC。嘛，我们不讨论那些。EBCDIC和你的生活没有关联。我们不需要走到那么远古的时期。   回到再近一点的时间，当Unix被发明，K&#38;R正在写那本著名的The C [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">每个软件开发者<strong style="mso-bidi-font-weight: normal;">必须绝对至少</strong>需要了解的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">和</span></span><span lang="EN-US"><span style="font-family: Calibri;">Character Sets</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">的知识（没有借口！）</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="color: #000000; font-family: 宋体;"><span style="font-size: 10.5pt;">原文：</span></span></span><span lang="EN-US"><a href="http://www.joelonsoftware.com/articles/Unicode.html"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #0000ff;">http://www.joelonsoftware.com/articles/Unicode.html</span></span></a></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">by Joel Spolsky </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">译</span></span></span><span style="font-family: Calibri;"><span lang="EN-US"><span style="font-size: 10.5pt;">windam</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt;">2003.10.8 </span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">星期三</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">你是否曾经对那个神秘的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">标记感到不解？</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><em style="mso-bidi-font-style: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">译注：每个</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span></span></em><span style="font-size: 10.5pt;"><em style="mso-bidi-font-style: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">页面的</span></span><span lang="EN-US"><span style="font-family: Calibri;">head</span></span></em><em style="mso-bidi-font-style: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">块中都可能包含一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span></em></span><em style="mso-bidi-font-style: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">标记，例如：</span></span></span></em></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><em style="mso-bidi-font-style: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">&lt;meta http-equiv=&#8221;Content-Type&#8221; content=&#8221;text/html; charset=UTF-8&#8243; /&gt;</span></span></span></em></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">你知道这东西应该被放到</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">里，但是你从来都没有确切得弄清楚它到底应该是什么？</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">你是否曾经收到过你朋友从</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Bulgaria</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">发来的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Email</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，它的主题行是</span></span><span lang="EN-US"><span style="font-family: Calibri;">&#8220;???? ?????? ??? ????&#8221;</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">？</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">当我发现还有那么多的软件开发者并没有真正领会关于字符集</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">(Character sets)</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，编码</span></span><span lang="EN-US"><span style="font-family: Calibri;">(encoding)</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">以及相关知识的时候，我非常失望。几年前，</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.fogcreek.com/FogBUGZ/"><span style="color: #0000ff; font-family: Calibri;">FogBUGZ</span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">beta</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">测试者对于它是否能处理收到的日语邮件感到疑惑。日语？他们有日文的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Email</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">？我不知道。但当我仔细研究我们用来解析</span></span><span lang="EN-US"><span style="font-family: Calibri;">MIME email</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的商业</span></span><span lang="EN-US"><span style="font-family: Calibri;">ActiveX</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">控件时，我们发现它恰恰正好对字符集做了完全错误的处理，于是，为了撤销控件中所做的错误转换，并正确的重新处理，我们不得不编写修正它的补救代码。而当我研究另一个商业库的时候，发现它有一样的完全错误的字符代码实现。我和那个代码库的开发者通信，发现他的想法是，他们“不能（对字符集）做任何事（正确的处理）”。就像很多程序员一样，他只是祈祷着，这一切麻烦事都可以被吹走。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">但事实上不会！当我发现流行的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">web</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">开发语言</span></span><span lang="EN-US"><span style="font-family: Calibri;">PHP</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">几乎</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://ca3.php.net/manual/en/language.types.string.php"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="color: #0000ff; font-family: 宋体;">完全的忽略了字符编码的问题</span></span></span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，没心没肺的用了</span></span><span lang="EN-US"><span style="font-family: Calibri;">8bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符，这种傻逼的行为让开发好的国际化</span></span><span lang="EN-US"><span style="font-family: Calibri;">web</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">应用变得几乎不可能的时候，我想，我受够了。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">我在此声明：如果你是一个工作在</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">2003</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">年或之后的程序员（此文写于</span></span><span lang="EN-US"><span style="font-family: Calibri;">2003</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">年</span></span><span lang="EN-US"><span style="font-family: Calibri;">10</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">月），并且你还没有对字符，字符集，编码和</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">有所了解，而且你被我我抓住了，我会罚你在潜艇里剥</span></span><span lang="EN-US"><span style="font-family: Calibri;">6</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">个月的洋葱皮！我发誓我会这样做的！</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">此外还有一事：</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">这真的没那么难</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">在本文中，我将会告诉你每个在工作中的程序员所应知道的。所有关于</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">&#8220;plain text = ascii = character</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">就是</span></span><span lang="EN-US"><span style="font-family: Calibri;">8bit&#8221;</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">的知识不仅仅是错误的，而且是错得令人绝望。如果你依然像这样编程，那么你真不比一个不信基因的医生好到哪里去。在读完本文之前，请不要再编写任何一行代码！</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">在我开始之前，我应该提醒你，如果你是那些少数懂得国际化的知识的程序员，那么你会发现我讨论的整个话题有那么一点过于简化。我仅仅只是希望在此设立一个门槛，使得每个人都理解关于字符编码究竟都发生了些什么事情，并有希望使写出的代码可以在任意语言下正常工作，而非仅仅只能工作在在不带方言词汇的英语环境中。我还要再提醒你，想创建可以在国际化语言环境下工作的软件，字符处理仅仅只是很小的一部分工作，但是我一次只能写一个主题，所以本文就是关于字符集的。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> <span id="more-336"></span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">从历史的角度</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">理解一件事情的最简单的方法，就是回到它发生的时候去。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">你可能以为我要在此谈论那些非常老旧的字符集如</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">EBCDIC</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。嘛，我们不讨论那些。</span></span><span lang="EN-US"><span style="font-family: Calibri;">EBCDIC</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">和你的生活没有关联。我们不需要走到那么远古的时期。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00213.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image002[13]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00213_thumb.jpg" alt="clip_image002[13]" width="273" height="146" border="0" hspace="12" /></a><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">回到再近一点的时间，当</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unix</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">被发明，</span></span><span lang="EN-US"><span style="font-family: Calibri;">K&amp;R</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">正在写那本著名的</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://cm.bell-labs.com/cm/cs/cbook/"><span style="color: #0000ff; font-family: Calibri;">The C Programming Language</span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的时候，一切都还很简单。</span></span><span lang="EN-US"><span style="font-family: Calibri;">EBCDIC</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">正逐渐消亡。那时唯一有意义的就是那些美好的，不包含方言字符的英文字母。于是我们将这套将每一个字符通过</span></span><span lang="EN-US"><span style="font-family: Calibri;">32</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">到</span></span><span lang="EN-US"><span style="font-family: Calibri;">127</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">之间的数进行表示的编码，记做</span></span></span><span lang="EN-US"><a href="http://www.robelle.com/library/smugbook/ascii.html"><span style="color: #0000ff; font-family: Calibri;">ASCII</span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。例如，空格是</span></span><span lang="EN-US"><span style="font-family: Calibri;">32</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">&#8220;A&#8221;</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">是</span></span><span lang="EN-US"><span style="font-family: Calibri;">65</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。这些字符用</span></span><span lang="EN-US"><span style="font-family: Calibri;">7</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个</span></span><span lang="EN-US"><span style="font-family: Calibri;">bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">就可以存储。那个年代的电脑多数采用</span></span><span lang="EN-US"><span style="font-family: Calibri;">8bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">为一字节，因此你不光可以用</span></span><span lang="EN-US"><span style="font-family: Calibri;">7</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个</span></span><span lang="EN-US"><span style="font-family: Calibri;">bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">保存每个可能的</span></span><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符，你还有一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的空余，如果你够邪恶，你也可以将之用于自己的狡猾目的：</span></span><span lang="EN-US"><span style="font-family: Calibri;">WordStar</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">用了一个很</span></span><span lang="EN-US"><span style="font-family: Calibri;">2B</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的做法——用最高位来标识一个单词的最后一个字母，这宣告了</span></span><span lang="EN-US"><span style="font-family: Calibri;">WordStar</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">仅能用于英文文本。比</span></span><span lang="EN-US"><span style="font-family: Calibri;">32</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">小的编码被称为不可打印字符，并且被用来释放诅咒——只是开个玩笑，实际上它们是控制字符，比如</span></span><span lang="EN-US"><span style="font-family: Calibri;">7</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">可以让你的电脑发出蜂鸣声，</span></span><span lang="EN-US"><span style="font-family: Calibri;">12</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">可以让当前页纸被送出打印机并传入新纸。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">如果你只是一个英语使用者的话，这一切都很美好。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">因为一个字节有</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个比特，于是很多人就想，“哎，我们可以使用</span></span><span lang="EN-US"><span style="font-family: Calibri;">128-255</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">作为自己的用途”。不过麻烦在于，很多人同时有了这个想法，并且他们关于如何使用</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">～</span></span><span lang="EN-US"><span style="font-family: Calibri;">255</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的想法又各不相同。</span></span><span lang="EN-US"><span style="font-family: Calibri;">IBM-PC</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">弄出来一个被称为</span></span><span lang="EN-US"><span style="font-family: Calibri;">OEM</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符集的玩意，为欧洲的语言提供了一些方言字母，以及</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.jimprice.com/ascii-dos.gif"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="color: #0000ff; font-family: 宋体;">一串用来绘制线条的字符</span></span></span></a><span style="color: #000000; font-family: Calibri;">&#8230; </span></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">如水平条，竖直条，右侧带有小的拐角的水平条等。这样，你就可以使用这些画线字符，在屏幕上绘制整洁漂亮的方框与线条了。你至今依然可以在那些那些运行于</span></span><span lang="EN-US"><span style="font-family: Calibri;">8088</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">计算机的干洗机上看到这些字符。事实上，当除美国之外的人们开始购买</span></span><span lang="EN-US"><span style="font-family: Calibri;">PC</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">时，人们凭空捏造出各种各样的</span></span><span lang="EN-US"><span style="font-family: Calibri;">OEM</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符集，都将高</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">位用于自己的用途。举例来说，在一些</span></span><span lang="EN-US"><span style="font-family: Calibri;">PC</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">上，字符码</span></span><span lang="EN-US"><span style="font-family: Calibri;">130</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">被显示为</span></span><span lang="EN-US"><span style="font-family: Calibri;">é</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，而在以色列销售的计算机，这个字符码则显示为希伯来字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">(<span style="mso-no-proof: yes;"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00432.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image004[32]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00432_thumb.jpg" alt="clip_image004[32]" width="4" height="9" border="0" /></a></span>) </span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，于是，如果美国人将他们的</span></span><span lang="EN-US"><span style="font-family: Calibri;">résumés</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（简历）发送到以色列，这简历在到达后就变成了</span></span><span lang="EN-US"><span style="font-family: Calibri;">r<span style="mso-no-proof: yes;"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00433.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image004[33]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00433_thumb.jpg" alt="clip_image004[33]" width="4" height="9" border="0" /></a></span>sum<span style="mso-no-proof: yes;"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00434.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image004[34]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00434_thumb.jpg" alt="clip_image004[34]" width="4" height="9" border="0" /></a></span>s</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。在很多场合，比如俄语中，关于如何使用高</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">位字符有各种各样的办法，因此你甚至无法可靠的交换俄语文档。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">最终，这种混乱无序的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">OEM</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码被</span></span><span lang="EN-US"><span style="font-family: Calibri;">ANSI</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">标准统一了。在</span></span><span lang="EN-US"><span style="font-family: Calibri;">ANSI</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">标准中，所有人都同意对低</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的定义，与</span></span><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">码保持一致，高</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">位编码的处理方式，则取决于你生活在什么地方。这些对高</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">位编码做不同处理的体系被称为</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.i18nguy.com/unicode/codepages.html#msftdos"><span style="color: #0000ff;"><span style="font-family: Calibri;">code pages</span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">（代码页）</span></span></span></span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。所以，例如以色列的</span></span><span lang="EN-US"><span style="font-family: Calibri;">DOS</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">使用的代码页被称为</span></span><span lang="EN-US"><span style="font-family: Calibri;">862</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，而希腊的用户使用的代码页是</span></span><span lang="EN-US"><span style="font-family: Calibri;">737</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。这些不同代码页在</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">以下的部分都是相同的，而对于</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">以上的编码则有不同的处理方案（那些搞笑的字母皆被含在其中）。</span></span><span lang="EN-US"><span style="font-family: Calibri;">MS-DOS</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的国家版本中包含了很多上述这种代码页，可以处理从英语到冰岛语的一切，他们甚至还包括了少数“多语言”代码页，可以在一台电脑上同时支持世界语和加利西亚语！</span></span><span lang="EN-US"><span style="font-family: Calibri;">WOW</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">！但是话说回来，由于希伯来语和希腊语分属不同的代码页，对大于</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">的字符有完全不同的解释，因此除非使用位图，否则想在一台电脑上同时支持这两种语言则是一件完全不可能的任务。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">另一方面，在亚洲，事情则更加令人抓狂了，因为亚洲的许多语言拥有数以千记的字符，这是无论如何不可能用</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个</span></span><span lang="EN-US"><span style="font-family: Calibri;">bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">进行编码的。这种情况通常是用“</span></span><span lang="EN-US"><span style="font-family: Calibri;">DBCS</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">”的方式进行解决，也即双字节字符集，在双字节字符集中，有的字符使用一个字节进行表示，而有的则需要存储在</span></span><span lang="EN-US"><span style="font-family: Calibri;">2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个字节中。这种字符集的问题在于，通常想要在字符串中顺序遍历比较容易，但是要想反向遍历，则几乎不可能。对于这类字符串，程序员们最好不要使用</span></span><span lang="EN-US"><span style="font-family: Calibri;">s++</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">或者</span></span><span lang="EN-US"><span style="font-family: Calibri;">s&#8211;</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">对其进行遍历，而是最好使用预定义的函数，例如</span></span><span lang="EN-US"><span style="font-family: Calibri;">Windows</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">平台上的</span></span><span lang="EN-US"><span style="font-family: Calibri;">AnsiNext</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">和</span></span><span lang="EN-US"><span style="font-family: Calibri;">AnsiPrev</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">函数，它们知道如何处理这一切乱七八糟的麻烦事。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">但是，绝大多数人依然以为一个字节就恰好对应着一个字母，或是一个字母就是一个字节。只要你永远不把一个字符串从一台电脑上拷贝到另一台电脑上，或者从来不使用超过一种语言，这种做法就可以在某种意义上正常的工作。但是，理所当然的，由于因特网的普及，现在将字符串从一台电脑拷贝到另一台电脑变得越来越常见，那么这一切做法的基础就垮台了。幸运的是，</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">被发明了。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">Unicode</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">针对人们想要创建一个可以囊括这颗星球上一切可能的书写系统的字符集的目标，</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode </span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">是一次勇敢的尝试。一些人以为</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">只是一个简单的</span></span><span lang="EN-US"><span style="font-family: Calibri;">16bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码，其中的每个字符都可以拥有</span></span><span lang="EN-US"><span style="font-family: Calibri;">16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个</span></span><span lang="EN-US"><span style="font-family: Calibri;">bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，因而可以支持最多</span></span><span lang="EN-US"><span style="font-family: Calibri;">65536</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">种可能的字符，<strong style="mso-bidi-font-weight: normal;">这种对</strong></span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></strong><span style="font-family: 宋体;"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;">的认识，事实上，是错误的</span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;">。这是针对</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">流传得最广的一种误解，所以，如果你也是这样认为的，不用觉得过于沮丧。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">事实上，</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">针对字符有一套完全不同的思路，因此你必须遵循</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">看待事物的思维模式，否则你什么都理解不了。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">直到现在，我们都认为一个字母可以被映射为若干比特，你可以将之存储于内存中或者磁盘上。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">例如</span></span></span><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt;"> A -&gt; 0100 0001</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">在</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中，一个字母被映射到一个称为</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的东西，这只是一个理论上的抽象概念。至于这个</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">如何在内存中表示，或是在磁盘中存储，则又是另一回事了。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">在</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中，字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">A</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">是抽象的形象。它在天堂中漂浮着：</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Georgia;"><span style="font-size: 36pt; color: #000000;">A</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">这个抽象的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">中的</span></span></span><span lang="EN-US"><span style="font-family: Georgia;"><span style="font-size: 36pt;">A</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">不同于</span></span></span><span lang="EN-US"><span style="font-family: Georgia;"><span style="font-size: 36pt;">B</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">，且不同于</span></span></span><span lang="EN-US"><span style="font-family: Georgia;"><span style="font-size: 36pt;">a</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">。但是与</span></span></span><span lang="EN-US"><span style="font-family: 'Arial Unicode MS';"><span style="font-size: 36pt;">A</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">或者</span></span></span><strong style="mso-bidi-font-weight: normal;"><em style="mso-bidi-font-style: normal;"><span lang="EN-US"><span style="font-family: Georgia;"><span style="font-size: 24pt;">A</span></span></span></em></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">以及</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: 'Times New Roman';">A</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">都是等同的。关键的地方在于，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Times New Roman</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字体中的</span></span><span lang="EN-US"><span style="font-family: Calibri;">A</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">与</span></span><span lang="EN-US"><span style="font-family: Calibri;">Helvetica</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字体中的</span></span><span lang="EN-US"><span style="font-family: Calibri;">A</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">是相同的字符，而与小写的“</span></span><span lang="EN-US"><span style="font-family: Calibri;">a</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">”是不同的字符。这看起来并没有什么有所疑议的，但是在某些语言中，仅仅指出一个字母是什么就可能引发疑议。德文字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">ß</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">究竟是一个真实的字母，还是仅仅只是</span></span><span lang="EN-US"><span style="font-family: Calibri;">s</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的另一种花式写法？如果一个单词末尾的字母的形状改变了，那么这个字母是否意味着一个不同的字母——请作答？在希伯来文中，上面这个问题的回答为真，而在阿拉伯语中，则为假。无论如何，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">协会的那些聪明人们已经在上一个十年间把这些东西都搞定了，尽管那其中依然包含了一大堆政治上的讨价还价，但是最终的结果是，你不用再为这些麻烦事而烦神了——他们把这些玩意都搞定了。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt;">Unicode</span></span></span><span style="font-size: 10.5pt;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">协会为每一个字母表中的每一个抽象字母都赋予了一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Magic number</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，写起来就像是这样：</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">U+0639</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。这个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Magic number</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（魔数）就被称为</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。其中的</span></span><span lang="EN-US"><span style="font-family: Calibri;">U+</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">意味着</span></span><span lang="EN-US"><span style="font-family: Calibri;">&#8220;Unicode&#8221;</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，而数字的部分则是</span></span><span lang="EN-US"><span style="font-family: Calibri;">16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">进制的（译注：</span></span><span lang="EN-US"><span style="font-family: Calibri;">4</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">位</span></span><span lang="EN-US"><span style="font-family: Calibri;">16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">进制数也就意味着需要</span></span><span lang="EN-US"><span style="font-family: Calibri;">16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个</span></span><span lang="EN-US"><span style="font-family: Calibri;">bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的存储空间）。那么</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">U+0639</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">实际上就是阿拉伯字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">Ain</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。英文字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">A</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">则是</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">U+0041</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。你可以在</span></span><span lang="EN-US"><span style="font-family: Calibri;">Windows 2000/XP(</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">译注：在</span></span><span lang="EN-US"><span style="font-family: Calibri;">Vista or Win7</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">上也可</span></span><span lang="EN-US"><span style="font-family: Calibri;">)</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">使用</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">charmap</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">实用工具来查询这些</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point(</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">译注：点击开始菜单，运行，输入</span></span><span lang="EN-US"><span style="font-family: Calibri;">charmap</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">回车启动该工具</span></span><span lang="EN-US"><span style="font-family: Calibri;">)</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，也可以通过访问</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.unicode.org/"><span style="color: #0000ff;"><span style="font-family: Calibri;">Unicode</span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">的网站</span></span></span></span></a></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">查询。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-no-proof: yes;" lang="EN-US"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00613.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image006[13]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00613_thumb.jpg" alt="clip_image006[13]" width="490" height="391" border="0" /></a></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt;">(</span></span></span><span style="font-size: 10.5pt;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">译补图：这是</span></span><span lang="EN-US"><span style="font-family: Calibri;">charmap</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">实用工具的运行界面，其中英文字母</span></span><span lang="EN-US"><span style="font-family: Calibri;">A</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">如图所示恰为</span></span></span><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt;">U+0041)</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">并没有人真正对</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">所能表示字母数目上限进行限制，事实上，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">所能表示的字母数目可以超过</span></span><span lang="EN-US"><span style="font-family: Calibri;">65536</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，所以并不是每一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字母都可以被塞进</span></span><span lang="EN-US"><span style="font-family: Calibri;">2</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">字节的空间中，不过这只是个传闻。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt;">OK</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">，假设我们有这样一个字符串</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: 'Times New Roman';" lang="EN-US"><span style="font-family: Georgia;"><span style="font-size: 16pt; color: #000000;">Hello</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">在</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中，这被表示为以下五个</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">：</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">U+0047<span style="mso-spacerun: yes;">  </span>U+0065<span style="mso-spacerun: yes;">  </span>U+006C<span style="mso-spacerun: yes;">  </span>U+006C<span style="mso-spacerun: yes;">  </span>U+006F.</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">只是一组</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。事实上，也就是数字。到目前为止，我们还没有提到过如何在内存中存储它们，或是在</span></span><span lang="EN-US"><span style="font-family: Calibri;">email</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">中如何表示它们。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">Encodings</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">这就是</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">encodings </span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">（编码）发挥作用的地方了。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">关于</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码的最早的主意是这样的，嘿伙计，咱们把这些数字每个存成</span></span><span lang="EN-US"><span style="font-family: Calibri;">2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字节吧。（这个主意也正是</span></span><span lang="EN-US"><span style="font-family: Calibri;">2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字节神话的渊源）于是，我们的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Helllo</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">就变成了下面这样：</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">00 48 00 65 00 6C 00 6C 00 6F</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">对吗？别着急！为什么不能是下面这样呢：</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">48 00 65 00 6C 00 6C 00 6F 00</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">好吧，从技术上说，这样也可以，我确实这么认为，而事实上，由于早期的实现者们在他们要存储</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的时候，希望依据特定的</span></span><span lang="EN-US"><span style="font-family: Calibri;">CPU</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">架构选择是使用大端</span></span><span lang="EN-US"><span style="font-family: Calibri;">(high-endian)</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">还是小端</span></span><span lang="EN-US"><span style="font-family: Calibri;">(low-endian)</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">模式，这样使得</span></span><span lang="EN-US"><span style="font-family: Calibri;">CPU</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">处理速度得以最佳化。于是，看哪，很快的，就出现了两种不同的存储</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的方式。于是人们不得不创造一个离奇的约定，在</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的字符串的最前面加上一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">FE FF</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">标识符。这个标识符被称为</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://msdn.microsoft.com/en-us/library/ms776429"><span style="color: #0000ff;"><span style="font-family: Calibri;">Unicode Byte Order Mark(Unicode</span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">字节序标<span lang="EN-US">识符</span></span></span></span><span style="font-family: Calibri;">)</span></span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，并且，如果你反转了你的高低字节，那么这个标识符就会变成</span></span><span lang="EN-US"><span style="font-family: Calibri;">FF FE</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，于是读取你的字符串的人就可以知道他们必须要翻转你的每一对高低字节。但是，喔，并不是每一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">字符串都在开头有这个字节序标识符。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">一开始，这一切看起来似乎还是挺好的，但是逐渐的，程序员们开始抱怨，“看那一堆没用的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">0</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">！”——由于这些美国程序员多数情况下只使用英文文本，也就意味着他们几乎不会用到那些高于</span></span><span lang="EN-US"><span style="font-family: Calibri;">U+00FF</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。尤其是他们多数还是加州的新自由主义嬉皮士，假若他们是德州人，那么他们多半不会在意这些多出来的字节。但是最终，这帮加州的苦孩子们终于无法容忍字符串存储空间被无端的增长一倍，并且，由于有那么多的文档已经用各种</span></span><span lang="EN-US"><span style="font-family: Calibri;">ANSI</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">和</span></span><span lang="EN-US"><span style="font-family: Calibri;">DBCS</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符集存在了，谁会把这些文档都转换到</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">下来呢？难道是我（法语）来？仅仅因为这样的想法，于是在好几年的时间里，大多数人都决定无视</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">，这使得事情变得更糟。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="font-family: 宋体;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="color: #000000;"><span style="font-size: 10.5pt;">终于，一个天才的概念</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="color: #0000ff;">被发明出来</span></span></span></a></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="color: #000000;">了——</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.utf-8.com/"><span style="color: #0000ff; font-family: Calibri;">UTF-8</span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">在内存中通过</span></span><span lang="EN-US"><span style="font-family: Calibri;">8bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的字节来保存</span></span><span lang="EN-US"><span style="font-family: Calibri;">U + magic number</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，定义了保存</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符串的一整套系统。在</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中，</span></span><span lang="EN-US"><span style="font-family: Calibri;">0-127</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">之间的</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">被保存在一个单字节中。只有那些大于等于</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，需要用到</span></span><span lang="EN-US"><span style="font-family: Calibri;">2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，</span></span><span lang="EN-US"><span style="font-family: Calibri;">3</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">以及多至</span></span><span lang="EN-US"><span style="font-family: Calibri;">6</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">个字节来保存。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="mso-no-proof: yes;" lang="EN-US"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00814.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image008[14]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00814_thumb.jpg" alt="clip_image008[14]" width="547" height="87" border="0" /></a></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">这种做法获得了一个非常不错的副作用——那就是</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中的英文文本与</span></span><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中的英文文本可以完全的保持一致，于是美国人们都不会发现有什么事情变得不一样了。只有这世界上其他地方的人们不得不跳过这个坑。举例来说，</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">Hello</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，这个字符串由</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">：</span></span><span lang="EN-US"><span style="font-family: Calibri;">U+0048 U+0065 U+006C U+006C U+006F</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">组成，在存储的时候，被保存为</span></span><span lang="EN-US"><span style="font-family: Calibri;">48 65 6C 6C 6F</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，这，恰恰正好与</span></span><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，</span></span><span lang="EN-US"><span style="font-family: Calibri;">ANSI</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，以及这颗星球上所有的</span></span><span lang="EN-US"><span style="font-family: Calibri;">OEM</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符集中的表示都完全一样。现在，如果你需要去使用方言字母，或者是希腊字母，或者是克林贡语字母的话，那么你就不得不为每个</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">使用多个字节去存储了，不过美国人永远都不用在意这些了。（</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">还有一个非常漂亮的特性，以往的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符串想使用老式的以单个</span></span><span lang="EN-US"><span style="font-family: Calibri;">byte</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的</span></span><span lang="EN-US"><span style="font-family: Calibri;">0</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">作为字符串的结尾并不至于切断字符串的话需要一些处理代码，而</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">则可以忽略之。）</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">到目前为止，我已经告诉了你</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码的三种方法。最传统的两字节存储方式被称为</span></span><span lang="EN-US"><span style="font-family: Calibri;">UCS-2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（因为有</span></span><span lang="EN-US"><span style="font-family: Calibri;">2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个字节）或者</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（因为有</span></span><span lang="EN-US"><span style="font-family: Calibri;">16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">），并且你还得自己弄清楚究竟这是一个大端</span></span><span lang="EN-US"><span style="font-family: Calibri;">(High-endian)UCS-2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">还是一个小端</span></span><span lang="EN-US"><span style="font-family: Calibri;">(low-endian)UCS-2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。你还可以采用全新的</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">标准，如果你只使用英文文本，它会让你在碰到一个无脑程序时，即便它完全无视了除</span></span><span lang="EN-US"><span style="font-family: Calibri;">ACSII</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">之外的一切，你依然会过得很幸福！</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">事实上还有其他一系列方法来编码</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。有一种编码叫做</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-7</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，它与</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">有很多相似之处，但是它假定所有字节的最高比特都是</span></span><span lang="EN-US"><span style="font-family: Calibri;">0</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">。因为这个原因，如果你要把</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字符串传递给一个严格认为</span></span><span lang="EN-US"><span style="font-family: Calibri;">7bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">就足够用的警方邮件系统，那么感谢</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-7</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">吧，它能使你免于痛苦。还有种</span></span><span lang="EN-US"><span style="font-family: Calibri;">UCS-4</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码，它使用</span></span><span lang="EN-US"><span style="font-family: Calibri;">4</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个字节存储一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，它有个不错的特性，每个</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">都是等长的，但是麻烦在于，它是在浪费了太多的内存，以至于即便是得克萨斯人也不敢使用它。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">事实上你正在使用</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">所表示的柏拉图式的理想的字母来考虑这些问题，这些</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">同样也可以使用任何一种旧的学院派的编码方案来表示。举例而言，你同样可以用</span></span><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">或古希腊</span></span><span lang="EN-US"><span style="font-family: Calibri;">OEM</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码或希伯来</span></span><span lang="EN-US"><span style="font-family: Calibri;">ANSI</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码，乃至迄今为止已被发明的数百种编码，来表示一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码的字符串</span></span><span lang="EN-US"><span style="font-family: Calibri;">Hello</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（</span></span><span lang="EN-US"><span style="font-family: Calibri;">U+0048 U+0065 U+006C U+006C U+006F</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">）。但是这些做法有一个陷阱，那就是某些字母可能不能正常显示！如果你想要将某个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">在某种编码中表示，而该编码中又没有能对应上该</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">的，你常常会得到一些小的问号：？或者，如果你的人品不错，你会得到一个</span></span></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%;" lang="EN-US"><span style="font-family: Tahoma;"><span style="font-size: 13.5pt; background-color: #f5f4df;">�</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">存在数以百计的传统编码，它们都只能正确表示</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的某些子集，而对那些处理不了的</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，则用问号来处理。有一些流行的英文编码，诸如</span></span><span lang="EN-US"><span style="font-family: Calibri;">Windows-1252</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（这是</span></span><span lang="EN-US"><span style="font-family: Calibri;">Windows 9x</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中的西欧语言标准），以及</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.htmlhelp.com/reference/charset/"><span style="color: #0000ff; font-family: Calibri;">ISO-8859-1</span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，</span></span><span lang="EN-US"><span style="font-family: Calibri;">aka Latin-1</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（同样在任何一个西欧语言中都会有用的），如果你想要用上面这些编码来处理俄文或者是希伯来字母，那么你会得到大量的问号。与之对应的，</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF7,8,16</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">以及</span></span><span lang="EN-US"><span style="font-family: Calibri;">32</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">等编码则有非常棒的特性，它们可以正确表示任何</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode code point</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 15pt; color: #000000;">关于编码的最重要的事实</span></span></span></strong><strong style="mso-bidi-font-weight: normal;"></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">如果你把我之前所解释的所有一切都忘光了，请你至少记住一个最最最重要的事实。<strong style="mso-bidi-font-weight: normal;">如果你有一个字符串，而不知道它的编码，那么这个字符串是毫无意义的。</strong>你再也不能把脑袋埋到沙子里，然后假装“普通”文本就是</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="text-decoration: underline;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">这世界上就没有普通文本这回事。</span></span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">如果你有一个字符串，不管是在内存里，还是在文件里，还是在一封</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">email</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">中，你必须知道它的确切的编码，否则你不可能做到正确的解释它，或是向用户显示。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">几乎所有的像是“我的网站看起来像是在胡言乱语”，或者是“如果我在邮件里用了方言字母，那么她就无法阅读”的傻逼问题，几乎都是由于某些天真犯二的程序员没能理解下面这个事实：如果你不告诉我一个特定的字符串用的是哪一种编码，</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">或是</span></span><span lang="EN-US"><span style="font-family: Calibri;">ASCII</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">或是</span></span><span lang="EN-US"><span style="font-family: Calibri;">ISO 8859-1</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（</span></span><span lang="EN-US"><span style="font-family: Calibri;">Latin 1</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">）或是</span></span><span lang="EN-US"><span style="font-family: Calibri;">Windows 1252</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（西欧），那么我就不可能正确的显示这个字符串，甚至不可能知道哪里是它的结尾。有上百种编码格式的存在，并且一旦出现大于</span></span><span lang="EN-US"><span style="font-family: Calibri;">127</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的</span></span><span lang="EN-US"><span style="font-family: Calibri;">code point</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">，那么一切就全完了。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">一个字符串是如何编码的，我们要如何维护这样一个信息呢？好吧，关于这件事情，有一些标准做法。对于</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">email</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">消息，你最好在正文的头部，加入这样一行字符串：</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;">Content-Type: text/plain; charset=&#8221;UTF-8&#8243;</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">对于网页页面，最早的想法是由</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">web</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">服务器返回一个类似的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，把这个信息放在与网页内容一同传输的</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTTP</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">报头中，不是放在</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">页面里，而是放在响应报头里，在</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">内容之前被发送。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">但这种做法会导致问题。想象一下你有一个巨大的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">web</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">服务器，上面跑着很多网站，并且有着由不同的人贡献的数以百计的网页。这些人创建网页的时候，他们所使用的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Microsoft FrontPage</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">可能以任何它觉得合适的方式来选择编码进行存储。</span></span><span lang="EN-US"><span style="font-family: Calibri;">web</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">服务器本身对此一无所知，它不可能知道每一个文件是以什么编码格式写的，所以它也就无法为之发送</span></span><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">头。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">如果你使用某种特殊的</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">tag</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，把</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">文件所使用的</span></span><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">直接写到</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">文件里，就会让后续的事情变得更加方便。当然这种做法会让某些纯化论者感到抓狂</span></span><span lang="EN-US"><span style="font-family: Calibri;">&#8230;</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">如果你不知道这个</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">文件的编码，你要如何去读取它？！幸运的是，几乎所有的编码对</span></span><span lang="EN-US"><span style="font-family: Calibri;">32</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">到</span></span><span lang="EN-US"><span style="font-family: Calibri;">127</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">之间的字符都是同样对待的，于是，在需要使用任何诡异的字母之前，你总是可以在</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">页面中读取到至少像下面这样多的内容：</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="left"><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 12pt; color: #000000;">&lt;html&gt;</span></span></span></strong></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="left"><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 12pt; color: #000000;">&lt;head&gt;</span></span></span></strong></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="left"><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 12pt; color: #000000;">&lt;meta http-equiv=&#8221;Content-Type&#8221; content=&#8221;text/html; charset=utf-8&#8243;&gt;</span></span></span></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">但是需要注意的是，这个</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">meta tag</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">必须是</span></span><span lang="EN-US"><span style="font-family: Calibri;">&lt;head&gt;</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">节中最先出现的东西。因为只要网页浏览器见到这个</span></span><span lang="EN-US"><span style="font-family: Calibri;">tag</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">，它就会停止解析这个页面，并且使用你所指定的编码开始重新解释整个页面。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">如果网页浏览器即无法从</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">http</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">报头也无法从</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的</span></span><span lang="EN-US"><span style="font-family: Calibri;">meta</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">标记中找到任何</span></span><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">信息，那么它们会如何对待这个网页呢？事实上，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Internet Explorer</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">做了一些有趣的事情，它基于一种启发式的方法去猜（依照典型编码的典型文本中，各种不同的语言使其字节呈现不同的分布频率的规律）。因为各种旧的</span></span><span lang="EN-US"><span style="font-family: Calibri;">8bit</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">代码页会尝试把他们国家的字母放在</span></span><span lang="EN-US"><span style="font-family: Calibri;">128</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">～</span></span><span lang="EN-US"><span style="font-family: Calibri;">255</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中不同的区间段里，同时又由于每一种人类语言对字母的使用都呈现不同的统计特征，所以上述方案，有一定的概率是可以工作的。这做法是很怪异的，这使得那些天真无邪的网页作者，在从来不知道每个</span></span><span lang="EN-US"><span style="font-family: Calibri;">HTML</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">页面都需要一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">Content-Type</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">头的情况下继续写网页，并且当他们在浏览器中查看时，发现一切都是正常的。直到有一天，他们写了点东西，与他们母语中的字母频率分布不相符合，于是</span></span><span lang="EN-US"><span style="font-family: Calibri;">Internet Explorer</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">便认为这是一段韩语，然后，就这么继续显示出来……</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">我相信，这证明了</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://en.wikipedia.org/wiki/Robustness_principle"><span style="color: #0000ff;"><span style="font-family: Calibri;">Postel</span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">法则</span></span></span></span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">中所说的，“宽容的对待输入，而保守的输出”，坦白说并不是一个好的工程原则。无论如何，当这个网站的可怜的读者，在面对这个被显示成韩语（并且事实上是根本无法理解的韩语）而事实上是保加利亚语的网页时，要怎么做呢？他使用</span></span><span lang="EN-US"><span style="font-family: Calibri;">View|Encoding</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">菜单，并且依次尝试每一个编码的选项（至少有十数个东欧语言选项），直到一切变得正常。但是，事实上，多数人都不知道要这么做。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="center"><span style="mso-no-proof: yes;" lang="EN-US"><a href="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00913.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image009[13]" src="http://www.windameister.org/blog/wp-content/uploads/2012/05/clip_image00913_thumb.jpg" alt="clip_image009[13]" width="300" height="225" border="0" /></a></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="font-family: 宋体;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="color: #000000;"><span style="font-size: 10.5pt;">在</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.fogcreek.com/FogBUGZ/"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="color: #0000ff;">我<span lang="EN-US">公司</span></span></span></span></a></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="color: #000000;">所发布的网站管理软件</span></span></span></span><span style="font-size: 10.5pt;"><span style="font-family: Calibri;"><span lang="EN-US"><a href="http://www.fogcreek.com/CityDesk/"><span style="color: #0000ff;">CityDesk</span></a></span></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的最新版本中，我们决定内部的一切都用</span></span><span lang="EN-US"><span style="font-family: Calibri;">UCS-2(2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">字节）</span></span><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">表示，这也是</span></span><span lang="EN-US"><span style="font-family: Calibri;">Visual Basic</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，</span></span><span lang="EN-US"><span style="font-family: Calibri;">COM</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">以及</span></span><span lang="EN-US"><span style="font-family: Calibri;">Windows NT/2000/XP</span></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">所使用的原生的字符串类型。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">在</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">C++</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">代码中，这意味着当定义字符串时，我们使用</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">wchar_t</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">（宽字符）来替代</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">char</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，并且使用</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">wcs</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">系函数来替代</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">str</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">系函数（例如，使用</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">wcscat</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">和</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">wcslen</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">而不是</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">strcat</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">和</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">strlen</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">）。要在</span></span><span lang="EN-US"><span style="font-family: Calibri;">C</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">代码中创建一个</span></span><span lang="EN-US"><span style="font-family: Calibri;">UCS-2</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的字符串，你只需要在字符串定义前增加一个</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">L</span></span></strong><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，如：</span></span><strong style="mso-bidi-font-weight: normal;"><span lang="EN-US"><span style="font-family: Calibri;">L&#8221;Hello&#8221;</span></span></strong></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">当</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">CityDesk</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">发布网页时，它将之转换为已经为网页浏览器所支持多年的</span></span><span lang="EN-US"><span style="font-family: Calibri;">UTF-8</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">编码格式。这也是</span></span><em style="mso-bidi-font-style: normal;"><span lang="EN-US"><span style="font-family: Calibri;">Joel on Software</span></span></em><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.joelonsoftware.com/navLinks/OtherLanguages.html"><span style="color: #0000ff;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">全部</span></span></span><span style="font-family: Calibri;">29</span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">种语言版本</span></span></span></span></a></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">所使用的编码，并且我从来没有听到过任何一个人抱怨说在阅读它的时候遇到麻烦。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">本文的篇幅有点长，并且我也不可能覆盖关于</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">和字符编码的所有话题，我希望的是，如果你已经阅读到这里，你已经知道了足够多的知识，我留给你的任务，就是回去编写程序，并且记得在对付疾病的时候使用抗生素，而不是水蛭和魔咒。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="font-family: 宋体;"><span style="color: #000000;"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-size: 10.5pt;">还想知道更多？</span></span></strong><span style="font-size: 10.5pt;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;">你现在阅读的是</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.joelonsoftware.com/"><span style="color: #0000ff; font-family: Calibri;">Joel on Software</span></a></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">，这里填满了各种经年累月积累下来的关于软件开发，管理软件团队，设计用户界面，成功运营一家软件公司，以及橡皮鸭的各种胡言乱语的文章。</span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="font-family: 宋体;"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-size: 10.5pt;">关于作者：</span></span></strong><span style="font-size: 10.5pt;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;">我是</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Joel Spolsky</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Fog Creek Software</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">的共同创始人，</span></span><span lang="EN-US"><span style="font-family: Calibri;">Fog Creek Software</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">是一家纽约的公司，它证明了你可以在对待程序员们很好的同时创造出很高的利润。这里的程序员拥有私人的办公室，免费的午餐，以及每周</span></span><span lang="EN-US"><span style="font-family: Calibri;">40</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">个小时的工作时间。公司的客户只为他们满意的软件付费。我们创造了一个更先进的</span></span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><a href="http://www.fogcreek.com/fogbugz/"><span style="color: #0000ff;"><span style="font-family: Calibri;">bug</span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="font-family: 宋体;">跟踪</span></span></span></span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">软件</span></span><span lang="EN-US"><span style="font-family: Calibri;">FogBugz</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，以及软件开发工具。</span></span></span><span lang="EN-US"><a href="http://www.fogcreek.com/kiln/"><span style="color: #0000ff; font-family: Calibri;">Kiln</span></a></span><span style="color: #000000;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，一个分布式的源代码管理系统，如果你迷恋</span></span><span lang="EN-US"><span style="font-family: Calibri;">svn</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，它会让你非常惊喜，以及</span></span><span lang="EN-US"><span style="font-family: Calibri;">Fog Creek Copilot</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">，可以让</span></span></span><span lang="EN-US"><a href="https://www.copilot.com/"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;" lang="EN-US"><span lang="EN-US"><span style="color: #0000ff;"><span style="font-family: 宋体;">访问<span lang="EN-US">远程<span lang="EN-US">桌面</span></span></span></span></span></span></a></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="color: #000000; font-family: 宋体;">变得更加容易。我同时也是</span></span><span lang="EN-US"><a href="http://stackoverflow.com/"><span style="color: #0000ff; font-family: Calibri;">Stack Overflow</span></a></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt; color: #000000;">的共同创始人。</span></span></span><strong style="mso-bidi-font-weight: normal;"></strong></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span style="color: #000000;"><span style="font-family: 宋体;"><strong style="mso-bidi-font-weight: normal;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-size: 10.5pt;">译注</span></span></strong><span style="font-size: 10.5pt;"><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;">：本文对</span></span></span><span style="font-size: 10.5pt;"><span lang="EN-US"><span style="font-family: Calibri;">Unicode</span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;">和编码的解释非常棒，将编码和字符集的来龙去脉解释得深入浅出，是每个合格的程序员所必知必会的基础知识，本人在阅读<a href="http://book.douban.com/subject/3745143/">《Game Engine Architecture》</a></span></span></span><span style="mso-ascii-font-family: calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: calibri; mso-hansi-theme-font: minor-latin;"><span style="font-family: 宋体;"><span style="font-size: 10.5pt;">一书时，了解到此文，遂生出翻译的兴趣，翻译的过程中确又发现再次理清了若干此前未曾真正理解的概念，只因英文水平和精力有限，难免有所错漏，如有指正，不吝感激。</span></span></span></span></p>
<p class="MsoNormal" style="text-justify: inter-ideograph; line-height: normal; list-style-type: disc; margin: 0cm 0cm 0pt;" align="justify"><span lang="EN-US"><span style="font-family: Calibri;"><span style="font-size: 10.5pt; color: #000000;"> </span></span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2012/05/03/translated-things-on-unicode-and-charset-each-developer-should-know-at-least/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Crysis 地形渲染技术剖析——材质与LOD</title>
		<link>http://www.windameister.org/blog/2011/11/04/crysis-terrain-render-tech-anaylsis-material-and-lod/</link>
		<comments>http://www.windameister.org/blog/2011/11/04/crysis-terrain-render-tech-anaylsis-material-and-lod/#comments</comments>
		<pubDate>Thu, 03 Nov 2011 16:09:00 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[3D渲染]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[Crysis]]></category>
		<category><![CDATA[terrain]]></category>
		<category><![CDATA[地形渲染]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/?p=314</guid>
		<description><![CDATA[材质 Crysis地形的一个最重要的特色是它的地表材质系统。当进入到一定距离之后，可以看到非常精细的地表材质，包括Bump Mapping，Parallax Occlusion Mapping，有了材质系统的支持，Crysis的地形相较基于传统的Texture Splatting的地形可以呈现出令人惊叹的细节。 在POM技术支撑下的Crysis地形： 基于Texture Splatting技术的地形： Crysis的地表材质技术的原理如下： 渲染包括两个步骤，首先基于颜色图和法线图，绘制基本的地形色彩与明暗，这一遍渲染结果主要用于远处地形。然后会针对不同材质，将细节通过AlphaBlend融合到之前的渲染结果上，材质细节通常只在离视野较近的区域内才渲染，因此第二个步骤的耗费并不多，根据实际情况，每帧中大约会有从一百到数百个不等的细节层Mesh被绘制。 第一遍基于颜色图渲染的效果如下： 可以看到，颜色图上提供了明暗细节，这对地形渲染中无处不在的Tiling问题起到了缓解作用。 第二遍Blend上细节之后的效果： Crysis为每个顶点赋予一个材质id，并且根据不同的材质id，将原先完整的地形网格划分成按材质组织的小块网格，（如果整块32×32的网格都是同一种材质，则无需划分），小块网格是通过索引区段的方式定义的。在Crysis中，地形顶点数据结构里Color属性的g分量被用了作材质层的ID。 下图展示了一个网格中的33×33个顶点被区分为两种材质的情况。本图为演示，将顶点颜色涂成不同的颜色，Crysis则是将将材质id通过顶点颜色传入vs。下面的网格中存在两种不同的材质需要分别渲染。 Crysis根据顶点材质id将整块Mesh拆分成以材质id分组的小块Mesh，如图： 不同材质的Mesh之间，有一个三角形的过渡带。 上图中，红色箭头表示草的材质从1过渡到0，蓝色箭头表示沙子材质从1过渡到0。 这个过渡带起到的作用正是让一个处于材质交汇带的三角形，其Alpha可以从1过渡到0。这样和相邻的隶属另一个材质正好融合到一起。 因此，材质过渡区域的三角形会被渲染2到3遍，取决于该三角形的三个顶点分属于2个材质还是3个材质。 上述的融合过程是通过下面这段代码做到的（本文只为解释原理，与真实代码有出入，Crysis的Shader代码没有加密，有心人可自己解包查阅）： 声明常量： float g_InputLayerId; 该常量通过程序传入VS常量中，表示当前渲染Mesh的LayerId。 在vs中计算顶点alpha： float alpha = 1- saturate (g_InputLayerId – Input.Color.g * 255.0f); Input.Color.g中存储的是该顶点所属的LayerId，由于是通过COLOR存储，取值范围是从0.0到1.0，因此在shader里用于计算之前，还需要乘以255.0f还原。 上式的逻辑如下： 如果InputLayerId和当前顶点存储的layerId相同，则alpha为1，否则，如g_InputLayerId与当前顶点上的layerId不同，则alpha为0。 因为可以使用不同材质做细节层的渲染，Bump Mapping，Parallax Occlusion Mapping这类技术对于地表细节的表现提升极为明显。除了Bump Map之外，Crysis还将Detail Bump Map，Specular Map等用于提升材质细节的技术纳入到地形细节层的渲染中。 LOD Crysis为了支撑8公里乘8公里的超大视距（由于Crysis中的网格Size是2米一格，一块地形拥有多达4096*4096个网格），在最高精度下，总共三千二百万个三角形。因此必须有一套合理的地形LOD方案。 Crysis的地形LOD，从地形LOD算法的分类上看，是基于Geo-Mipmapping的。不过相比最传统的Geo-Mipmapping，Crysis利用四叉树的特性，并且考虑到最新图形硬件的特点，针对地形网格做了相当多的优化。 首先解释一下Geo-Mipmapping的基本思想： Geo-Mipmapping始于Willem H. de [...]]]></description>
			<content:encoded><![CDATA[<h4>材质</h4>
<p>Crysis地形的一个最重要的特色是它的地表材质系统。当进入到一定距离之后，可以看到非常精细的地表材质，包括Bump Mapping，Parallax Occlusion Mapping，有了材质系统的支持，Crysis的地形相较基于传统的Texture Splatting的地形可以呈现出令人惊叹的细节。</p>
<p>在POM技术支撑下的Crysis地形：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image002.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image002" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image002_thumb.jpg" alt="clip_image002" width="651" height="322" border="0" /></a></p>
<p>基于Texture Splatting技术的地形：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image004.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image004" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image004_thumb.jpg" alt="clip_image004" width="650" height="416" border="0" /></a></p>
<p>Crysis的地表材质技术的原理如下：</p>
<p>渲染包括两个步骤，首先基于颜色图和法线图，绘制基本的地形色彩与明暗，这一遍渲染结果主要用于远处地形。然后会针对不同材质，将细节通过AlphaBlend融合到之前的渲染结果上，材质细节通常只在离视野较近的区域内才渲染，因此第二个步骤的耗费并不多，根据实际情况，每帧中大约会有从一百到数百个不等的细节层Mesh被绘制。<span id="more-314"></span></p>
<p>第一遍基于颜色图渲染的效果如下：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image006.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image006" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image006_thumb.jpg" alt="clip_image006" width="647" height="342" border="0" /></a></p>
<p>可以看到，颜色图上提供了明暗细节，这对地形渲染中无处不在的Tiling问题起到了缓解作用。</p>
<p>第二遍Blend上细节之后的效果：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image008.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image008" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image008_thumb.jpg" alt="clip_image008" width="651" height="336" border="0" /></a></p>
<p>Crysis为每个顶点赋予一个材质id，并且根据不同的材质id，将原先完整的地形网格划分成按材质组织的小块网格，（如果整块32×32的网格都是同一种材质，则无需划分），小块网格是通过索引区段的方式定义的。在Crysis中，地形顶点数据结构里Color属性的g分量被用了作材质层的ID。</p>
<p>下图展示了一个网格中的33×33个顶点被区分为两种材质的情况。本图为演示，将顶点颜色涂成不同的颜色，Crysis则是将将材质id通过顶点颜色传入vs。下面的网格中存在两种不同的材质需要分别渲染。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image010.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image010" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image010_thumb.jpg" alt="clip_image010" width="507" height="398" border="0" /></a></p>
<p>Crysis根据顶点材质id将整块Mesh拆分成以材质id分组的小块Mesh，如图：</p>
<p>不同材质的Mesh之间，有一个三角形的过渡带。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image012.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image012" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image012_thumb.jpg" alt="clip_image012" width="643" height="361" border="0" /></a></p>
<p>上图中，红色箭头表示草的材质从1过渡到0，蓝色箭头表示沙子材质从1过渡到0。</p>
<p>这个过渡带起到的作用正是让一个处于材质交汇带的三角形，其Alpha可以从1过渡到0。这样和相邻的隶属另一个材质正好融合到一起。</p>
<p>因此，材质过渡区域的三角形会被渲染2到3遍，取决于该三角形的三个顶点分属于2个材质还是3个材质。</p>
<p>上述的融合过程是通过下面这段代码做到的（本文只为解释原理，与真实代码有出入，Crysis的Shader代码没有加密，有心人可自己解包查阅）：</p>
<p>声明常量：</p>
<p>float g_InputLayerId;</p>
<p>该常量通过程序传入VS常量中，表示当前渲染Mesh的LayerId。</p>
<p>在vs中计算顶点alpha：</p>
<p>float alpha = 1- saturate (g_InputLayerId – Input.Color.g * 255.0f);</p>
<p>Input.Color.g中存储的是该顶点所属的LayerId，由于是通过COLOR存储，取值范围是从0.0到1.0，因此在shader里用于计算之前，还需要乘以255.0f还原。</p>
<p>上式的逻辑如下：</p>
<p>如果InputLayerId和当前顶点存储的layerId相同，则alpha为1，否则，如g_InputLayerId与当前顶点上的layerId不同，则alpha为0。</p>
<p>因为可以使用不同材质做细节层的渲染，Bump Mapping，Parallax Occlusion Mapping这类技术对于地表细节的表现提升极为明显。除了Bump Map之外，Crysis还将Detail Bump Map，Specular Map等用于提升材质细节的技术纳入到地形细节层的渲染中。</p>
<h4>LOD</h4>
<p>Crysis为了支撑8公里乘8公里的超大视距（由于Crysis中的网格Size是2米一格，一块地形拥有多达4096*4096个网格），在最高精度下，总共三千二百万个三角形。因此必须有一套合理的地形LOD方案。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image014.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image014" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image014_thumb.jpg" alt="clip_image014" width="651" height="416" border="0" /></a></p>
<p>Crysis的地形LOD，从地形LOD算法的分类上看，是基于<a href="http://www.flipcode.com/archives/Fast_Terrain_Rendering_Using_Geometrical_MipMapping.shtml">Geo-Mipmapping</a>的。不过相比最传统的Geo-Mipmapping，Crysis利用四叉树的特性，并且考虑到最新图形硬件的特点，针对地形网格做了相当多的优化。</p>
<p>首先解释一下Geo-Mipmapping的基本思想：</p>
<p>Geo-Mipmapping始于<a href="mailto:whdeboer@iname.com">Willem H. de Boer</a>的论文<a href="http://www.flipcode.com/tutorials/tut_geomipmaps.shtml">Fast Terrain Rendering Using Geometrical MipMapping</a> (2000)。</p>
<p>与近处的地形相比，离摄像机远的Block不必采用同样的细节的网格，我们可以采用一个更低精度的版本来近似。通过减少三角形的数量，获得渲染效率上的提升。</p>
<p>考虑传统意义上的纹理MipMapping技术。对每张纹理，都会创建一条mipmap链，链中的第一级贴图就是实际的纹理，而后的每一级都是将上一级的分辨率缩小一半得到的。当贴图距摄像机一定距离的时候，mipmap链中的合适的层级会被选择出来用于渲染，而不是选择最高分辨率的纹理。我们也可以将同样的原理应用到三维网格中，在地形中，等价于纹理的就是地形Block，地形Block的mipmap链则由最高分辨率版本的Block通过缩小分辨率获得。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image016.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image016" src="http://www.windameister.org/blog/wp-content/uploads/2011/11/clip_image016_thumb.jpg" alt="clip_image016" width="383" height="356" border="0" /></a></p>
<p>如上图：（图来自于<a href="http://www.flipcode.com/archives/article_geomipmaps.pdf">这里</a>）</p>
<p>白色的点位MipMap Level 0，黑点为MipMap Level 1，依次类推。</p>
<p>传统的GeoMipMapping技术就是采用上述方案，例如对一个32×32格子的原始网格依次创建16×16，8×8格子的MipMap链。随着地形Block到摄像机距离的增加，逐渐采用越来越稀疏的版本。</p>
<p>Crysis的地形LOD的基础就是基于上述思想——其实这是废话，基本上大多数的地形LOD算法都是基于这个思想。</p>
<p>所不同的是，Crysis利用四叉树结构对GeoMipMapping做了优化。</p>
<p>Crysis渲染的基本单位是32×32的网格。也就是说，一次draw call最多向图形管线传递32×32×2个三角形。</p>
<p><strong>随着距离增加，32*32</strong><strong>的网格会降级成16*16</strong><strong>，如果四个紧挨着的Block</strong><strong>都变成16</strong><strong>×16</strong><strong>，且这四个Block</strong><strong>都是同一个父节点的子，则会合并成一个LOD</strong><strong>级别更高的32</strong><strong>×32</strong><strong>的网格。</strong></p>
<p>换一个角度看，把地形Mesh看成一棵四叉树，处于叶节点的Block拥有最高精度网格，每向上一层，精度都会缩减一半（总的分辨率变成之前的一半）。</p>
<p>这样假设叶节点层（第0层）的Mesh是一个1025*1025个网格，那么第1层就是513*513的网格，第2层257*257，第3层129*129，第4层65*65，第5层33*33。</p>
<p>如果我们选择第5层进行渲染，只需要一次Draw Call就可以将整个Mesh绘制完毕，当然在精度上也会有很大损失。因此，可以这样考虑，从根节点开始遍历，如果当前节点距离摄像机的距离很近，以至于该节点自身的细节不足够精确，并且该节点还有子节点，则我们将该节点的四个子节点而非该节点本身置入渲染队列，否则意味着该节点的细节就足以应付需求，因此可以只渲染该节点。</p>
<p>上述方式由于为整个Mesh创建了一个MipMap链，因此会增加33%的冗余顶点数据，但是利用这个原理，Crysis成功将4096×4096的地形DrawCall次数降低到了300～500次。这便是Crysis能够高效渲染超大视距地形的原理。</p>
<p>&nbsp;</p>
<p>最后谈谈针对GPU的优化：</p>
<p>现代GPU的特点是有大量的流处理器，支持高并发的运算量，顶点计算也好，像素计算也好，都是可以高度并行化的，现代GPU针对这些做了大量的工作。</p>
<p>GPU的显存越做越大，1GB的显存已经是小儿科，动辄2GB，甚至更多的显存也能在市场上见到。</p>
<p>也就是说，随着GPU的发展，运算和存储都逐渐不再是瓶颈——那么相比之下，通过PCIE总线把数据从CPU传输到显卡则成了一个制约性能的瓶颈所在了。</p>
<p>以往我们习惯于每帧Lock一个Buffer，然后通过CPU动态填充数据到Buffer里，再把这个Buffer提交到Device上去用于渲染。这种做法就会导致每帧都要传递大量的数据到显卡上去。相比之下，现代GPU的结构更倾向于让我们进行这样的渲染：在初始化阶段就将数据创建成静态的Buffer并存放于显存里，每帧渲染都利用这些现有的Buffer。</p>
<p>针对地形来说，顶点数据很好说，因为本来就不会在运行期进行修改，因此可以直接创建成静态的Buffer，而索引数据往往会引发疑惑，因为LOD时时刻刻都在变化。地形LOD因为每帧要动态更新Block的LOD状态（包括自身的LOD级别以及和相邻Block之间的接缝），因此不得不去每帧Lock索引的Buffer，动态填充。</p>
<p>但如果仔细想想，就会发现索引也是可以预计算的。（Crysis就采用了预算好的索引Buffer）</p>
<p>考虑一个32×32的网格，它的索引大小为32*32*2(三角形) * 3(索引)* 2(sizeof(WORD))= 12KB</p>
<p>考虑周围邻接Block的LOD级别高于它的情况，每条邻接边都可能是[16, 8, 4, 2, 1]个Grid，也就是有5种情况，一共有4个邻接边。这样总的数据量是：5* 5* 5 * 5 * 12KB 约等于 7.32 MB。这是我们允许跨5级LOD的极端情况，在Crysis中我没有观察到跨5级LOD的情况，而如果我们只允许跨3级LOD，也就是对于32*32的Block的邻接Block只允许[16, 8, 4]三种情况，则总的数据量约为 3 * 3 * 3 * 3 * 12KB = 972KB。</p>
<p>如果每个Block内部允许存在3级LOD，也就是[32*32, 16*16, 8*8]三种，其中16* 16的网格，其索引数据占用空间为32*32的1/4，即3KB，8*8网格的索引数据则不到1KB。</p>
<p>也就是说，即便允许Block内部3级LOD，同时允许每个Block与邻接Block跨3级LOD级别，总的索引数据量也不过在1.5MB左右。完全可以预计算好然后存在显存里。</p>
<p>在渲染当中，当Block的LOD级别被确定下来的时候，根据Block的内部LOD级别以及该Block与邻接Block的LOD差作为索引，就可以查找到需要的IndexBuffer了。</p>
<p>===分割线===</p>
<p>由于没有CryEngine的代码，分析所依赖的手段只有PIX抓帧和PerfHud，以及CryEngine的Shader，所以本文中所述的观点仅供参考，欢迎讨论。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2011/11/04/crysis-terrain-render-tech-anaylsis-material-and-lod/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>关于地形渲染技术的杂谈</title>
		<link>http://www.windameister.org/blog/2011/08/28/some-tech-topics-on-terrain-rendering/</link>
		<comments>http://www.windameister.org/blog/2011/08/28/some-tech-topics-on-terrain-rendering/#comments</comments>
		<pubDate>Sun, 28 Aug 2011 14:28:31 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[3D渲染]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[LOD]]></category>
		<category><![CDATA[Virtual Texture]]></category>
		<category><![CDATA[地形渲染]]></category>
		<category><![CDATA[材质]]></category>
		<category><![CDATA[阴影]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2011/08/28/%e5%85%b3%e4%ba%8e%e5%9c%b0%e5%bd%a2%e6%b8%b2%e6%9f%93%e6%8a%80%e6%9c%af%e7%9a%84%e6%9d%82%e8%b0%88/</guid>
		<description><![CDATA[地形是3D游戏中不可或缺的基础部分，特别是对于要表现室外场景的游戏来说。随着图形硬件的发展，地形渲染技术也经历了若干变迁。主要包括几个方面：LOD，光照和阴影，材质表现。由于本人的时间精力有限不可能面面俱到，所以只能是浅谈辄止，粗浅的叙述一下相关的技术和一些思考，欢迎交流指正。 关于LOD 早些年，由于图形硬件的瓶颈在于顶点和三角形处理上，因此发展出一批目的在于尽可能减少顶点和三角形数量的算法，如ROAM。后来随着显卡性能的提升，渲染效率的瓶颈逐渐变成了总线上的数据传输速率，地形渲染随之演变成尽可能将预计算好的数据存储于显卡上，从而避免每帧传递数据，如Geo-Mipmapping。还有后续的算法在此基础上继续改进，如Chunked LOD。 除此之外，地形LOD算法还需要处理的问题包括如何消除LOD级别改变时发生的视觉上的突变。一种常见的方法就是通过Morphing。不过不知是出于效率还是工程上的考虑，Crysis的地形上并没有做morphing。 再后来，随着Shader Model 3.0中增加了Vertex Texture访问以及对Instancing的支持，地形渲染技术则有了更多的选择，例如通过VertexTexture技术，可以在VertexShader中算顶点，而Instancing技术更进一步减少了数据传输量，进一步简化了CPU端的计算和数据传输。 参考：CDLOD，这个作者正在基于DX11实现他的下一个版本的CDLOD，将会包含下面要说的Tessellation技术。 到了DX11，新引入的Tessellation技术则让引擎开发者拥有了将整个地形渲染完全搬到显卡上去做的能力。如果说SM3.0中我们只是在硬件上动态生成所需的地形顶点，那么到了DX11中，我们就可以在硬件上实现LOD了，我们可以GPU上决定每个Patch应该有多细密的网格，并且在GPU上处理好和邻接Patch的接缝问题。关于这个话题可以参考GPU Pro2中的Terrain And Ocean Rending with Hardware Tessellation。 这意味着到DX11普及的时候，以往的那些在用于CPU端计算LOD索引的很多算法，都不再被需要了。当然，上述算法中产生的核心思想仍然会继续起作用——例如利用四叉树做地形的数据管理，例如如何在LOD改变时避免视觉上看到跳变等等。 p.s.有时候难免对于国内的Win7普及率感到无奈…… 关于光照和阴影 由于地形是一种静态的模型，不会移动，相对光源的位置是不变的，因此实时渲染地形的时候，很流行的方法是采用LightMap对地形光影做预计算，而传统意义上的光照计算，则往往是在vs阶段（这里指顶点光照，若是逐像素光照，则是在ps阶段）实时进行。 由于LightMap省却了实时进行光照计算的计算量，在效率上有所提升，并且一些对计算量要求较高的技术如全局光照，如果采用实时计算会导致性能急剧下降，因此在实际中往往也是预计算并存储于LightMap中。 另一方面，LightMap不便存储动态的光照信息，当光源的角度，颜色发生改变，LightMap就需要随之更新。而这在实时游戏中往往很难做到。 目前主流的实时阴影技术基本都是基于ShadowMap的，在Doom3中使用的Shadow Volume，现在已经很少看到了。 ShadowMap的基本原理是从光源的位置和朝向绘制一张场景的深度图，成为ShadowMap，然后再在实际渲染场景的时候，将每个像素的位置到光源的距离和ShadowMap中的深度值进行比较，如果发现该像素的深度小于ShadowMap中对应位置像素的深度，则不在阴影中，反之，则在阴影中。 ShadowMap的好处在于可以方便的实现很多个物体的阴影，物体的自阴影。 但是也有几个问题： １. 边缘会出现难看的锯齿状走样，一方面因为像素的含义是深度，因此相邻像素的值是跳变的，可能一个值为7，邻接的就是200，你无法对深度做过滤；另一方面和ShadowMap的大小有关，同一个场景，使用的ShadowMap的Size越小，越会出现较大的锯齿。 ２. 如上所述，由于存储的是深度，因此ShadowMap难以判断一个像素是否处在阴影边缘中，难以给出柔和的半影过度 ３. ShadowMap只适合于平行光和SpotLight，对于点光源需要计算多达６张ShadowMap（利用DPSM可以减少到2张） 为了解决ShadowMap局限，有很多方法被发明出来，例如，采用PCF获取软边缘，不过PCF需要多次自行采样纹理，效率上有损失，另一方面PCF不是真的计算软阴影，而是通过采样的手段去找出边缘，所以无法根据距离远近产生真实的半影过度。 还有种方法是VSM（方差阴影贴图），其原理是通过车比雪夫不等式(Chebyshev)去计算一个像素在阴影中的概率： 公式来自于Variance Shadow Maps by William Donnelly_ Andrew Lauritzen† 具体来说，它在渲染深度的时候同时存储深度和深度的平方（不同的颜色通道中），然后对ShadowMap做过滤，这样得到的就逐像素的深度的期望μ和深度平方的期望，利用这两个值可以求得方差σ，然后再用车比雪夫不等式计算概率。（具体原理及实现可参考 vsm） 关于材质表现 传统的地形表现比较常见的是用多层纹理混合，也称为Texture splatting。 （图片来自Wikipedia） 这种做法可以实现多种贴图之间的混合过度。优点是实现简单，而且贴图通过反复Tiling即可构成整个地形表面，从而节省了纹理资源。 缺点则是，如果美术稍微偷点懒，就可以看到大片大片的Tiling，重复感非常明显。以魔兽世界为代表的一大批游戏引擎用的都是Texture splatting来表现地表纹理。 在Crysis中有一个在表现效果上和效率上结合得非常完美的材质系统，Crysis为了给地表提供尽可能丰富的细节，支持给顶点赋材质，这样就能够支持地表的Bump [...]]]></description>
			<content:encoded><![CDATA[<p>地形是3D游戏中不可或缺的基础部分，特别是对于要表现室外场景的游戏来说。随着图形硬件的发展，地形渲染技术也经历了若干变迁。主要包括几个方面：LOD，光照和阴影，材质表现。由于本人的时间精力有限不可能面面俱到，所以只能是浅谈辄止，粗浅的叙述一下相关的技术和一些思考，欢迎交流指正。</p>
<h4>关于LOD</h4>
<p>早些年，由于图形硬件的瓶颈在于顶点和三角形处理上，因此发展出一批目的在于尽可能减少顶点和三角形数量的算法，如<a href="https://graphics.llnl.gov/ROAM/">ROAM</a>。后来随着显卡性能的提升，渲染效率的瓶颈逐渐变成了总线上的数据传输速率，地形渲染随之演变成尽可能将预计算好的数据存储于显卡上，从而避免每帧传递数据，如<a href="http://www.flipcode.com/archives/Fast_Terrain_Rendering_Using_Geometrical_MipMapping.shtml">Geo-Mipmapping</a>。还有后续的算法在此基础上继续改进，如<a href="http://tulrich.com/geekstuff/chunklod.html">Chunked LOD</a>。</p>
<p>除此之外，地形LOD算法还需要处理的问题包括如何消除LOD级别改变时发生的视觉上的突变。一种常见的方法就是通过<a href="http://www.google.com.hk/search?hl=zh-CN&amp;newwindow=1&amp;safe=strict&amp;biw=1920&amp;bih=932&amp;q=terrain+Morphing&amp;oq=terrain+Morphing&amp;aq=f&amp;aqi=&amp;aql=&amp;gs_sm=e&amp;gs_upl=61681l63742l0l63882l11l7l0l0l0l0l0l0ll0l0">Morphing</a>。不过不知是出于效率还是工程上的考虑，Crysis的地形上并没有做morphing。</p>
<p>再后来，随着Shader Model 3.0中增加了<a href="http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter18.html">Vertex Texture</a>访问以及对Instancing的支持，地形渲染技术则有了更多的选择，例如通过VertexTexture技术，可以在VertexShader中算顶点，而Instancing技术更进一步减少了数据传输量，进一步简化了CPU端的计算和数据传输。</p>
<p>参考：<a href="http://vertexasylum.com/2010/07/11/oh-no-another-terrain-rendering-paper/">CDLOD</a>，这个作者正在基于DX11实现他的下一个版本的CDLOD，将会包含下面要说的Tessellation技术。</p>
<p>到了DX11，新引入的Tessellation技术则让引擎开发者拥有了将整个地形渲染完全搬到显卡上去做的能力。如果说SM3.0中我们只是在硬件上动态生成所需的地形顶点，那么到了DX11中，我们就可以在硬件上实现LOD了，我们可以GPU上决定每个Patch应该有多细密的网格，并且在GPU上处理好和邻接Patch的接缝问题。关于这个话题可以参考<a href="http://book.douban.com/subject/6064395/">GPU Pro2</a>中的Terrain And Ocean Rending with Hardware Tessellation。</p>
<p>这意味着到DX11普及的时候，以往的那些在用于CPU端计算LOD索引的很多算法，都不再被需要了。当然，上述算法中产生的核心思想仍然会继续起作用——例如利用四叉树做地形的数据管理，例如如何在LOD改变时避免视觉上看到跳变等等。<span id="more-289"></span></p>
<p>p.s.有时候难免对于国内的Win7普及率感到无奈……</p>
<h4>关于光照和阴影</h4>
<p>由于地形是一种静态的模型，不会移动，相对光源的位置是不变的，因此实时渲染地形的时候，很流行的方法是采用LightMap对地形光影做预计算，而传统意义上的光照计算，则往往是在vs阶段（这里指顶点光照，若是逐像素光照，则是在ps阶段）实时进行。</p>
<p>由于LightMap省却了实时进行光照计算的计算量，在效率上有所提升，并且一些对计算量要求较高的技术如全局光照，如果采用实时计算会导致性能急剧下降，因此在实际中往往也是预计算并存储于LightMap中。</p>
<p>另一方面，LightMap不便存储动态的光照信息，当光源的角度，颜色发生改变，LightMap就需要随之更新。而这在实时游戏中往往很难做到。</p>
<p>目前主流的实时阴影技术基本都是基于ShadowMap的，在Doom3中使用的<a href="http://en.wikipedia.org/wiki/Shadow_volume">Shadow Volume</a>，现在已经很少看到了。</p>
<p>ShadowMap的基本原理是从光源的位置和朝向绘制一张场景的深度图，成为ShadowMap，然后再在实际渲染场景的时候，将每个像素的位置到光源的距离和ShadowMap中的深度值进行比较，如果发现该像素的深度小于ShadowMap中对应位置像素的深度，则不在阴影中，反之，则在阴影中。</p>
<p>ShadowMap的好处在于可以方便的实现很多个物体的阴影，物体的自阴影。</p>
<p>但是也有几个问题：</p>
<p>１. 边缘会出现难看的锯齿状走样，一方面因为像素的含义是深度，因此相邻像素的值是跳变的，可能一个值为7，邻接的就是200，你无法对深度做过滤；另一方面和ShadowMap的大小有关，同一个场景，使用的ShadowMap的Size越小，越会出现较大的锯齿。</p>
<p>２. 如上所述，由于存储的是深度，因此ShadowMap难以判断一个像素是否处在阴影边缘中，难以给出柔和的半影过度</p>
<p>３. ShadowMap只适合于平行光和SpotLight，对于点光源需要计算多达６张ShadowMap（利用<a href="http://www.google.com.hk/search?hl=zh-CN&amp;newwindow=1&amp;safe=strict&amp;biw=1920&amp;bih=896&amp;q=DualParaboloidMappingInTheVertexShader&amp;oq=DualParaboloidMappingInTheVertexShader&amp;aq=f&amp;aqi=&amp;aql=&amp;gs_sm=s&amp;gs_upl=34108l34108l0l34862l1l1l0l0l0l0l0l0ll0l0">DPSM</a>可以减少到2张）</p>
<p>为了解决ShadowMap局限，有很多方法被发明出来，例如，采用PCF获取软边缘，不过PCF需要多次自行采样纹理，效率上有损失，另一方面PCF不是真的计算软阴影，而是通过采样的手段去找出边缘，所以无法根据距离远近产生真实的半影过度。</p>
<p>还有种方法是VSM（方差阴影贴图），其原理是通过车比雪夫不等式(Chebyshev)去计算一个像素在阴影中的概率：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image002.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image002" src="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image002_thumb.jpg" alt="clip_image002" width="244" height="64" border="0" /></a></p>
<p>公式来自于Variance Shadow Maps by William Donnelly_ Andrew Lauritzen†</p>
<p>具体来说，它在渲染深度的时候同时存储深度和深度的平方（不同的颜色通道中），然后对ShadowMap做过滤，这样得到的就逐像素的深度的期望μ和深度平方的期望，利用这两个值可以求得方差σ，然后再用车比雪夫不等式计算概率。（具体原理及实现可参考 <a href="http://www.punkuser.net/vsm/">vsm</a>）</p>
<h4>关于材质表现</h4>
<p>传统的地形表现比较常见的是用多层纹理混合，也称为<a href="http://en.wikipedia.org/wiki/Texture_splatting">Texture splatting</a>。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image004.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image004" src="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image004_thumb.gif" alt="clip_image004" width="244" height="191" border="0" /></a> （图片来自Wikipedia）</p>
<p>这种做法可以实现多种贴图之间的混合过度。优点是实现简单，而且贴图通过反复Tiling即可构成整个地形表面，从而节省了纹理资源。</p>
<p>缺点则是，如果美术稍微偷点懒，就可以看到大片大片的Tiling，重复感非常明显。以魔兽世界为代表的一大批游戏引擎用的都是Texture splatting来表现地表纹理。</p>
<p>在Crysis中有一个在表现效果上和效率上结合得非常完美的材质系统，Crysis为了给地表提供尽可能丰富的细节，支持给顶点赋材质，这样就能够支持地表的<a href="http://en.wikipedia.org/wiki/Bump_mapping">Bump Mapping</a>以及更高级的<a href="http://en.wikipedia.org/wiki/Parallax_occlusion_mapping">POM</a>。而传统的Texture splatting在混合时不去区分实际的材质，是不可能做到这一点的。当离远之后，Crysis就不再渲染细节纹理的pass，而是只渲染地表颜色图。</p>
<p>来一张Crysis的炫技图（图片来自互联网）：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image006.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image006" src="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image006_thumb.jpg" alt="clip_image006" width="244" height="153" border="0" /></a></p>
<p>接下来，为了引出Virtual Texturing，先介绍下Clipmap。</p>
<p>在类似GoogleEarth之类的地图软件中可能使用了一种类似于<a href="http://www.cs.virginia.edu/~gfx/Courses/2002/BigData/papers/Texturing/Clipmap.pdf">Clipmap</a>的技术，这种技术基于mipmap，同时又对之作了扩展。</p>
<p>传统的Mipmap是从一张贴图原始的Size开始直到Size为1有一个完整的Mipmap链，比如一张1024×1024的贴图，会有从512×512直到1×1的全部的mipmap版本，同时存在于显卡中，到了纹理采样的时候根据mip级别采样不同的纹理。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image008.jpg"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image008" src="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image008_thumb.jpg" alt="clip_image008" width="244" height="116" border="0" /></a></p>
<p>图片来自<a href="http://www.cs.virginia.edu/~gfx/Courses/2002/BigData/papers/Texturing/Clipmap.pdf">The Clipmap: A Virtual Mipmap</a></p>
<p>而Clipmap中的贴图可能很大，比如64000×64000，这样就不可能把它和它的完整的mipmap链放到显卡里去了，所以他只放最低级别的那些Mipmap到显卡里，超出显卡能力的部分也放，但是只放一部分（需要的），就好象是Clip过了一样，所以叫Clipmap （= =）如图：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image010.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="clip_image010" src="http://www.windameister.org/blog/wp-content/uploads/2011/08/clip_image010_thumb.jpg" alt="clip_image010" width="244" height="92" border="0" /></a></p>
<p>虽然我们无法把整个贴图完全加载到显卡上，但是我们观察到足够清晰细节的距离不可能太远，离远了就切到下一个mip级别，所以随着到视点距离的增加，从最高精度到最低精度有一个逐渐的变化过程。所以这种做法是可行的。</p>
<p>很多人把Clipmap和Virtual Texture搞混了。其实这是两个完全不同的技术。虽然在对Mipmap的使用方面有类似的地方。</p>
<p>我觉得未来的趋势应该是把地形和模型的贴图都统一纳入到<a href="http://en.wikipedia.org/wiki/MegaTexture">Virtual Texture</a>中管理，这个技术是由卡马克在id tech 5中引入的。在Id Tech5中，通过Virtual Texture技术可以制作没有任何重复感的地表（Virtual Texture也支持模型贴图），从此再也不愁Tiling的问题——只不过可能就得苦了美术和编辑器制作人员了，而且Virtual Texture技术存在许多在制作流程上需要克服的问题。</p>
<p>Virtual Texture说白了就是一张巨大无比的大纹理，可能有1024000 * 1024000这么大，存储在磁盘上。但是到游戏中，只加载实际需要的就可以——实际需要一方面是指mip level上的需要，远处的只需要低精度的纹理，近处才需要高精度，另一方面是指不需要加载那些不进入可视范围内的纹理（看不到的）。</p>
<p>Virtual Texture技术实际上借鉴了计算机中的Virtual Memory的理念。我们知道早期的计算机物理内存没有4GB，但是应用程序却可以通过32位指针访问到整个4GB的地址空间，好像这么大的内存都可以访问一样，但是实际的物理内存可能很小，只有512MB，这是怎么做到的呢？</p>
<p>操作系统把内存按页进行管理，每个页4KB大，并且只把应用程序需要访问的内存页放到到实际的物理内存中，如果应用程序访问一块内存，而这块内存又不在物理内存中存在，那么应用程序会暂停执行，操作系统执行换入操作，并把应用程序需要的内存页拿到物理内存里，然后再把执行权交回给应用程序，当然这一切对于应用程序的开发者来说都是透明的。</p>
<p>虚拟纹理（<a href="http://en.wikipedia.org/wiki/MegaTexture">Virtual Texture</a>）也是采用类似的方案，实际的Physical Texture（想像成对应于物理内存的实际纹理）可能只有4096 * 4096这么大（根据实际显卡的支持程度决定），但是3D游戏中各物体的uv坐标则可以寻址远超出这个物理纹理范围的大纹理，因此virtual texture也需要把物理纹理分页，比如切成256×256的小块纹理，并且根据实际需要进行换入换出操作。这里一共存在从硬盘到内存，再从内存到显卡的三级缓存，这个过程中有许多复杂的地方要处理，比如怎么知道应该加载什么mip级别的贴图，怎么知道应该加载那块贴图等等。基本的思路是通过预先渲染一个pass，将需要加载的mip级别和具体的页面索引算出来。</p>
<p>Virtual Texture目前网上已经有了开源的实现，感兴趣的朋友可以参考下 <a href="http://silverspaceship.com/src/svt/">Sparse Virtual Texture</a>，<a href="http://forum.beyond3d.com/showthread.php?t=55594">这里</a>，还有<a href="http://s09.idav.ucdavis.edu/talks/05-JP_id_Tech_5_Challenges.pdf">id Tech5的介绍</a>，<a href="http://crytek.com/cryengine/presentations/advanced-virtual-texture-topics">CryEngine对Virtual Texture的看法</a>。</p>
<p>本文中提到的技术，在实际的实现中都要解决各种实现上或者工程上的问题，不可能如我在这里夸夸其谈这样简单，所以本文只能是简述下基本思想，算是对近期一段时间的学习做个整理。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2011/08/28/some-tech-topics-on-terrain-rendering/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>自动构建二：CruiseControl.NET配置基础</title>
		<link>http://www.windameister.org/blog/2011/06/12/autobuild_basics_on_cruisecontrol_net_cofiguration/</link>
		<comments>http://www.windameister.org/blog/2011/06/12/autobuild_basics_on_cruisecontrol_net_cofiguration/#comments</comments>
		<pubDate>Sun, 12 Jun 2011 08:24:56 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[Windows平台开发]]></category>
		<category><![CDATA[自动构建]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2011/06/12/%e8%87%aa%e5%8a%a8%e6%9e%84%e5%bb%ba%e4%ba%8c%ef%bc%9acruisecontrol-net%e9%85%8d%e7%bd%ae%e5%9f%ba%e7%a1%80/</guid>
		<description><![CDATA[在软件工程领域，CruiseControl是一个基于Java的持续集成框架。它包含了大量与持续集成有关的功能，如：邮件通知，Ant自动构建，以及支持多种源码管理工具。可以利用Web页面观察当前和以往的构建流程。它允许我们对软件开发中的很多流程进行持续的自动化控制。 CruiseControl是一个自由，开源软件，使用BSD类型的license。最早的时候，该软件是由ThoughtWorks公司的员工开发出来用于该公司自身内部项目的，随后则变成了一个独立的应用软件。 CruiseControl.NET是CruiseControl的.NET版本。还有一个Ruby版本的CruiseControl，被称为CruiseControl.rb。 对于使用Windows平台，以及Visual Studio集成开发环境的团队来说，使用CruiseControl.NET的好处在于他整合了MSBuild，NAnt，VSS等微软平台下常用的软件开发中的工具，并且非常易于在.NET平台下对他的功能进行扩展。 我们可以利用MSBuild来编写构建脚本，利用CruiseControl.NET配置实现持续集成，每日构建，自动化测试，邮件通知等功能。 安装CruiseControl.NET需要先安装.NET Framework 2.0以及支持ASP.NET的Web server（比较典型的如开启了ASP.NET的IIS服务器） CruiseControl.NET提供了两种查看和管理构建流程的方式： 1. 通过Web Dashboard，也就是通过网页查看 2. 通过CCTray客户端（该客户端是一个常驻程序，可以随时点开查看当前的构建状况，并且可以在构建成功或失败后弹出提示） 安装CruiseControl.NET 从ThoughtWorks的网站下载当前最新的Release版本： http://confluence.public.thoughtworks.org/display/CCNET/Download 在服务器上安装该CCNet安装程序（服务器需要是Windows的，并且有.NET2.0运行环境与支持ASP.NET的WebServer） 配置CruiseControl.NET： 安装目录下有名为ccnet.config的xml格式的配置文件，用于配置当前的CCNet服务器。 对于一个比较简单的项目，我们的持续集成需求包括： 1. 从源代码管理服务器上取下最新的源码 2. 构建 3. 构建成功后，将文件发布到我们指定的目录 我们还可能会需要每日构建，每天夜里0:00开始一次所有项目的构建，并将结果发布到指定位置。 项目之间往往存在互相依赖，如果被依赖项发生了更改，应该有办法让所有依赖了该项目的项目都依次构建。 下面以一个简单的例子描述如何配置CruiseControl.net服务器。 打开ccnet.config文件，该文件是一个xml格式的文件，可以在配置文件中编写多个project，每个project都对应着一个&#60;project&#62; &#60;/project&#62;块。 &#60;cruisecontrol&#62; &#60;project name=”MyProj1”&#62; &#60;/project&#62; &#60;project name=”MyProj2”&#62; &#60;/project&#62; &#60;/cruisecontrol&#62; 每个Project块的配置类似下面的例子： &#60;project name=&#8221;Project 1&#8243; queue=&#8221;Q1&#8243; queuePriority=&#8221;1&#8243;&#62; &#60;workingDirectory&#62;yourWorkingDirectory&#60;/workingDirectory&#62; &#60;artifactDirectory&#62;yourArtifactDirectory&#60;/artifactDirectory&#62; &#60;category&#62;Category 1&#60;/category&#62; &#60;webURL&#62;http://server1/ccnet/server/local/project/testProject/ViewLatestBuildReport.aspx&#60;/webURL&#62; &#60;modificationDelaySeconds&#62;2&#60;/modificationDelaySeconds&#62; &#60;maxSourceControlRetries&#62;5&#60;/maxSourceControlRetries&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>在软件工程领域，CruiseControl是一个基于Java的持续集成框架。它包含了大量与持续集成有关的功能，如：邮件通知，Ant自动构建，以及支持多种源码管理工具。可以利用Web页面观察当前和以往的构建流程。它允许我们对软件开发中的很多流程进行持续的自动化控制。</p>
<p>CruiseControl是一个自由，开源软件，使用BSD类型的license。最早的时候，该软件是由ThoughtWorks公司的员工开发出来用于该公司自身内部项目的，随后则变成了一个独立的应用软件。</p>
<p>CruiseControl.NET是CruiseControl的.NET版本。还有一个Ruby版本的CruiseControl，被称为CruiseControl.rb。</p>
<p>对于使用Windows平台，以及Visual Studio集成开发环境的团队来说，使用CruiseControl.NET的好处在于他整合了MSBuild，NAnt，VSS等微软平台下常用的软件开发中的工具，并且非常易于在.NET平台下对他的功能进行扩展。</p>
<p><span id="more-272"></span></p>
<p>我们可以利用MSBuild来编写构建脚本，利用CruiseControl.NET配置实现持续集成，每日构建，自动化测试，邮件通知等功能。</p>
<p>安装CruiseControl.NET需要先安装.NET Framework 2.0以及支持ASP.NET的Web server（比较典型的如开启了ASP.NET的IIS服务器）</p>
<p>CruiseControl.NET提供了两种查看和管理构建流程的方式：</p>
<p>1. 通过Web Dashboard，也就是通过网页查看</p>
<p>2. 通过CCTray客户端（该客户端是一个常驻程序，可以随时点开查看当前的构建状况，并且可以在构建成功或失败后弹出提示）</p>
<p>安装CruiseControl.NET</p>
<p>从ThoughtWorks的网站下载当前最新的Release版本：</p>
<p><a href="http://confluence.public.thoughtworks.org/display/CCNET/Download">http://confluence.public.thoughtworks.org/display/CCNET/Download</a></p>
<p>在服务器上安装该CCNet安装程序（服务器需要是Windows的，并且有.NET2.0运行环境与支持ASP.NET的WebServer）</p>
<p>配置CruiseControl.NET：</p>
<p>安装目录下有名为ccnet.config的xml格式的配置文件，用于配置当前的CCNet服务器。</p>
<p>对于一个比较简单的项目，我们的持续集成需求包括：</p>
<p>1. 从源代码管理服务器上取下最新的源码</p>
<p>2. 构建</p>
<p>3. 构建成功后，将文件发布到我们指定的目录</p>
<p>我们还可能会需要每日构建，每天夜里0:00开始一次所有项目的构建，并将结果发布到指定位置。</p>
<p>项目之间往往存在互相依赖，如果被依赖项发生了更改，应该有办法让所有依赖了该项目的项目都依次构建。</p>
<p>下面以一个简单的例子描述如何配置CruiseControl.net服务器。</p>
<p>打开ccnet.config文件，该文件是一个xml格式的文件，可以在配置文件中编写多个project，每个project都对应着一个&lt;project&gt; &lt;/project&gt;块。</p>
<p>&lt;cruisecontrol&gt;</p>
<p>&lt;project name=”MyProj1”&gt;</p>
<p>&lt;/project&gt;</p>
<p>&lt;project name=”MyProj2”&gt;</p>
<p>&lt;/project&gt;</p>
<p>&lt;/cruisecontrol&gt;</p>
<p>每个Project块的配置类似下面的例子：</p>
<p>&lt;project name=&#8221;Project 1&#8243; queue=&#8221;Q1&#8243; queuePriority=&#8221;1&#8243;&gt;</p>
<p>&lt;workingDirectory&gt;yourWorkingDirectory&lt;/workingDirectory&gt;</p>
<p>&lt;artifactDirectory&gt;yourArtifactDirectory&lt;/artifactDirectory&gt;</p>
<p>&lt;category&gt;Category 1&lt;/category&gt;</p>
<p>&lt;webURL&gt;http://server1/ccnet/server/local/project/testProject/ViewLatestBuildReport.aspx&lt;/webURL&gt;</p>
<p>&lt;modificationDelaySeconds&gt;2&lt;/modificationDelaySeconds&gt;</p>
<p>&lt;maxSourceControlRetries&gt;5&lt;/maxSourceControlRetries&gt;</p>
<p>&lt;initialState&gt;Stopped&lt;/initialState&gt;</p>
<p>&lt;startupMode&gt;UseInitialState&lt;/startupMode&gt;</p>
<p>&lt;triggers&gt;</p>
<p>&lt;!&#8211;yourFirstTriggerType .. &#8211;&gt;</p>
<p>&lt;!&#8211;yourOtherTriggerType .. &#8211;&gt;</p>
<p>&lt;/triggers&gt;</p>
<p>&lt;!&#8211; state type=&#8221;yourStateManagerType&#8221; .. &#8211;&gt;</p>
<p>&lt;!&#8211; sourcecontrol type=&#8221;yourSourceControlType&#8221; .. &#8211;&gt;</p>
<p>&lt;!&#8211; labeller type=&#8221;yourLabellerType&#8221; .. &#8211;&gt;</p>
<p>&lt;prebuild&gt;</p>
<p>&lt;!&#8211; yourFirstPrebuildTask .. &#8211;&gt;</p>
<p>&lt;!&#8211; yourOtherPrebuildTask .. &#8211;&gt;</p>
<p>&lt;/prebuild&gt;</p>
<p>&lt;tasks&gt;</p>
<p>&lt;!&#8211; yourFirstTask .. &#8211;&gt;</p>
<p>&lt;!&#8211; yourOtherTask .. &#8211;&gt;</p>
<p>&lt;/tasks&gt;</p>
<p>&lt;publishers&gt;</p>
<p>&lt;!&#8211; yourFirstPublisherTask .. &#8211;&gt;</p>
<p>&lt;!&#8211; yourOtherPublisherTask .. &#8211;&gt;</p>
<p>&lt;/publishers&gt;</p>
<p>&lt;externalLinks&gt;</p>
<p>&lt;externalLink name=&#8221;My First Link&#8221; url=&#8221;http://somewhere/&#8221; /&gt;</p>
<p>&lt;externalLink name=&#8221;My Other Link&#8221; url=&#8221;http://somewhere.else/&#8221; /&gt;</p>
<p>&lt;/externalLinks&gt;</p>
<p>&lt;parameters&gt;</p>
<p>&lt;textParameter name=&#8221;Build Name&#8221; default=&#8221;Unknown&#8221; /&gt;</p>
<p>&lt;/parameters&gt;</p>
<p>&lt;linkedSites&gt;</p>
<p>&lt;namedValue name=&#8221;ohloh&#8221; value=&#8221;5623&#8243; /&gt;</p>
<p>&lt;/linkedSites&gt;</p>
<p>&lt;/project&gt;</p>
<p>具体的属性含义可以参考文档：</p>
<p><a href="http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block">http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block</a></p>
<p>对于Project块，有几个比较重要的内容值得详细说明：</p>
<p>1. Queue</p>
<p>&lt;project name=&#8221;Project 1&#8243; queue=&#8221;Q1&#8243; queuePriority=&#8221;1&#8243;&gt;</p>
<p>这里有一个queue属性，以及对应的queuePriority属性。说明的是该project被放置于哪个queue中，如果不加指明，那么每个project都会被放置到一个独立的queue中。</p>
<p>Queue的作用是什么？</p>
<p>想象一下存在两个项目A和B，并且B依赖A。如果正在构建B的时候，trigger又启动了一个Build开始构建A，但是由于B依赖A，因此在构建B的过程中，需要打开A的目标文件进行读取（例如B使用A的lib文件进行link）。如果A此时恰好要写入该目标文件，则会发生文件访问冲突。进而造成A的构建流程失败。</p>
<p>我们想到或许可以将B依赖的文件拷贝一份出来，从而避免出现使用文件和写入文件冲突的情况，但是很快我们就会意识到这也行不通——因为可能我们在拷贝文件的时候（这里需要打开并读取A的输出文件），遇到了A正要写入文件的状况。</p>
<p>总结一下，对于相互之间存在依赖的项目，我们不应该让他们不受控制的并发构建，而是必须要有一个先后顺序——这里就是Queue的用处所在。</p>
<p>CruiseControl工作的时候，是以queue为单位进行的，当trigger或者人工通过force build触发了一次构建，这次构建会被置放到queue中，并且根据queuePriority决定被插入的位置。</p>
<p>这样，可以保证一系列相互之间存在依赖关系的项目在一个队列中依次进行Build，避免因相互依赖项目同时构建而导致的文件读写冲突等问题。</p>
<p>2. Triggers</p>
<p>触发器是实现我们的各种构建需求的工具。比如，每天夜里0:00产生一次Nightly Build，比如每次Check in之后都进行一次Continuous Integration Build，比如基础项目构建成功了，应当引发所有的依赖该基础项的项目都产生一次构建。等等。</p>
<p>要实现上述的功能，我们可以使用CruiseControl.NET提供的诸多类型的trigger达到目的，或者选择其中若干进行组合使用。</p>
<p>最常用的trigger之一是<a href="http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger">Interval Trigger</a>，我们可以设置Interval的间隔时间，每隔这么长的时间，触发器就会被触发一次。配合SCM工具对源代码的检查，我们可以利用Interval Trigger实现持续集成。（每隔1分钟触发一次，检查源码仓库是否有新checkin的代码，如果有则Build）</p>
<p><a href="http://confluence.public.thoughtworks.org/display/CCNET/Project+Trigger">Project Trigger</a>可以使得当前项目获知依赖项目构建成功的消息，当制定的Project构建成功之后，Trigger会被触发</p>
<p><a href="http://confluence.public.thoughtworks.org/display/CCNET/Multiple+Trigger">Multiple Trigger</a>用于将多个Trigger用逻辑关系组合起来使用，例如，当使用And逻辑进行组合时，Multiple Trigger中只要有一个Trigger认为不应当触发构建，就不会被触发构建。</p>
<p>3. Tasks</p>
<p>当Trigger触发之后，就会开始构建流程，从而将Tasks块的所有Task依次执行一遍。</p>
<p>我们需要使用Task来完成主要的构建流程。上篇文章中曾经简单介绍过MSBuild，到了这里，我们就利用MSBuild来实现自动构建了。</p>
<p>&lt;msbuild&gt;</p>
<p>&lt;executable&gt;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe&lt;/executable&gt;</p>
<p>&lt;workingDirectory&gt;C:\dev\ccnet&lt;/workingDirectory&gt;</p>
<p>&lt;projectFile&gt;build.xml&lt;/projectFile&gt;</p>
<p>&lt;targets&gt;Build;Test&lt;/targets&gt;</p>
<p>&lt;timeout&gt;900&lt;/timeout&gt;</p>
<p>&lt;logger&gt;C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll&lt;/logger&gt;</p>
<p>&lt;/msbuild&gt;</p>
<p>最简单的利用MSBuild的方式如上例所示。</p>
<p>projectFile是预先编写好的MSBuild的脚本文件，targets里面填写的是要执行MSBuild脚本中的哪个Target。（关于Target，可以参考此前总结的MSBuild简介里的相关内容，以及MSBuild自身的文档）timeout时间是指此次build如果超过多长时间则认为是超时失败。</p>
<p>4. Publishers</p>
<p>Publisher用于在构建流程走完之后将最终的结果发布出去。Publisher中可以有一系列的Task，与Tasks块中的Task的用法类似，包括调用MSBuild Task，在MSBuild脚本中执行操作等。</p>
<p>我们可以利用Publisher模块，将最新版本的SDK发布到服务器，或是创建提供给用户的安装包等。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2011/06/12/autobuild_basics_on_cruisecontrol_net_cofiguration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自动构建一：MSBuild基础</title>
		<link>http://www.windameister.org/blog/2011/06/12/autobuild_basics_on_msbuild/</link>
		<comments>http://www.windameister.org/blog/2011/06/12/autobuild_basics_on_msbuild/#comments</comments>
		<pubDate>Sun, 12 Jun 2011 08:24:22 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[Windows平台开发]]></category>
		<category><![CDATA[自动构建]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2011/06/12/%e8%87%aa%e5%8a%a8%e6%9e%84%e5%bb%ba%e4%b8%80%ef%bc%9amsbuild%e5%9f%ba%e7%a1%80/</guid>
		<description><![CDATA[MSBuild是微软自Visual Studio 2005开始提供的构建平台，既可以用于VC#项目，也可用于VC++项目。 通常情况下，我们采用IDE本身进行项目的构建，有时，也会采用命令行方式调用IDE程序Build我们的项目。（对于VC++项目来说，就是通过命令行调用devenv进行构建） 然而，当我们希望在持续集成工具当中实现项目的自动构建时，尤其是当依赖情况或者部署情况较为复杂时，我们希望有一个简单、易维护的工具实现构建——MSBuild就是我们所需要的工具。 采用MSBuild进行构建，需要我们编写MSBuild脚本——一种规定格式的XML文件。 MSBuild基本组成部分包括：Target（目标），ItemGroup（项），PropertyGroup（属性），Task（任务）。 其中：Target目标是MSBuild执行的基本单元。 我们在命令行中调用MSBuild /t:TargetName指定需要执行的目标。 每个Target中可以包含若干Task。 Task是基本的功能单元：例如拷贝文件，删除文件，创建/删除目录，使用Exec调用外部程序，调用VCBuild构建.vcproj项目，调用Csc编译.cs文件，等等。此外，你还可以通过实现ITask接口，创建自定义的Task。 PropertyGroup作为属性，起着类似于变量一样的作用，可以定义一个属性，并在后续的位置使用该属性，例如： &#60;PropertyGroup&#62; &#60;ProjFile&#62;C:\Test\test.vcproj&#60;/ProjFile&#62; &#60;Rebuild&#62;true&#60;/Rebuild&#62; &#60;/PropertyGroup&#62; &#60;Target Name=”Build”&#62; &#60;VCBuild     Projects=”$(ProjFile)”     Rebuild=”$(Rebuild)”    /&#62; &#60;/Target&#62; ItemGroup往往作为输入，例如： &#60;ItemGroup&#62; &#60;IncFiles Include=”C:\Test\*.h” /&#62; &#60;/ItemGroup&#62; &#60;Target Name=”Build”&#62; &#60;Copy    SourceFiles=”@(IncFiles)”    DestinationFolder=”c:\output\include” /&#62; &#60;/Target&#62; &#160; 实例： 假设我们有一个项目A，依赖一个动态连接库B，我们需要先构建B，将B的头文件和lib文件拷贝到A的包含头文件路径和Lib路径下，再构建A，然后将A发布到指定的路径下。 B的项目结构如下： C:\B\B.vcproj A的项目结构如下： C:\A \DepInclude \DepLib \Src\A.vcproj \Output 对应的MSBuild脚本如下： &#60;ItemGroup&#62; &#60;BIncFiles Include=”C:\B\*.h” /&#62; &#60;BLibFiles Include=”C:\B\Release\*.lib” [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://msdn.microsoft.com/zh-cn/library/ms171451(v=vs.80).aspx">MSBuild</a>是微软自Visual Studio 2005开始提供的构建平台，既可以用于VC#项目，也可用于VC++项目。</p>
<p>通常情况下，我们采用IDE本身进行项目的构建，有时，也会采用命令行方式调用IDE程序Build我们的项目。（对于VC++项目来说，就是通过命令行调用devenv进行构建）</p>
<p>然而，当我们希望在持续集成工具当中实现项目的自动构建时，尤其是当依赖情况或者部署情况较为复杂时，我们希望有一个简单、易维护的工具实现构建——MSBuild就是我们所需要的工具。</p>
<p><span id="more-271"></span></p>
<p>采用MSBuild进行构建，需要我们编写MSBuild脚本——一种规定格式的XML文件。</p>
<p>MSBuild基本组成部分包括：Target（目标），ItemGroup（项），PropertyGroup（属性），Task（任务）。</p>
<p>其中：Target目标是MSBuild执行的基本单元。</p>
<p>我们在命令行中调用MSBuild /t:TargetName指定需要执行的目标。</p>
<p>每个Target中可以包含若干Task。</p>
<p>Task是基本的功能单元：例如拷贝文件，删除文件，创建/删除目录，使用Exec调用外部程序，调用VCBuild构建.vcproj项目，调用Csc编译.cs文件，等等。此外，你还可以通过实现ITask接口，创建自定义的Task。</p>
<p>PropertyGroup作为属性，起着类似于变量一样的作用，可以定义一个属性，并在后续的位置使用该属性，例如：</p>
<div class="codearea">
<pre>&lt;PropertyGroup&gt;
   &lt;ProjFile&gt;C:\Test\test.vcproj&lt;/ProjFile&gt;
   &lt;Rebuild&gt;true&lt;/Rebuild&gt;
&lt;/PropertyGroup&gt;

&lt;Target Name=”Build”&gt;
   &lt;VCBuild     Projects=”$(ProjFile)”     Rebuild=”$(Rebuild)”    /&gt;
&lt;/Target&gt;</pre>
</div>
<p>ItemGroup往往作为输入，例如：</p>
<div class="codearea">
<pre>&lt;ItemGroup&gt;
   &lt;IncFiles Include=”C:\Test\*.h” /&gt;
&lt;/ItemGroup&gt;

&lt;Target Name=”Build”&gt;
   &lt;Copy    SourceFiles=”@(IncFiles)”    DestinationFolder=”c:\output\include”
/&gt;
&lt;/Target&gt;</pre>
</div>
<p><!--.codearea{ color:black;  background-color:white;  line-height:18px;  border:1px solid #4f81bd;  margin:0;  width:auto !important;  width:100%;  overflow:auto;  text-align:left;  font-size:12px;  font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif} .codearea pre{ color:black; line-height:18px;  padding:0 0 0 12px !important; margin:0em;  background-color:#fff !important} .linewrap pre{white-space:pre-wrap;  white-space:-moz-pre-wrap;  white-space:-pre-wrap;  white-space:-o-pre-wrap;  word-wrap:break-word;  word-break:normal} .codearea pre.alt{ background-color:#f7f7ff !important} .codearea .lnum{color:#4f81bd;line-height:18px} -->&nbsp;</p>
<p>实例：</p>
<p>假设我们有一个项目A，依赖一个动态连接库B，我们需要先构建B，将B的头文件和lib文件拷贝到A的包含头文件路径和Lib路径下，再构建A，然后将A发布到指定的路径下。</p>
<p>B的项目结构如下：</p>
<p>C:\B\B.vcproj</p>
<p>A的项目结构如下：</p>
<p>C:\A</p>
<p>\DepInclude</p>
<p>\DepLib</p>
<p>\Src\A.vcproj</p>
<p>\Output</p>
<p>对应的MSBuild脚本如下：</p>
<div class="codearea">
<pre>&lt;ItemGroup&gt;
   &lt;BIncFiles Include=”C:\B\*.h” /&gt;
   &lt;BLibFiles Include=”C:\B\Release\*.lib” /&gt;
   &lt;BDllFiles Include=”C:\B\Release\*.dll” /&gt;
&lt;/ItemGroup&gt;

&lt;TargetName=”Build_B”&gt;
    &lt;VCBuild
      Projects=”C:\B\B.vcproj”
      Configuration=”Release”
      Rebuild=”true”     /&gt;
&lt;Copy   SourceFiles=”@(BIncFiles)”
  DestinationFolder=”C:\A\DepInclude”
/&gt;
&lt;Copy   SourceFiles=”@(BLibFiles)”
  DestinationFolder=”C:\A\DepLib”
/&gt;
&lt;/Target&gt;

&lt;Target Name=“Build_A” DependOnTargets=“Build_B”&gt;
    &lt;VCBuild
      Projects=”C:\A\Src\A.vcproj“
      Configuration=“Release”
      Rebuild=”true”
    /&gt;
&lt;/Target&gt;</pre>
</div>
<p><!--.codearea{ color:black;  background-color:white;  line-height:18px;  border:1px solid #4f81bd;  margin:0;  width:auto !important;  width:100%;  overflow:auto;  text-align:left;  font-size:12px;  font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif} .codearea pre{ color:black; line-height:18px;  padding:0 0 0 12px !important; margin:0em;  background-color:#fff !important} .linewrap pre{white-space:pre-wrap;  white-space:-moz-pre-wrap;  white-space:-pre-wrap;  white-space:-o-pre-wrap;  word-wrap:break-word;  word-break:normal} .codearea pre.alt{ background-color:#f7f7ff !important} .codearea .lnum{color:#4f81bd;line-height:18px} -->&nbsp;</p>
<p>Build_A的Target使用了一个DependOnTargets属性，该属性的含义是当前Target要依赖前续的某些Targets，那些依赖的Targets必须先执行，然后才能执行当前的Target。</p>
<p>在本例中Build_B会rebuild整个B工程，并将结果的头文件和lib文件拷贝到A项目的依赖路径当中。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2011/06/12/autobuild_basics_on_msbuild/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为什么你应当从现在就开始学习投资理财</title>
		<link>http://www.windameister.org/blog/2011/03/27/why-u-should-learn-value-investing-from-now/</link>
		<comments>http://www.windameister.org/blog/2011/03/27/why-u-should-learn-value-investing-from-now/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 03:41:00 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[投资理财]]></category>
		<category><![CDATA[价值投资]]></category>
		<category><![CDATA[理财]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2011/03/27/%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bd%a0%e5%ba%94%e5%bd%93%e4%bb%8e%e7%8e%b0%e5%9c%a8%e5%b0%b1%e5%bc%80%e5%a7%8b%e5%ad%a6%e4%b9%a0%e6%8a%95%e8%b5%84%e7%90%86%e8%b4%a2/</guid>
		<description><![CDATA[用一句话来说就是，学习投资理财有很多好处，却没有任何明显的坏处。 更明确一点说，学习投资理财，可以提升自己对市场经济的认识，有助于形成正确的财富观念，在实践当中获得收益，并且是一条通往财务自由之路。 1．投资与投机。 投机不是投资。投资者会根据公司的业务状况计算一只股票的价值；而投机者则会打赌股票的价格的上涨，因为他们认为，其他人会出更高的价格来买入这支股票。投机的对象可以是证券、可以是债券、可以是金银、甚至可以是只有观赏价值的花卉： 1634年到1636年的荷兰，由于上流社会的追捧以及供求关系的不平衡，郁金香的价格被迅速抬了起来。郁金香价格暴涨吸引了许多人从欧洲各地赶到荷兰，带来了大量的资金，给郁金香交易火上浇油。在1636年12月到1637年1月之间，所有品种的郁金香价格全线上升。以一种稀有品种Gouda为例，其价格在12月9日的最低点（1.5基尔德）到12月12日的最高点（11基尔德），3天内价格上升将近10倍。超额利润招来了四面八方的投机客。也许早有人怀疑到郁金香的价格已经完全背离了作为一种花卉的常规，但是倒买倒卖所获取的暴利使得许多投机客们丧失了理智。荷兰的郁金香泡沫只维持了一个冬天，在开春之前，泡沫就崩溃了，郁金香市场一片混乱，价格急剧下降。1639年的数据显示，有些品种的郁金香的价格狂跌到最高价位的0.005%。 投资还是投机，与你买入对象的类别无关，只取决于你买入的理由。 按照格雷厄姆给出的定义，“投资操作是建立在透彻分析的基础之上的，目的是要保证本金安全并获得适当的回报”。“投资”所特意强调的安全保障不能建立在市场虚假的信息、毫无根据的臆断、内部小道消息的传播或十足的赌性上；“投资”的安全性必须取决于投资对象是否具备真正的内在价值或存在一个价值变化的空间。相比于投资者的这种“根据公认的价值标准”来判断“股票的市场价格”，投机者则是“根据市场价格来确定价值标准”。 2. 投资回报率与折现率 如果你不能承受风险，就应当满足于较低的投资回报——这是一个由来已久，且听起来十分合理的原则。由此可以得出这样的结论：投资者能够指望的回报，在一定程度上是与其承担的风险成正比的——对这种观点，格雷厄姆在《聪明的投资者》中予以否认。投资者的目标收益率，更多的是由他们乐于且能够为其投资付出的智慧所决定的：图省事且注重安全性的消极投资者，理应得到最低的报酬，而那些精明且富有经验的投资者，由于他们付出了最大的智慧和技能，则理应得到最大的回报。 在思考投资回报率的时候，我们需要引入折现率的概念：折现率是指将未来预期收益折算成现值的比率。简单来说，就是让你选择今天获取10000块钱还是3年后获取12000块钱，如果你正在考虑哪种更合算，那么你正在考虑的就是折现率。（未来的钱相当于现在的钱的比例） 如果一项投资的年收益率小于折现率，那么就可以认为是亏损的。 折现率的构成中包括：无风险利率+风险报酬率+通货膨胀率。 折现率有多种评估方法：a. 累加法，从定义出发，折现率应该包含无风险利率、风险报酬率和通货膨胀率。b. 市场比较法，通过比较同行业企业的资本收益率来评估。 c. 社会平均资产收益率法，通过社会平均资产收益率的情况来评估。 如果从定义出发，计算一下银行的利率，比如三年期定期存款的年利率是4.5%，这里的4.5%的收益率就是无风险利率。无风险利率是投资者在不冒风险的情况下就可以长期而稳定的获取的投资收益率，因此折现率必须高于无风险利率。（从折现率的角度来考虑投资收益，存在银行的钱就是在产生持续的亏损） 社会平均资产收益率是指一段时间内，全社会的总资产，通过投资获取的收益与资产之比率，这与银行存款利率是有很大差别的——银行通过收集存款人的存款，并以贷款的形式投资到各个企业中，从息差中获得收益，企业通过贷款获取经营资本，并在经营中收获利润，当你把钱存入银行之后，这笔钱所经历的每一层收益：银行的息差，企业的利润，都扩大了你收获的银行存款利率与社会平均资产收益率之间的差额——这也是为什么你的银行账户中不应当保留太多存款的理由。 如果我们将折现率就看成是社会平均资产收益率，那么，对于投资者来说，社会平均资产收益率应当是长期资本的无风险收益率，因为取得这个收益率只是与整体经济同步增长，如果低于社会平均资产收益率，则意味着投资亏损了。举例来说，如果社会全部财富有10万亿的时候个人拥有资产1万元，与社会全部财富达到11.5万亿时，个人资产达到1.15万元，两种情况下投资者应当具有相同的满意度。如果这个平均增长比率无法达到，就意味着个人拥有的财富相对社会总财富的比重减小了。 3. 积极的理财目标 由于我们所持有的货币会随着通货膨胀贬值，同时，随着GDP的增长，我们所拥有的财富也在被摊薄。也就是说，只有让自己的投资收益率高于通货膨胀率+GDP增长率，才能跑赢社会平均资产收益率。 为什么GDP增长也在摊薄你手中的货币价值？ 假如A年社会总财富为10万亿，如果你手中的货币今年为10万元，你手中的财富占社会总财富比重的10万/10万亿。如果今年的GDP增长为10%，第二年社会总财富为11万亿，而你的钱全部存银行定期，利率为3%，第二年为10.3万元。那么经过这一年，你的财富占社会总财富的比重就从10万/10万亿，下降为10.3万/11万亿了。（这里是不考虑通货膨胀因素的） 除了GDP增长会摊薄你手中的财富之外，通货膨胀也在侵蚀你的财富地位。通货膨胀是通过间接的方式发生作用的。还是以上例来说，A年的GDP是10万亿——全社会生产了价值10万亿的商品和服务，到A+1年，GDP增长到11万亿（实际价值），但是A年的货币总量从10万亿（为了简化情况，我们假设开始的时候没有任何通货膨胀，也就是说货币总量与资产总价值相等，实际情况中肯定是不可能的），增长到11.8万亿，也就是说货币总量增加了18%，这时候的11万亿是生产的商品+服务的实际价值，但是由于这一年中货币总量的增加，而且你的财富全部是以货币的形式表现的，因此你所持有的10.3万元，所占社会财富的总比重不是10.3万/11万亿，而是10.3万/11.8万亿。 通货膨胀的一个特点是只针对货币资产——如果你的财富不全是以货币的形式存在的，而是以实际资产的形式（股票，债券，黄金，房产），则一定程度上避免了通货膨胀对你的影响。 为什么不是黄金？黄金是社会总资产中的一种，且是一种“静止的资产”：相比于将资金投入到社会资本运作中，变成商品和服务，并依此收获增值，你所持有的黄金资产并不能主动为你带来增值（而往往只是在通货膨胀带来的价格上涨中取得保值的效用）。因此，长期来看，黄金不可能带来超过社会平均资产收益率的回报。（由于金本位制已经离我们远去了，因此黄金从某种意义上可以看成是一根通货膨胀的指针，虽然从短期来看，黄金的价格中存在许多投机的成分，但是长期来看，黄金的价格上涨实际上只是标识出的是货币购买力下降的程度，而这段时间内社会又创造出了大量的新财富，黄金并不能从中受益） 如果我们将手中的货币变成具有长期前景的优质公司的股票，那么我们拥有的份额就会随着公司的成长而改变。长期来看，持有几个优质公司的一部分，比持有所有公司(指数)的一部分会取得更高的收益，比持有贵金属或者消费品（货币）更好。而如何择选优质公司的股票，这需要做大量的甄别和鉴选，需要对市场，行业大环境，财务知识，公司管理者有足够的了解，才能做出有利的选择。在这方面，《股市真规则》，《聪明的投资者》可以作为学习价值投资的入门书籍。 引用九牛老师的一句话作为结语： 过去的三十年间，中国的GDP大约增长了10倍，通货膨胀了约10倍，人民币总额变成30年前的100倍。人民币年复合增长率达到18%。在这样一个背景下，只有对已有财富做积极投资才能保住财富的相对地位，否则一切纸币都会在洪流中化为乌有。]]></description>
			<content:encoded><![CDATA[<p>用一句话来说就是，<strong>学习投资理财有很多好处，却没有任何明显的坏处</strong>。</p>
<p>更明确一点说，<strong>学习投资理财，可以提升自己对市场经济的认识，有助于形成正确的财富观念，在实践当中获得收益，并且是一条通往财务自由之路</strong>。</p>
<p><span id="more-263"></span>1．投资与投机。
<p>投机不是投资。<strong>投资者会根据公司的业务状况计算一只股票的价值；而投机者则会打赌股票的价格的上涨，因为他们认为，其他人会出更高的价格来买入这支股票</strong>。投机的对象可以是证券、可以是债券、可以是金银、甚至可以是<a href="http://wiki.mbalib.com/zh-tw/%E9%83%81%E9%87%91%E9%A6%99%E6%B3%A1%E6%B2%AB%E7%BB%8F%E6%B5%8E">只有观赏价值的花卉</a>：</p>
<blockquote><p>1634年到1636年的荷兰，由于上流社会的追捧以及供求关系的不平衡，郁金香的价格被迅速抬了起来。郁金香价格暴涨吸引了许多人从欧洲各地赶到荷兰，带来了大量的资金，给郁金香交易火上浇油。在1636年12月到1637年1月之间，所有品种的郁金香价格全线上升。以一种稀有品种Gouda为例，其价格在12月9日的最低点（1.5基尔德）到12月12日的最高点（11基尔德），3天内价格上升将近10倍。超额利润招来了四面八方的投机客。也许早有人怀疑到郁金香的价格已经完全背离了作为一种花卉的常规，但是倒买倒卖所获取的暴利使得许多投机客们丧失了理智。荷兰的郁金香泡沫只维持了一个冬天，在开春之前，泡沫就崩溃了，郁金香市场一片混乱，价格急剧下降。1639年的数据显示，有些品种的郁金香的价格狂跌到最高价位的0.005%。</p>
</blockquote>
<p><strong>投资还是投机，与你买入对象的类别无关，只取决于你买入的理由</strong>。</p>
<p>按照格雷厄姆给出的定义，“<strong>投资操作是建立在透彻分析的基础之上的，目的是要保证本金安全并获得适当的回报</strong>”。“投资”所特意强调的安全保障不能建立在市场虚假的信息、毫无根据的臆断、内部小道消息的传播或十足的赌性上；“投资”的安全性必须取决于投资对象是否具备真正的内在价值或存在一个价值变化的空间。<a href="http://en.wikipedia.org/wiki/Security_Analysis_(book)">相比于投资者的这种“根据公认的价值标准”来判断“股票的市场价格”，投机者则是“根据市场价格来确定价值标准”</a>。</p>
<p>2. 投资回报率与折现率</p>
<p>如果你不能承受风险，就应当满足于较低的投资回报——这是一个由来已久，且听起来十分合理的原则。由此可以得出这样的结论：投资者能够指望的回报，在一定程度上是与其承担的风险成正比的——对这种观点，格雷厄姆在《<a href="http://book.douban.com/subject/5243775/">聪明的投资者</a>》中予以否认。投资者的目标收益率，更多的是由他们乐于且能够为其投资付出的智慧所决定的：<strong>图省事且注重安全性的消极投资者，理应得到最低的报酬，而那些精明且富有经验的投资者，由于他们付出了最大的智慧和技能，则理应得到最大的回报</strong>。</p>
<p>在思考投资回报率的时候，我们需要引入<a href="http://wiki.mbalib.com/wiki/%E6%8A%98%E7%8E%B0%E7%8E%87">折现率</a>的概念：<strong>折现率是指将未来预期收益折算成现值的比率</strong>。简单来说，就是让你选择今天获取10000块钱还是3年后获取12000块钱，如果你正在考虑哪种更合算，那么你正在考虑的就是折现率。（未来的钱相当于现在的钱的比例）</p>
<p><strong>如果一项投资的年收益率小于折现率，那么就可以认为是亏损的。</strong><strong></strong></p>
<p>折现率的构成中包括：无风险利率+风险报酬率+通货膨胀率。</p>
<p>折现率有多种评估方法：a. 累加法，从定义出发，折现率应该包含无风险利率、风险报酬率和通货膨胀率。b. 市场比较法，通过比较同行业企业的资本收益率来评估。 c. 社会平均资产收益率法，通过<strong>社会平均资产收益率</strong>的情况来评估。</p>
<p>如果从定义出发，计算一下银行的利率，比如三年期定期存款的年利率是4.5%，这里的4.5%的收益率就是无风险利率。无风险利率是投资者在不冒风险的情况下就可以长期而稳定的获取的投资收益率，因此<strong>折现率必须高于无风险利率。</strong>（从折现率的角度来考虑投资收益，存在银行的钱就是在产生持续的亏损）</p>
<p>社会平均资产收益率是指一段时间内，全社会的总资产，通过投资获取的收益与资产之比率，这与银行存款利率是有很大差别的——银行通过收集存款人的存款，并以贷款的形式投资到各个企业中，从息差中获得收益，企业通过贷款获取经营资本，并在经营中收获利润，当你把钱存入银行之后，这笔钱所经历的每一层收益：银行的息差，企业的利润，都扩大了你收获的银行存款利率与社会平均资产收益率之间的差额——<strong>这也是为什么你的银行账户中不应当保留太多存款的理由</strong>。</p>
<p>如果我们将折现率就看成是社会平均资产收益率，那么，<strong><a href="http://blog.sina.com.cn/s/blog_4978eb8f010006ux.html">对于投资者来说，社会平均资产收益率应当是长期资本的无风险收益率，因为取得这个收益率只是与整体经济同步增长，如果低于社会平均资产收益率，则意味着投资亏损了。</a></strong>举例来说，如果社会全部财富有10万亿的时候个人拥有资产1万元，与社会全部财富达到11.5万亿时，个人资产达到1.15万元，两种情况下投资者应当具有相同的满意度。如果这个平均增长比率无法达到，就意味着个人拥有的财富相对社会总财富的比重减小了。</p>
<p>3. 积极的理财目标</p>
<p>由于我们所持有的货币会随着通货膨胀贬值，同时，随着GDP的增长，我们所拥有的财富也在被摊薄。也就是说，只有让自己的<strong>投资收益率高于通货膨胀率</strong><strong>+GDP</strong><strong>增长率</strong>，才能跑赢社会平均资产收益率。</p>
<p>为什么GDP增长也在摊薄你手中的货币价值？</p>
<blockquote><p>假如A年社会总财富为10万亿，如果你手中的货币今年为10万元，你手中的财富占社会总财富比重的10万/10万亿。如果今年的GDP增长为10%，第二年社会总财富为11万亿，而你的钱全部存银行定期，利率为3%，第二年为10.3万元。那么经过这一年，你的财富占社会总财富的比重就从10万/10万亿，下降为10.3万/11万亿了。（这里是不考虑通货膨胀因素的）</p>
<p>除了GDP增长会摊薄你手中的财富之外，通货膨胀也在侵蚀你的财富地位。通货膨胀是通过间接的方式发生作用的。还是以上例来说，A年的GDP是10万亿——全社会生产了价值10万亿的商品和服务，到A+1年，GDP增长到11万亿（实际价值），但是A年的货币总量从10万亿（为了简化情况，我们假设开始的时候没有任何通货膨胀，也就是说货币总量与资产总价值相等，实际情况中肯定是不可能的），增长到11.8万亿，也就是说货币总量增加了18%，这时候的11万亿是生产的商品+服务的实际价值，但是由于这一年中货币总量的增加，而且你的财富全部是以货币的形式表现的，因此你所持有的10.3万元，所占社会财富的总比重不是10.3万/11万亿，而是10.3万/11.8万亿。</p>
</blockquote>
<p>通货膨胀的一个特点是只针对货币资产——如果你的财富不全是以货币的形式存在的，而是以实际资产的形式（股票，债券，黄金，房产），则一定程度上避免了通货膨胀对你的影响。</p>
<p>为什么不是黄金？黄金是社会总资产中的一种，且是一种“静止的资产”：相比于将资金投入到社会资本运作中，变成商品和服务，并依此收获增值，你所持有的黄金资产并不能主动为你带来增值（而往往只是在通货膨胀带来的价格上涨中取得保值的效用）。因此，长期来看，黄金不可能带来超过社会平均资产收益率的回报。（由于金本位制已经离我们远去了，因此黄金从某种意义上可以看成是一根通货膨胀的指针，虽然从短期来看，黄金的价格中存在许多投机的成分，但是<strong>长期来看，黄金的价格上涨实际上只是标识出的是货币购买力下降的程度，而这段时间内社会又创造出了大量的新财富，黄金并不能从中受益</strong>）</p>
<p>如果我们<strong>将手中的货币变成具有长期前景的优质公司的股票，那么我们拥有的份额就会随着公司的成长而改变</strong>。长期来看，持有几个优质公司的一部分，比持有所有公司(指数)的一部分会取得更高的收益，比持有贵金属或者消费品（货币）更好。而如何择选优质公司的股票，这需要做大量的甄别和鉴选，需要对市场，行业大环境，财务知识，公司管理者有足够的了解，才能做出有利的选择。在这方面，《<a href="http://book.douban.com/subject/4137173/">股市真规则</a>》，《<a href="http://book.douban.com/subject/5243775/">聪明的投资者</a>》可以作为学习价值投资的入门书籍。</p>
<p>引用九牛老师的一句话作为结语：</p>
<p><a href="http://blog.sina.com.cn/s/blog_4978eb8f0100go5l.html">过去的三十年间，中国的GDP大约增长了10倍，通货膨胀了约10倍，人民币总额变成30年前的100倍。人民币年复合增长率达到18%。在这样一个背景下，只有对已有财富做积极投资才能保住财富的相对地位，否则一切纸币都会在洪流中化为乌有。</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2011/03/27/why-u-should-learn-value-investing-from-now/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>从C++到C#——穿行于Native与.Net 托管代码之间</title>
		<link>http://www.windameister.org/blog/2010/12/19/from-cpp-to-csharp-cross-the-boundary-of-native-and-managed-code/</link>
		<comments>http://www.windameister.org/blog/2010/12/19/from-cpp-to-csharp-cross-the-boundary-of-native-and-managed-code/#comments</comments>
		<pubDate>Sun, 19 Dec 2010 09:52:55 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[C++ & Design]]></category>
		<category><![CDATA[Windows平台开发]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[托管代码]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/?p=245</guid>
		<description><![CDATA[微软在.Net平台中提供了大量丰富的语言，库，并为之提供了非常强大的开发工具。借用.Net平台，我们可以非常容易的开发基于Windows的应用，与采用C++相比，使用C#语言开发相同功能的软件可以极大的提升开发效率，缩短开发周期，减少Bug。 然而，往往现存有大量的积累代码是基于原生语言开发的，当我们决定采用C#时，必须考虑到与现存的软件组件交互的能力，具体而言——如何在一个以C++语言为主的项目中引入.NET组件？如何在.NET组件中使用C++代码库提供的功能？ 在游戏项目中，比较理想的情况是底层的3D引擎采用C++编写，而上层编辑器则采用C#编写，这样可以兼顾引擎的运行效率和编辑器的开发效率。一个值得一提的案例是UDK（Unreal引擎的开发包），其中就采用了C++语言与.NET组件相结合的模式，其界面上相当一部分新功能是采用.NET开发的。 下面介绍下我总结的C++与.NET互操作的方法： 1. C++ –&#62; .NET在C++语言中调用.NET 由于.NET组件被设计成COM兼容格式，我们可以像使用COM组件一样使用.NET组件。也就是说，我们可以创建.NET组件中的COM对象，并获取接口来使用它。 值得注意的是使用.NET编译出的dll模块，与采用Native语言构建的ActiveX模块或者其他COM DLL是有差别的，你无法使用regsvr32对其进行注册（没有导出DllRegisterServer, DllUnregisterServer）。 &#160; 如果希望在C++中调用.NET代码，那么在实现.NET组件时，需要设置ComVisible属性，具体而言，就是在Properties\AssemblyInfo.cs 中，将[assembly: ComVisible(false)]（默认）属性，更改为： [assembly: ComVisible(true)]，这样才能使用COM的方式访问到.NET组件中的接口。 将需要暴露给Native代码使用的功能抽象成接口，在.NET中实现该接口，并为之提供Guid（可以采用VC2005中的工具Tools/Create Guid），这样才能在Native代码中使用该接口，并用Guid创建这个接口的实例。例如下面这样： namespace XDll { [Guid("1DE25FAA-4AA1-4819-B1FF-0D507567685E ")] public interface IXSystem { } [Guid("603F977B-34CF-40ca-BB30-B6BC25D2A370")] public class ImplXSystem : IXSystem { } } 在.NET组件构建完成后，需要使用regasm工具，将其中的COM接口导出成tlb文件，以供给C++代码使用。Regasm工具通常安装在.NET Framework的目录下，例如： &#8220;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm&#8221; 命令行如下： &#8220;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm&#8221; X.dll /tlb:X.tlb 这里注意一点，安装.NET framework并不会自动将上述路径加入到系统路径中，因此运行regasm时需要键入完整的路径。 在Native代码中调用.NET代码时（VC2005开发环境），需要做以下几件事： #import &#60;mscorlib.tlb&#62; raw_interfaces_only #import “X.tlb” no_namespace [...]]]></description>
			<content:encoded><![CDATA[<p>微软在.Net平台中提供了大量丰富的语言，库，并为之提供了非常强大的开发工具。借用.Net平台，我们可以非常容易的开发基于Windows的应用，与采用C++相比，使用C#语言开发相同功能的软件可以极大的提升开发效率，缩短开发周期，减少Bug。</p>
<p>然而，往往现存有大量的积累代码是基于原生语言开发的，当我们决定采用C#时，必须考虑到与现存的软件组件交互的能力，具体而言——如何在一个以C++语言为主的项目中引入.NET组件？如何在.NET组件中使用C++代码库提供的功能？</p>
<p>在游戏项目中，比较理想的情况是底层的3D引擎采用C++编写，而上层编辑器则采用C#编写，这样可以兼顾引擎的运行效率和编辑器的开发效率。一个值得一提的案例是<a href="http://www.udk.com/">UDK</a>（Unreal引擎的开发包），其中就采用了C++语言与.NET组件相结合的模式，其界面上相当一部分新功能是采用.NET开发的。</p>
<p><span id="more-245"></span></p>
<p>下面介绍下我总结的C++与.NET互操作的方法：</p>
<p><strong>1. C++ –&gt; .NET在C++语言中调用.NET</strong></p>
<p>由于.NET组件被设计成COM兼容格式，我们可以像使用COM组件一样使用.NET组件。也就是说，我们可以创建.NET组件中的COM对象，并获取接口来使用它。</p>
<p>值得注意的是使用.NET编译出的dll模块，与采用Native语言构建的ActiveX模块或者其他COM DLL是有差别的，你无法使用regsvr32对其进行注册（没有导出DllRegisterServer, DllUnregisterServer）。</p>
<p>&nbsp;</p>
<p>如果希望在C++中调用.NET代码，那么在实现.NET组件时，需要设置ComVisible属性，具体而言，就是在Properties\AssemblyInfo.cs 中，将[assembly: ComVisible(false)]（默认）属性，更改为：</p>
<p>[assembly: ComVisible(true)]，这样才能使用COM的方式访问到.NET组件中的接口。</p>
<p>将需要暴露给Native代码使用的功能抽象成接口，在.NET中实现该接口，并为之提供Guid（可以采用VC2005中的工具Tools/Create Guid），这样才能在Native代码中使用该接口，并用Guid创建这个接口的实例。例如下面这样：</p>
<div class="codearea">
<pre><span style="color: blue;">namespace </span><span style="color: #010001;">XDll
</span>{
    [<span style="color: #010001;">Guid</span>(<span style="color: #a31515;">"1DE25FAA-4AA1-4819-B1FF-0D507567685E "</span>)]
    <span style="color: blue;">public interface </span><span style="color: #010001;">IXSystem
    </span>{

    }

    [<span style="color: #010001;">Guid</span>(<span style="color: #a31515;">"603F977B-34CF-40ca-BB30-B6BC25D2A370"</span>)]
    <span style="color: blue;">public class </span><span style="color: #010001;">ImplXSystem </span>: <span style="color: #010001;">IXSystem
    </span>{ 

    }
}</pre>
</div>
<p>在.NET组件构建完成后，需要使用<a href="http://msdn.microsoft.com/zh-cn/library/tzat5yw6(v=vs.80).aspx">regasm</a>工具，将其中的COM接口导出成tlb文件，以供给C++代码使用。Regasm工具通常安装在.NET Framework的目录下，例如：</p>
<p>&#8220;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm&#8221;</p>
<p>命令行如下：</p>
<p>&#8220;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm&#8221; X.dll /tlb:X.tlb</p>
<p>这里注意一点，安装.NET framework并不会自动将上述路径加入到系统路径中，因此运行regasm时需要键入完整的路径。</p>
<p>在Native代码中调用.NET代码时（VC2005开发环境），需要做以下几件事：</p>
<p>#import &lt;mscorlib.tlb&gt; raw_interfaces_only</p>
<p>#import “X.tlb” no_namespace named_guids</p>
<p>这两行将一些必要的接口导入，X.tlb是前述步骤中使用regasm工具导出的文件，其中包含了使用C++语言描述的.NET组件中的接口。</p>
<p>通常情况下，Visual Studio会在$CURRENTUSER$\local settings\temp\目录下生成一个后缀名为.tlh的文件，其中包含了.NET库导出的诸多CLSID_X以及IID_X等GUID，以及各COM接口，C++代码可以直接使用该文件中的GUID与接口声明。</p>
<p>接下来使用.NET组件接口与使用COM接口基本相同：</p>
<div class="codearea">
<pre><span style="color: #010001;">CoInitialize</span>(<span style="color: #010001;">NULL</span>); <span style="color: green;">// 初?始?化?COM相?关?

</span><span style="color: #010001;">IX</span>* <span style="color: #010001;">pIX</span>;
<span style="color: #010001;">CoCreateInstance</span>(<span style="color: #010001;">CLSID_X
                 </span>, <span style="color: #010001;">NULL
                 </span>, <span style="color: #010001;">CLSCTX_INPROC_SERVER
                 </span>, <span style="color: #010001;">IID_IX
                 </span>, <span style="color: blue;">reinterpret_cast</span>&lt;<span style="color: blue;">void</span>**&gt;(&amp;<span style="color: #010001;">pIX</span>));</pre>
</div>
<p>&nbsp;</p>
<p>注意这里的CLSID前缀的Guid与IID前缀的Guid的区别，前者是实现类的Guid，后者是接口的Guid，我们这里调用CoCreateInstance的意义在于，创建一个Guid为CLSID_X的实现类，并返回给我一个Guid为IID_IX的接口，我将会以这个接口去访问该实现类。</p>
<p>这里的CLSID_X与IID_IX都是在导出tlb文件时自动生成的GUID数据结构，可以在Native代码中直接使用。</p>
<p>当使用了.NET组件的程序被发布时，需要将上述tlb中的各种ID注册到目标机器的注册表的相应键值中。比如，CLSID就需要导入到目标机器的注册表的HKEY_CLASSES_ROOT\CLSID键中。这一步可以通过regasm的/regfile功能实现，该功能可以导出所有需要的信息到注册表中。</p>
<p>最后当使用完毕之后，记得需要调用创建的COM接口的Release()方法。</p>
<p>pIX-&gt;Release();</p>
<p>以及清理：</p>
<p>CoUninitialize();</p>
<p><strong>2. .NET组件调用Native代码(C++)</strong></p>
<p>由于.NET组件是出现于C++之后，微软在设计时就已经基于COM模型设计其二进制接口，因此很容易可以让以前的原生语言来调用，而C++语言则诞生得更早，没有定义二进制标准，要想让.NET组件调用，只能把自己实现成COM组件的模式。关于如何用Native语言实现一个COM组件，可以参考更加专业的参考书：<a href="http://book.douban.com/subject/1231596/">《COM技术内幕》</a>，<a href="http://book.douban.com/subject/1231481/">《COM本质论》</a>等。本文主要提及在实现COM接口时值得考虑的两种思路。</p>
<p>根据实际应用场景的不同，我们可能面临不同的技术选择：</p>
<p>场景1： <strong>.NET组件依赖于C++库，完全基于C++库构建，并且C++模块不会反向依赖.NET组件</strong></p>
<p>这种情形下，由于依赖结构简单，我们可以将整个C++库采用C++CLI封装，有一些开源库采用了这种做法，比如<a href="http://slimdx.org/">SlimDX</a>项目（这是一个为了可以在.NET中使用DirectX的项目，将DirectX采用C++CLI封装，最终提供了一套面向.NET的开发框架。）再如ManagedOgre或者OgreDotNet，都将Ogre引擎封装在C++CLI中从而提供在.NET中操作OGRE的方案。</p>
<p>场景2： <strong>.NET组件依赖于C++模块，C++模块又依赖.NET组件</strong></p>
<p>.NET中需要调用底层的一些服务做一些事情，例如采用底层接口绘制一个三维场景，置放于.NET模块的窗口中。同时可能C++模块又要依赖.NET组件，比如一个.NET控件需要在一个以C++语言为主开发的编辑器中被调用。</p>
<p>形成类似于下面这样的关系，Native Code与Managed Code互相依赖：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/12/image.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://www.windameister.org/blog/wp-content/uploads/2010/12/image_thumb.png" border="0" alt="image" width="547" height="147" /></a></p>
<p>这里，我们可以将.NET对C++模块的依赖提取成一个.NET接口，而后C++代码实现该接口，从而消除.NET对C++代码的直接依赖，将之转变成C++模块对.NET接口的依赖。这是一种在重构中经常使用的手法。</p>
<p>举一个简单的例子来说明这个问题：</p>
<div class="codearea">
<pre><span style="color: blue;">namespace </span><span style="color: #010001;">XDLL
</span>{
    <span style="color: blue;">interface </span><span style="color: #010001;">XInterface
    </span>{
        <span style="color: blue;">void </span><span style="color: #010001;">Foo</span>();
    };

    <span style="color: blue;">public class </span><span style="color: #010001;">XModule
    </span>{
        <span style="color: blue;">private </span><span style="color: #010001;">XInterface ix</span>;

        <span style="color: #010001;">XModule</span>(<span style="color: #010001;">XInterface ix</span>)
        {
            <span style="color: blue;">this</span>.<span style="color: #010001;">ix </span>= <span style="color: #010001;">ix</span>;
        }

        <span style="color: blue;">void </span><span style="color: #010001;">Foo</span>()
        {
            <span style="color: blue;">this</span>.<span style="color: #010001;">ix</span>.<span style="color: #010001;">Foo</span>();
        }
    }
}</pre>
</div>
<p>假设我们的C#模块中有一个类XModule，需要使用C++代码提供的某种功能，我们不直接调用C++代码（这产生一个.NET到C++的直接依赖），而是调用一个自己定义的接口XInterface，这个接口会被暴露给外部，C++代码实现该接口，并在初始化过程中传入.NET组件。</p>
<p>将上述依赖关系变成下面这样：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/12/image1.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://www.windameister.org/blog/wp-content/uploads/2010/12/image_thumb1.png" border="0" alt="image" width="537" height="270" /></a></p>
<p>## 理想的情况当然是引擎用C++实现，而后底层提供一个C++CLI的封装，这样编辑器以及上层控件都采用C#开发，既可以兼顾引擎部分的运行效率与编辑器的开发效率，这样就可以保证依赖关系始终是上层编辑器直接依赖引擎。但是如果遇到某些现实状况，例如编辑器已经由C++开发，后期的部分控件界面期望采用C#开发，这样就需要采用类似于上文中的方案，将依赖关系反过来处理。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2010/12/19/from-cpp-to-csharp-cross-the-boundary-of-native-and-managed-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在3D游戏中采用场景管理的意义</title>
		<link>http://www.windameister.org/blog/2010/11/14/value-of-scene-management-in-3d-game/</link>
		<comments>http://www.windameister.org/blog/2010/11/14/value-of-scene-management-in-3d-game/#comments</comments>
		<pubDate>Sun, 14 Nov 2010 13:13:45 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[3D渲染]]></category>
		<category><![CDATA[网络游戏]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[场景管理]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2010/11/14/%e5%9c%a83d%e6%b8%b8%e6%88%8f%e4%b8%ad%e9%87%87%e7%94%a8%e5%9c%ba%e6%99%af%e7%ae%a1%e7%90%86%e7%9a%84%e6%84%8f%e4%b9%89/</guid>
		<description><![CDATA[我们常说3D引擎应当包含若干功能：材质，模型，动画等等，这些功能我们很好理解，模型是我们需要渲染的几何体，材质表现的是几何体如何对光照如何做出回应，动画（特别的，骨骼动画）往往是3D世界中可运动模型的基础。除了这些与渲染直接关联的概念之外，往往还有个与渲染看似无关的概念：场景管理。 游戏渲染当中常用的场景管理往往被称为Scene Graph：它的实现通常采用树状结构，构成它的基本单位是节点，一个节点可以有若干个子节点，并且（除了根节点之外）往往有且只有一个父节点。 在实际游戏当中，对于需要渲染的几何体，比如静态的Mesh或者有Skeleton的Mesh，其本身不包含世界变换信息，而是由其所处的节点决定其位置与朝向。很久以前读Ogre的源码看到它就是这么做的，然而问题是，为什么必须要这么做？我一直心存疑惑，如果不采用Scene Graph的方案，我们给每一个需要渲染的模型赋予世界变换信息，那么这个模型不是一样可以渲染么？为什么非要把变换信息与模型本身分离开？分开有什么好处？而不这样做又有什么缺点呢？ 以下是我对该问题做的小结： 问题1：视锥裁剪 采用了Scene Graph，提供层级结构之后，就可以高效的进行视锥裁剪：（更新父节点的包围盒时需要囊括其所有子节点的包围盒）如果父节点无法被看见，那么其所有子节点也都无法被看见。这样，如果一个节点有繁多（数以百计）的子孙节点，我们可以节约很多计算。 如果没有层级结构——我们采用线性表之类的数据结构，那么需要依此遍历所有物体，并依次根据其包围盒判断可见性。 这两个方案的优劣在场景不够复杂时很难分辨，但是显而易见，随着场景复杂度的增加，场景中的物体树N越大，采用层级结构的优势就越明显。 问题1衍生：碰撞检测支持 碰撞检测是比较耗时的算法，在游戏当中，如果一次碰撞检测需要计算的物体太多，会极大的影响效率，因此，与渲染时做可见性判断类似，碰撞检测也需要在进行计算之前尽可能多的剔除无关物体。 采用层级结构的场景，可以为碰撞检测提供天然的支持，如果父节点不与物体相交，那么自然其所有子节点都不会与之相交。 问题2：资源共享 有时候我们会遇到这种需求：需要在Pos[1], Pos[2], … , Pos[N]处渲染同一个Mesh，Mesh的几何数据是一样的，而变换矩阵不同。（这里不考虑Instancing的方案） 如果没有采用Scene Graph的分离变换信息与几何数据的方案，那么我们会遇到一个尴尬的局面：重复。 下面一个例子摘自SceneGraph的Wiki，生动的描述了这个问题： For instance, a game might define a logical relationship between a knight and a horse so that the knight is considered an extension to the horse. The scene graph would have a [...]]]></description>
			<content:encoded><![CDATA[<p>我们常说3D引擎应当包含若干功能：材质，模型，动画等等，这些功能我们很好理解，模型是我们需要渲染的几何体，材质表现的是几何体如何对光照如何做出回应，动画（特别的，骨骼动画）往往是3D世界中可运动模型的基础。除了这些与渲染直接关联的概念之外，往往还有个与渲染看似无关的概念：场景管理。</p>
<p>游戏渲染当中常用的场景管理往往被称为Scene Graph：它的实现通常采用树状结构，构成它的基本单位是节点，一个节点可以有若干个子节点，并且（除了根节点之外）往往有且只有一个父节点。</p>
<p>在实际游戏当中，对于需要渲染的几何体，比如静态的Mesh或者有Skeleton的Mesh，其本身不包含世界变换信息，而是由其所处的节点决定其位置与朝向。很久以前读Ogre的源码看到它就是这么做的，然而问题是，为什么必须要这么做？我一直心存疑惑，如果不采用Scene Graph的方案，我们给每一个需要渲染的模型赋予世界变换信息，那么这个模型不是一样可以渲染么？为什么非要把变换信息与模型本身分离开？分开有什么好处？而不这样做又有什么缺点呢？</p>
<p><span id="more-237"></span></p>
<p>以下是我对该问题做的小结：</p>
<p><strong>问题1</strong><strong>：视锥裁剪</strong></p>
<p>采用了Scene Graph，提供层级结构之后，就可以高效的进行视锥裁剪：（更新父节点的包围盒时需要囊括其所有子节点的包围盒）如果父节点无法被看见，那么其所有子节点也都无法被看见。这样，如果一个节点有繁多（数以百计）的子孙节点，我们可以节约很多计算。</p>
<p>如果没有层级结构——我们采用线性表之类的数据结构，那么需要依此遍历所有物体，并依次根据其包围盒判断可见性。</p>
<p>这两个方案的优劣在场景不够复杂时很难分辨，但是显而易见，随着场景复杂度的增加，场景中的物体树N越大，采用层级结构的优势就越明显。</p>
<p><strong>问题1</strong><strong>衍生：碰撞检测支持</strong></p>
<p>碰撞检测是比较耗时的算法，在游戏当中，如果一次碰撞检测需要计算的物体太多，会极大的影响效率，因此，与渲染时做可见性判断类似，碰撞检测也需要在进行计算之前尽可能多的剔除无关物体。</p>
<p>采用层级结构的场景，可以为碰撞检测提供天然的支持，如果父节点不与物体相交，那么自然其所有子节点都不会与之相交。</p>
<p><strong>问题2</strong><strong>：资源共享</strong></p>
<p>有时候我们会遇到这种需求：需要在Pos[1], Pos[2], … , Pos[N]处渲染同一个Mesh，Mesh的几何数据是一样的，而变换矩阵不同。（这里不考虑Instancing的方案）</p>
<p>如果没有采用Scene Graph的分离变换信息与几何数据的方案，那么我们会遇到一个尴尬的局面：重复。</p>
<p>下面一个例子摘自<a href="http://en.wikipedia.org/wiki/Scene_graph">SceneGraph的Wiki</a>，生动的描述了这个问题：</p>
<blockquote><p>For instance, a game might define a logical relationship between a knight and a horse so that the knight is considered an extension to the horse. The scene graph would have a &#8216;horse&#8217; node with a &#8216;knight&#8217; node attached to it.</p>
<p>As well as describing the logical relationship, the scene graph may also describe the spatial relationship of the various entities: the knight moves through 3D space as the horse moves.</p>
<p>In these large applications, memory requirements are major considerations when designing a scene graph. For this reason many large scene graph systems use instancing to reduce memory costs and increase speed. <strong>In our example above, each knight is a separate scene node, but the graphical representation of the knight (made up of a 3D mesh, textures, materials and shaders) is instanced. This means that only a single copy of the data is kept, which is then referenced by any &#8216;knight&#8217; nodes in the scene graph. This allows a reduced memory budget and increased speed, since when a new knight node is created, the appearance data does not need to be duplicated.</strong></p></blockquote>
<p>可能有人会说：为什么不能在一个循环里依次设置世界矩阵，并绘制Mesh？这样就不会有重复。</p>
<p>是的，如果我们可以只针对这一个Mesh渲染的话，自然没有问题——但情况往往是，我们会预先注册很多个Mesh，最后一次性批量渲染（以尽可能最小化渲染状态切换的次数）。这样就要求我们注册Mesh的时候，附带着把Mesh的Transform信息也一起带着——如果不采用SceneGraph的方案，头疼的事情来了，这个Transform信息应该存放在哪？如果把它放在Mesh里：比如Mesh有一个属性说明自己在世界空间中的位置朝向 ，那么这个Mesh就被绑定到这个位置上了！绘制N个不同位置的Mesh就需要创建N个不同的Mesh实例！这在3D渲染中是无法想象的资源浪费。最后，我们还是不得不想办法把Mesh的Transform信息与Geometry数据分开。</p>
<p>SceneGraph是如何解决问题的？很简单，由于不同的Node可以挂接同一个Mesh，这样自然就实现的几何数据，乃至纹理，材质的共享。注册渲染的时候把Node注册到渲染器里就万事大吉了。</p>
<p>上述两个问题我认为是在3D游戏中采用SceneGraph的最重要的理由。</p>
<p>另，以下摘译自《<a href="http://book.douban.com/subject/3554163/">3D Game Engine Design</a>》一书：</p>
<blockquote><p>采用场景图组织游戏内容，对于游戏来说非常重要，以下是原因：</p>
<p>1. 需要管理的数据通常很大，并且是有艺术家通过小片小片的形式建造出来的。关卡编辑者可以将一整个关卡的内容，通过树结构聚合起来，则自然的由此结构造出了整体性的结构。譬如，场景中的一盏灯可以只照亮场景图中的某个子树。关卡编辑者的责任就是将该灯赋予场景图中的某个节点，该灯的效果就由场景管理系统来维护。</p>
<p>2. 层次组织结构提供了一个局部性的模式：通常游戏中存在当前交互的对象，都处在相同的空间范围内。场景图可以使得游戏程序快速的排除游戏的其他区域，从而加速后续的处理。尽管将尽可能少的数据传送至显卡是让游戏运行效率提高的主要目标，但是聚焦处理小块的数据，也对碰撞检测尤为重要。如果潜在可碰撞物体特别多的话，那么碰撞检测模块也会变得非常慢。场景图可以将一组潜在需碰撞的物体组织起来，这些物体仅在当前游戏交互区域内被考虑进来。</p>
<p>3. 很多物体天然就被用层次结构搭建起来：譬如绝大多数类人体的骨架系统。手部的位置和朝向，自然的决定于腕部，肘部以及肩部的位置和朝向。</p>
<p>4. 有持久化需要的游戏，有的时候玩家需要在某一时刻将游戏状态储存起来，并在将来从此状态继续。层次化组织结构可以使得存储世界的状态非常简单：要求根节点存储自己，然后后续的就是递归的存储每一个节点即可。</p></blockquote>
<p><strong>关于Scene Graph </strong><strong>的实现：</strong></p>
<p>SceneGraph的好处众多，但重要的问题是，维护这样一个数据结构需要的代价有多大？</p>
<p>最简单的Scene Graph就直接采用线性表，渲染，碰撞检测，都采取线性遍历即可，维护也极其简单，一个Node的移动旋转不会对其他Node产生任何影响（因为没有父子关系），因此也无需维护。对于小规模的场景，这种方案是可以接受的。但是当场景规模增大时，在可见性判断，碰撞检测等问题上，线性表的实现就表现出很大的局限性了。</p>
<p>因此比较常见的SceneGraph实现是一棵树，由Node构成，每个Node都可以挂接可渲染对象Object，并且可以有多个子Node，有且只有一个Parent Node。Node上挂接的可渲染对象决定了该Node的包围体。</p>
<p>当有Node的位置移动/朝向改变时（位于其局部坐标系内）一方面，从该Node出发，其父节点直至根节点的包围体都需要更新；另一方面，其所有的子孙节点的世界变换也需要更新以适应该节点的新位置朝向信息。</p>
<p>可能有不止一处改变在SceneGraph中的不同Node上同时发生，SceneGraph管理机制应当保证仅维护必要的节点：举例而言，如果A，B两个节点都有局部坐标变换发生，并且如果B是A的子孙节点，那么更新A的子树会自动更新B的子树，因此如果我们先更新B子树，再更新A子树，则会导致多余的计算，造成不必要的效率损失。</p>
<p>参考资料：</p>
<p>1.《3D Game Engine Desion》 Eberly, D.H <a href="http://book.douban.com/subject/3554163/">http://book.douban.com/subject/3554163/</a></p>
<p>2. Wiki SceneGraph <a href="http://en.wikipedia.org/wiki/Scene_graph">http://en.wikipedia.org/wiki/Scene_graph</a></p>
<p>3. <a href="http://www.gamerendering.com/category/scene-management/">http://www.gamerendering.com/category/scene-management/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2010/11/14/value-of-scene-management-in-3d-game/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>D3D基础 – 光照，材质与着色#1</title>
		<link>http://www.windameister.org/blog/2010/09/18/d3dbasic-lighting-material-shading/</link>
		<comments>http://www.windameister.org/blog/2010/09/18/d3dbasic-lighting-material-shading/#comments</comments>
		<pubDate>Sat, 18 Sep 2010 04:22:25 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[3D渲染]]></category>
		<category><![CDATA[shader]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[d3d]]></category>
		<category><![CDATA[lighting]]></category>
		<category><![CDATA[pileline]]></category>
		<category><![CDATA[shading]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2010/09/18/d3d%e5%9f%ba%e7%a1%80-%e5%85%89%e7%85%a7%ef%bc%8c%e6%9d%90%e8%b4%a8%e4%b8%8e%e7%9d%80%e8%89%b2/</guid>
		<description><![CDATA[初接触d3d时，相信许多初学者和我一样，虽然对3D实时渲染的原理有所了解，但是却对整体的管线结构有所困惑，包括可能许多做3d游戏的程序员，由于常常采用封装好的引擎做上层逻辑开发，因此对底层的架构也未必了解得十分透彻。 长久以来，对3d图形学的底层技术，我一直也是只了解个只鳞半爪而已，最近一段时间，在工作中不断的接触到这方面的知识，才有了比较系统的思考与总结，本文记叙了我学习dx管线的一些思考，由于水平所限以及尚未对最新的DX11架构有所关注，所以本文不涵盖DX11的最新架构，只涉及DX9及以前的知识结构，虽然如此，但是相信如果系统的掌握了这块知识，对了解后续的新技术也是有所帮助的。 本文主要是针对对3D渲染知识有一定了解，然而对D3D的结构却不是很清楚的同学，把DX8/9的管线结构做了一番说明，将固定管线的光照、纹理混合与可编程管线加以对比，期望对这一块知识有一个比较完整的总结。 &#160; 目录 1. 硬件加速的3D渲染 2. 材质与光照 3. 变换，光照与顶点着色器 4. 纹理与像素着色器 5. Alpha测试，深度测试与Alpha混合 6. 更多话题 1. 硬件加速的3D渲染 硬件加速的3D渲染，早些时候只是被称为Hardware Transform &#38; Lighting的加速技术，这些技术是相对于早期时候，图形硬件尚未普及，软件实现的实时3d游戏中常用的软件变换与光照而言的。因此，最早的显卡最主要的目标也就是通过硬件来加速顶点变换，和顶点光照（如果严格来说，纹理采样应该也要算在内），从DX的固定管线接口中可以看出这一点，在固定管线中，通过SetTransform来设置变换矩阵，通过SetMaterial来设置材质属性，SetLight来设置光源参数，最后一个DrawPirmitive把三角形画到表面上去。 这几个步骤分别都是什么意思？接下来我会一一分说。 对于3D图形学有所了解的同学应当知道，绘制3D画面时，我们需要几样东西： 1) 所要绘制的目标：一个Mesh网格（包含了若干顶点，若干索引，实际构成为一个个三角形） 2) 物体的世界变换矩阵：通常我们表示一个3d物体（比如一个Mesh）的时候，都是用Local坐标系进行表示，实际渲染时，再乘上变换矩阵得到其在世界中的位置。这种做法有什么好处？或者是否非如此不可？读者可以想一想，其实原因非常简单。 : ) 3) 摄像机与视口：我们如何去看待三维世界中的物体，摄像机定义了我们观察物体的位置，角度，以及远近变换的程度 上述三样东西是必须的，有了相机和绘制目标，以及绘制目标的世界矩阵，我们就可以进行3D绘制了。但是想要获得更加具有真实感的图像，我们需要给绘制目标加上光照（注意，光照不等同于阴影，尽管当我们要实施阴影的时候，也往往是按照光照时设置的光源来绘制阴影的）此处所说的光照是指顶点光照，根据光源与顶点的相对位置，顶点的法线朝向，以及物体的受光材质决定最终的顶点颜色。一个简单的光照函数类似下面这样： DiffuseColor = Clamp(DotProduct(VertexNormal, VertexToLightDir), 0, 1) * LightColor * MaterialColor + Ambient Clamp函数保证点积的结果在[0.0, 1.0]区间内 上面的这个函数没有考虑光源衰减，灯光范围，不考虑SpotLight的衰减，另外只涉及漫反射光照，高光则需另外计算。但是从原理上已经可以说明（顶点）光照是怎么一回事了。这里强调顶点光照，是相对于像素光照来说的，顶点光照与像素光照后文会详述。 公式中提到的VertexToLightDir, LightColor属于光源的属性，在D3D9中则是由D3DLIGHT9来描述的，通过D3DDevice::SetLight接口进行设置。而MaterialColor属于材质属性，描述结构为D3DMATERIAL9，通过SetMaterial设置。 这样我们得到了绘制3D物体的另两样参数，分别为： 4) 光源：决定灯光的强度，颜色，范围，衰减等 5) [...]]]></description>
			<content:encoded><![CDATA[<p>初接触d3d时，相信许多初学者和我一样，虽然对3D实时渲染的原理有所了解，但是却对整体的管线结构有所困惑，包括可能许多做3d游戏的程序员，由于常常采用封装好的引擎做上层逻辑开发，因此对底层的架构也未必了解得十分透彻。</p>
<p>长久以来，对3d图形学的底层技术，我一直也是只了解个只鳞半爪而已，最近一段时间，在工作中不断的接触到这方面的知识，才有了比较系统的思考与总结，本文记叙了我学习dx管线的一些思考，由于水平所限以及尚未对最新的DX11架构有所关注，所以本文不涵盖DX11的最新架构，只涉及DX9及以前的知识结构，虽然如此，但是相信如果系统的掌握了这块知识，对了解后续的新技术也是有所帮助的。</p>
<p>本文主要是针对对3D渲染知识有一定了解，然而对D3D的结构却不是很清楚的同学，把DX8/9的管线结构做了一番说明，将固定管线的光照、纹理混合与可编程管线加以对比，期望对这一块知识有一个比较完整的总结。</p>
<p>&nbsp;</p>
<h5>目录</h5>
<p>1. 硬件加速的3D渲染</p>
<p>2. 材质与光照</p>
<p>3. 变换，光照与顶点着色器</p>
<p>4. 纹理与像素着色器</p>
<p>5. Alpha测试，深度测试与Alpha混合</p>
<p>6. 更多话题</p>
<p><span id="more-231"></span></p>
<h5>1. 硬件加速的3D渲染</h5>
<p>硬件加速的3D渲染，早些时候只是被称为Hardware Transform &amp; Lighting的加速技术，这些技术是相对于早期时候，图形硬件尚未普及，软件实现的实时3d游戏中常用的软件变换与光照而言的。因此，最早的显卡最主要的目标也就是通过硬件来加速顶点变换，和顶点光照（如果严格来说，纹理采样应该也要算在内），从DX的固定管线接口中可以看出这一点，在固定管线中，通过SetTransform来设置变换矩阵，通过SetMaterial来设置材质属性，SetLight来设置光源参数，最后一个DrawPirmitive把三角形画到表面上去。</p>
<p>这几个步骤分别都是什么意思？接下来我会一一分说。</p>
<p>对于3D图形学有所了解的同学应当知道，绘制3D画面时，我们需要几样东西：</p>
<p>1) 所要绘制的目标：一个Mesh网格（包含了若干顶点，若干索引，实际构成为一个个三角形）</p>
<p>2) 物体的世界变换矩阵：通常我们表示一个3d物体（比如一个Mesh）的时候，都是用Local坐标系进行表示，实际渲染时，再乘上变换矩阵得到其在世界中的位置。这种做法有什么好处？或者是否非如此不可？读者可以想一想，其实原因非常简单。 : )</p>
<p>3) 摄像机与视口：我们如何去看待三维世界中的物体，摄像机定义了我们观察物体的位置，角度，以及远近变换的程度</p>
<p>上述三样东西是必须的，有了相机和绘制目标，以及绘制目标的世界矩阵，我们就可以进行3D绘制了。但是想要获得更加具有真实感的图像，我们需要给绘制目标加上光照（注意，光照不等同于阴影，尽管当我们要实施阴影的时候，也往往是按照光照时设置的光源来绘制阴影的）此处所说的光照是指顶点光照，根据光源与顶点的相对位置，顶点的法线朝向，以及物体的受光材质决定最终的顶点颜色。一个简单的光照函数类似下面这样：</p>
<p>DiffuseColor = Clamp(DotProduct(VertexNormal, VertexToLightDir), 0, 1) * LightColor * MaterialColor + Ambient</p>
<p><em>Clamp函数保证点积的结果在[0.0, 1.0]区间内</em></p>
<p>上面的这个函数没有考虑光源衰减，灯光范围，不考虑SpotLight的衰减，另外只涉及漫反射光照，高光则需另外计算。但是从原理上已经可以说明（顶点）光照是怎么一回事了。这里强调顶点光照，是相对于像素光照来说的，顶点光照与像素光照后文会详述。</p>
<p>公式中提到的VertexToLightDir, LightColor属于光源的属性，在D3D9中则是由D3DLIGHT9来描述的，通过D3DDevice::SetLight接口进行设置。而MaterialColor属于材质属性，描述结构为D3DMATERIAL9，通过SetMaterial设置。</p>
<p>这样我们得到了绘制3D物体的另两样参数，分别为：</p>
<p>4) 光源：决定灯光的强度，颜色，范围，衰减等</p>
<p>5) 材质：决定物体受光的颜色，比如是绿色的物体，或红色的物体等。</p>
<p>有了光源和材质，绘制的3D物体则有了明暗和颜色，这对于提升渲染的真实感是有很大帮助的。</p>
<p>在此做一下小节：我们刚才回顾了绘制3D画面时，所必要做的事情，我们想象一下，如果没有3D硬件，或者不利用D3D，要实现上述功能，得由我们自己去完成哪些事？</p>
<p>首先要做软件的顶点变换，对每一个顶点，使用世界矩阵把它乘到世界坐标系中，用相机参数做必要的可见性剔除，利用相机朝向与面法线朝向做隐藏面消除，用光源与材质参数对世界空间中的顶点位置做顶点光照，将世界空间中的三角形变换到屏幕空间中，利用光照得到的顶点颜色，对三角形做<a href="http://en.wikipedia.org/wiki/Gouraud_shading">Gouraud插值着色</a>，最终得到绘制在屏幕上的图像。（有一本书叫做<a href="http://book.douban.com/subject/1321769/">《3D游戏编程大师技巧》</a>，对上述过程作了非常详尽的描述）</p>
<p>好了，有了图形硬件与D3D之后，上述工作都省掉了，我们通过SetTransform来设置世界矩阵、观察矩阵和投影矩阵，通过SetMaterial/SetLight来设置材质和光源参数，然后通过DrawPrimitive来绘制三角面。图形硬件和D3D接口极大的简化了我们编写3D程序的难度，诸多繁杂的事情都被交给硬件去完成了。</p>
<p>&nbsp;</p>
<h5>2. 材质与光照</h5>
<p>前一节主要是简单介绍了一下D3D硬件都为我们做了哪些事——事实上现如今的图形硬件所完成的功能已经远远不止上述那些了。接下来一节，我准备总结一下材质与光照的细节和原理。</p>
<p>上一节简单介绍了下材质与光照，但是没有深入系统的做总结，本节准备将这个过程做一个比较系统的总结。</p>
<p>关于几种基本光源，其公式，原理，实现，可以通过<a href="http://www.cnblogs.com/miloyip/archive/2010/04/02/1702768.html">MiloYip大牛的这篇文章</a>来了解。该文中的范例是基于光线追踪渲染器实现的，因此光和影的效果直接都有了，甚至在最后一个Demo中运用多光源模拟了软阴影的绘制。然而在光栅化渲染器中，光照与材质只能解决物体的颜色以及明暗问题，不能解决影子问题。要在光栅化渲染器中实现阴影的绘制，则是另外一番话题了。</p>
<p>接下来还是借助D3D的接口来说材质。</p>
<div class="codearea linewrap">
<pre><span style="color: blue;">typedef struct </span><span style="color: #010001;">_D3DMATERIAL9 </span>{
    <span style="color: #010001;">D3DCOLORVALUE   Diffuse</span>;        <span style="color: green;">/* Diffuse color RGBA */
    </span><span style="color: #010001;">D3DCOLORVALUE   Ambient</span>;        <span style="color: green;">/* Ambient color RGB */
    </span><span style="color: #010001;">D3DCOLORVALUE   Specular</span>;       <span style="color: green;">/* Specular 'shininess' */
    </span><span style="color: #010001;">D3DCOLORVALUE   Emissive</span>;       <span style="color: green;">/* Emissive color RGB */
    </span><span style="color: blue;">float           </span><span style="color: #010001;">Power</span>;          <span style="color: green;">/* Sharpness if specular highlight */
</span>} <span style="color: #010001;">D3DMATERIAL9</span>;</pre>
</div>
<p>材质描述了物体是如何对光作出响应的。虽然在可编程管线中，材质、光照都有自定义的实现方法，然而在固定管线中，光照采用的都是D3D所固有的一套机制，D3D中的最终光照结果由下式构成：</p>
<p>Global Illumination = Ambient Light + Diffuse Light + Specular Light + Emissive Light</p>
<p>环境光（Ambient Light）的计算方法为：Ambient Lighting = <a href="http://msdn.microsoft.com/en-us/library/bb172256(VS.85).aspx"><img src="http://latex.codecogs.com/gif.latex?C_{a}%20*%20[G_{a}%20+%20\sum%20\left%20(%20Atten_{i}%20*%20Spot_{i}%20*%20L_{ai}%20\right%20)]" alt="" /></a></p>
<p>其中C<sub>a</sub>为材质的Ambient分量，G<sub>a</sub>为全局环境光颜色（通过ID3DDevice9::SetRenderState(D3DRS_AMBIENT, COLOR)设置全局环境光颜色），求和的部分是所有被激活的光源的环境光进行求和，光源的衰减，聚光灯的Factor（如果是聚光灯）会被考虑在内。</p>
<p>漫反射光（Diffuse Light）的计算方法：Diffuse Lighting = <a href="http://msdn.microsoft.com/en-us/library/bb219656(VS.85).aspx"><img src="http://latex.codecogs.com/gif.latex?\sum%20(C_{d}%20*%20L_{d}%20*%20(N%20\cdot%20L_{dir}))%20*%20Atten%20*%20Spot)" alt="" /></a></p>
<p>解释一下这个方程，其中C<sub>d</sub>是材质的DiffuseColor，L<sub>d</sub>是光的DiffuseColor，N是顶点法线，L<sub>dir</sub>是从顶点到光源的方向向量（N与L<sub>dir</sub>都是单位向量），再乘以光源的衰减参数，及SpotLight的因子。这里的N<sup>.</sup>L<sub>dir</sub>正是计算漫反射光强弱的关键，一个顶点是否能被光源照亮，取决于该点法线与光方向的夹角，如果两者重合，该点受光程度达到最大，如果夹角大于等于90度，则不受光。</p>
<p>高光（Specular Light）的计算方法：Specular Lighting = <a href="http://msdn.microsoft.com/en-us/library/bb147399(VS.85).aspx"><img src="http://latex.codecogs.com/gif.latex?C_{s}%20*%20\sum%20[L_{s}%20*%20(N%20\cdot%20H)^{p}%20*%20Atten%20*%20Spot]" alt="" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>C<sub>s</sub>是材质的Specular值，p是材质中的Power，L<sub>s</sub>是灯光的Specular值，N是顶点法线，H是一个被称为Halfway vector的单位方向，该向量的含义为顶点到摄像机的向量与顶点到光源的向量的中间向量，计算方式为（H = norm(norm(C<sub>p</sub> &#8211; V<sub>p</sub>) + L<sub>dir</sub>)）</p>
<p>关于Halfway vector的含义，可以参考下图：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/09/halfwayvector.png"><img style="display: inline; border-width: 0px;" title="halfwayvector" src="http://www.windameister.org/blog/wp-content/uploads/2010/09/halfwayvector_thumb.png" border="0" alt="halfwayvector" width="244" height="244" /></a></p>
<p>仔细思考一下我们就能明白，相比将入射光向各个方向均匀反射的漫反射而言（对方向不敏感），高光对视线与反射光线方向是敏感的，也就是说，从眼睛到顶点与反射光方向的夹角越小就会越亮，日常生活中我们往往可以在光滑表面看到高光现象，比如汽车表面的喷漆或者玻璃。</p>
<p>最后一个是自发光，自发光很简单，就直接等于材质参数中的Emissive分量：Emissive Lighting = C<sub>e</sub></p>
<p>上述这些就是D3D固定管线中材质与光照的工作原理。其实所有的公式都可以在DXSDK的文档中获取到，这里不过是简单总结了一下。</p>
<p>前面所描述的这些材质与光照，依赖于正确的输入，比如顶点法线：漫反射和高光的计算都要依赖于顶点法线。我们都知道D3D有自定义的顶点格式，被称为FVF的东西。那么也就是说，如果想要正确的使用D3D顶点光照，我们采用的顶点格式，应当至少包含法线（D3DFVF_NORMAL）。</p>
<p>我们也常见到不包含法线，而是包含漫反射颜色（D3DFVF_DIFFUSE）和高光色彩（D3DFVF_SPECULAR）的顶点格式，采用这种顶点格式往往意味着我们准备自行为顶点填充颜色，而不采用D3D光照。</p>
<p>&nbsp;</p>
<h5>3. 变换，光照与顶点着色器</h5>
<p>要说顶点着色器，则不得不从固定管线与顶点格式说起。D3D中有所谓的Flexible Vertex Format，也就是大名鼎鼎的FVF常量。我们常见的D3DFVF_DIFFUSE，D3DFVF_XYZ，D3DFVF_NORMAL都是定义好的常量，在需要用的时候，我们把这些常量“或”在一起，构成一个顶点格式，传递给D3D使用。D3D固定管线通过该FVF格式对我们传入的VertexBuffer进行解释（每份顶点数据的长度，以及每个成员的偏移）。</p>
<p>起初学习D3D的时候，我对FVF格式有个疑惑，百思而不得其解。我们都知道要写一个普通的具有位置，法线和UV的顶点格式声明应该怎么写：</p>
<div class="codearea linewrap">
<pre><span style="color: blue;">#define </span><span style="color: #010001;">MY_VERTEX_FVF D3DFVF_XYZ </span>| <span style="color: #010001;">D3DFVF_NORMAL </span>| <span style="color: #010001;">D3DFVF_TEX0

</span><span style="color: blue;">struct </span><span style="color: #010001;">VERTEX
</span>{
    <span style="color: blue;">float </span><span style="color: #010001;">x</span>, <span style="color: #010001;">y</span>, <span style="color: #010001;">z</span>;
    <span style="color: blue;">float </span><span style="color: #010001;">nx</span>, <span style="color: #010001;">ny</span>, <span style="color: #010001;">nz</span>;
    <span style="color: blue;">float </span><span style="color: #010001;">u</span>, <span style="color: #010001;">v</span>;
};</pre>
</div>
<p>我觉得很奇怪，D3D怎么知道我把x，y，z放在前面还是把nx，ny，nz放在前面，难道是根据我定义FVF时的先后顺序？明显讲不通啊：因为或运算不可能给出任何先后顺序的信息来的。</p>
<p>直到后来我才明白，原来D3D固定管线的顶点格式也是有固定顺序的，也就是说如果要写一个既带有位置，又带有法线的顶点数据结构，那么x，y，z一定要放在nx，ny，nz之前，或者说，D3D是根据一个固定的偏移去解释这个顶点数据结构的，首先一定是位置，然后才是法线，其他更复杂包含更多成员的数据格式也是与此同理。什么意思呢？</p>
<p>还是以上面的例子来解释，你把顶点数据结构写成下面这样（区别在于，nx，ny，nz与x，y，z调换了顺序）：</p>
<div class="codearea linewrap">
<pre><span style="color: blue;">#define </span><span style="color: #010001;">MY_VERTEX_FVF D3DFVF_XYZ </span>| <span style="color: #010001;">D3DFVF_NORMAL </span>| <span style="color: #010001;">D3DFVF_TEX0

</span><span style="color: blue;">struct </span><span style="color: #010001;">VERTEX
</span>{
    <span style="color: blue;">float </span><span style="color: #010001;">nx</span>, <span style="color: #010001;">ny</span>, <span style="color: #010001;">nz</span>;
    <span style="color: blue;">float </span><span style="color: #010001;">x</span>, <span style="color: #010001;">y</span>, <span style="color: #010001;">z</span>;
    <span style="color: blue;">float </span><span style="color: #010001;">u</span>, <span style="color: #010001;">v</span>;
};</pre>
</div>
<p>D3D会说，不好意思，我不知道你怎么命名的，也不在乎你把它叫nx还是x，反正我都把你你头三个浮点数就当作是位置，接下来三个浮点数当成是法线，只要你给我的FVF是有D3DFVF_XYZ的，那头三个浮点就是位置没跑了！</p>
<p>从上面的例子中我们可以看到，实际上固定管线的结构是很死板的，缺乏给程序员自由发挥的空间，它规定好了一系列的顶点数据的用途，然后你必须按照它指定的方式去做，否则结果就不对。</p>
<p>当然了，这也只是后来的可编程管线替代固定管线的诸多原因之一。如今我们见到的市面上的所有显卡基本上已经没有不支持可编程管线的了，而且DX也已经更新换代到了DX11，新架构与本文中所介绍的基于DX9的结构又有了很多变化。</p>
<p>继续前面所述的话题，D3DFVF格式不仅决定了顶点数据结构如何定义，也说明了顶点要如何进行坐标系变换，比如：</p>
<p>D3DFVF_XYZ说明了顶点需要进行全套的世界、观察、投影变换；</p>
<p>D3DFVF_XYZRHW则说明该顶点坐标已经是屏幕坐标，x，y表示窗口中的坐标，z值表示z-buffer中的值，从近到远为0.0~1.0，采用这种格式的顶点声明不能与D3DFVF_XYZ或者D3DFVF_NORMAL混用，并且不经过顶点处理单元；</p>
<p>D3DFVF_XYZW也是表示已经变换过后的顶点，但是这种顶点格式会经过顶点处理单元，也就是vertexshader的阶段；</p>
<p>D3DFVF_XYZBn (n=1..4) 表示该顶点在变换阶段需要进行混合，啥意思？也就是说在做变换的时候，不是一个世界矩阵对其起作用，而是有n个矩阵，根据Blend的参数共同对该顶点起作用。如下例（摘自DXSDK）：</p>
<div class="codearea linewrap">
<pre><span style="color: blue;">#define </span><span style="color: #010001;">D3DFVF_BLENDVERTEX </span>(<span style="color: #010001;">D3DFVF_XYZB3</span>|<span style="color: #010001;">D3DFVF_NORMAL</span>|<span style="color: #010001;">D3DFVF_TEX1</span>)

<span style="color: blue;">struct </span><span style="color: #010001;">BLENDVERTEX
</span>{
    <span style="color: #010001;">D3DXVECTOR3 v</span>;       <span style="color: green;">// Referenced as v0 in the vertex shader
    </span><span style="color: #010001;">FLOAT       blend1</span>;  <span style="color: green;">// Referenced as v1.x in the vertex shader
    </span><span style="color: #010001;">FLOAT       blend2</span>;  <span style="color: green;">// Referenced as v1.y in the vertex shader
    </span><span style="color: #010001;">FLOAT       blend3</span>;  <span style="color: green;">// Referenced as v1.z in the vertex shader
    // v1.w = 1.0 - (v1.x + v1.y + v1.z)
    </span><span style="color: #010001;">D3DXVECTOR3 n</span>;       <span style="color: green;">// Referenced as v3 in the vertex shader
    </span><span style="color: #010001;">FLOAT       tu</span>, <span style="color: #010001;">tv</span>;  <span style="color: green;">// Referenced as v7 in the vertex shader
</span>};</pre>
</div>
<p>也就是说v在被变换的时候，会被4个矩阵依次乘上，并将其结果使用（blend1,blend2,blend3,1-(blend1 + blend2 + blend3)）四个参数作为系数进行混合。注意一下SetTransform函数，它有两个参数，第一个参数的说明里有这么一段：</p>
<p>&nbsp;</p>
<dt><em>State</em>&nbsp;</p>
</dt>
<dd>[in] Device-state variable that is being modified. This parameter can be any member of the <a href="http://msdn.microsoft.com/en-us/library/bb172619(VS.85).aspx">D3DTRANSFORMSTATETYPE</a> enumerated type, or the <a href="http://msdn.microsoft.com/en-us/library/bb172623(VS.85).aspx">D3DTS_WORLDMATRIX</a> macro.</dd>
<dd>其中的D3DTS_WORLDMATRIX是一个宏，可以像这么用D3DTS_WORLDMATRIX(0)，D3DTS_WORLDMATRIX(1)，这样一来就可以传递多个矩阵到固定管线中了（等到可编程管线就没这么麻烦了，可以直接通过顶点着色器常量传递矩阵）。</p>
<p>最后简单说一下D3DFVF_XYZBn这种顶点格式的用途：这种顶点格式往往被用在骨骼动画的顶点里，因为骨骼动画需要一个顶点受多个骨骼的影响。</p>
<p>定义好了FVF与顶点数据结构之后，我们需要把它设置到设备上去。我们知道，早些年的DX8也好，DX9也好，其Device都有一个SetVertexShader接口，用于设置顶点着色器程序。而在DX8中，这个接口不仅仅是可编程管线的vertex shader通过它来设置，实际上如果采用的是固定管线的话，顶点的FVF格式也是走这个接口设置的。DX8中的Vertex shader创建出来之后是一个32位的DWORD类型的handle，从而得以与FVF常量共用这同一个接口。而在DX9中，SetVertexShader的接受参数变成一个<strong>IDirect3DVertexShader9*</strong>了，而固定管线的FVF被挪走，需要通过接口SetFVF来进行设置了。</p>
<p>另外，由于在DX9中，<strong>IDirect3DVertexShader9</strong>在创建的时候，并没有包含顶点声明信息，因此DX9增加了一个接口<strong>IDirect3DVertexDeclaration9</strong>专门用于为可编程管线的VertexShader提供顶点声明信息。为什么一定要有顶点声明信息呢？写过HLSL的同学都知道，我们在vertex shader里是必须要定义vs input的数据结构的，顶点声明信息必须与我们的VS_INPUT数据结构保持一致。那么这个顶点声明信息在什么时候用呢？仔细思考一下就会明白，vs是一段运行于GPU上的程序，它按照我们编写的HLSL代码接受输入，经过计算后输出，输入的数据是在顶点缓冲中准备好的，在DrawPrimitive之前，通过SetVertexBuffer设置，此后这些输入数据通过驱动程序被提供给显卡，然而底层如何知晓应把多长一截的数据作为一份输入的顶点数据呢？以及应该把顶点数据中的哪一部分送到顶点寄存器里，哪些送到纹理采样单元里去？到这里，就不得不依赖顶点声明提供的信息了。</p>
<p>前面在材质与光照一节，我们简单介绍了一下D3D固定管线光照中，材质是如何与灯光一起起作用，并作用于物体的色泽，明暗，高光的。现在当我们手握Shader这样的利器，就拥有了绕开D3D固定管线光照的自由了（譬如如今已经很普及的基于像素的光照技术，就是把光照从顶点着色阶段推迟至像素着色器中）。我们还可以利用顶点着色器的常量传递变换矩阵，从而拥有自定义顶点变换，或者在顶点变换阶段获取一些我们想要的中间结果的能力。</p>
<h5>4. 纹理与像素着色器</h5>
<p>前面说了关于顶点变换与顶点光照相关的东西。接下来要说的是纹理混合，也就是SetTextureStageState函数干的事情。我们都知道DX支持纹理混合，我们可以把多个纹理按照Sampler的索引(DX9中是Sampler，而在DX8中则是Stage)，通过SetTexture函数设置到设备上。</p>
<p>&nbsp;</p>
<p>所谓Stage是什么一个概念呢？参考下图（来源于DX9SDK）：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/09/dx_texture_stage.png"><img style="display: inline; border-width: 0px;" title="dx_texture_stage" src="http://www.windameister.org/blog/wp-content/uploads/2010/09/dx_texture_stage_thumb.png" border="0" alt="dx_texture_stage" width="400" height="393" /></a></p>
<p>在每一个Stage上设有一张纹理（如果没有设置纹理），在固定管线中，我们通过<strong>SetTextureStageState</strong>设置在当前的Stage中，纹理如何与“当前像素”混合并输出到下一个Stage，“当前像素”来源于上一个Stage的输出，0Stage的当前像素的Color及Alpha是顶点Color/Alpha插值得来的。在纹理阶段比较常见的就是DiffuseTexture，SpecularTexture，分别用于颜色与高光。在每一个Stage中，纹理颜色与上一阶段颜色采用下式进行混合：</p>
</dd>
<p><em>FinalColor = TexelColor × SourceBlendFactor + PixelColor × DestBlendFactor</em></p>
<p>这里需要注意的是，纹理混合与最终的AlphaBlending是两个概念。纹理混合阶段，根据顶点颜色以及纹理决定最终要输出的像素的颜色和透明度，而到了AlphaBlending阶段，则是决定该像素与已经绘制到BackBuffer上的像素如何去混合。此外，更复杂的功能如NormalMapping，通常则需要像素着色器参与。按照我的理解，如果想要实现像素光照，则必须把光照阶段从顶点着色器中推迟到像素着色器中才可行，NormalMap提供了这一阶段每个像素的法线，从而使像素光照得以实现。（D3D9在固定管线中提供了一套<a href="http://msdn.microsoft.com/en-us/library/bb206304(VS.85).aspx">BumpMap</a>，但是老实说，<a href="http://msdn.microsoft.com/en-us/library/bb172379(VS.85).aspx">D3D9文档里对此的说明</a>看得我云里雾里的，并没有搞清楚其原理究竟是什么。）</p>
<p>像素着色器最初的就是为了替代固定管线的纹理混合操作而诞生的。也就是说，如果采用了PixelShader对像素进行着色，那么SetTextureStageState里面的那些颜色，Alpha混合操作就不再起作用了。</p>
<p>我们以一个常见的例子来解释纹理混合的用法，美术可能要求实现一种<a href="http://en.wikipedia.org/wiki/Blend_modes#Multiply">正片叠底</a>的纹理混合效果，对于程序实现而言，实现方案就是找两张贴图，用乘法进行纹理混合。如果采用SetTextureStageState实现：</p>
<p class="codearea linewrap">&nbsp;</p>
<pre><span style="color: #010001;">pD3DDevice</span>-&gt;<span style="color: #010001;">SetTextureStageState</span>(0, <span style="color: #010001;">D3DTSS_COLOROP</span>, <span style="color: #010001;">D3DTOP_SELECTARG1</span>);
<span style="color: #010001;">pD3DDevice</span>-&gt;<span style="color: #010001;">SetTextureStageState</span>(0, <span style="color: #010001;">D3DTSS_COLORARG1</span>, <span style="color: #010001;">D3DTA_TEXTURE</span>);

<span style="color: #010001;">pD3DDevice</span>-&gt;<span style="color: #010001;">SetTextureStageState</span>(1, <span style="color: #010001;">D3DTSS_COLOROP</span>, D<span style="color: #010001;">3DTOP_MODULATE</span>);
<span style="color: #010001;">pD3DDevice</span>-&gt;<span style="color: #010001;">SetTextureStageState</span>(1, <span style="color: #010001;">D3DTSS_COLORARG1</span>, <span style="color: #010001;">D3DTA_TEXTURE</span>);
<span style="color: #010001;">pD3DDevice</span>-&gt;<span style="color: #010001;">SetTextureStageState</span>(1, <span style="color: #010001;">D3DTSS_COLORARG2</span>, <span style="color: #010001;">D3DTA_CURRENT</span>);</pre>
<p>&nbsp;</p>
<p>解释一下这里的两个StageState的设置：阶段0，我们对Color采用SELECTARG1操作，同时把COLORARG1，设置为D3DTA_TEXTURE，也就是说，完全以SetTexture(0, …)设置的纹理颜色作为这一阶段的输出；在阶段1，COLOROP为MODULATE，也就是将COLORARG1与COLORARG2相乘作为输出，公式：<img src="http://latex.codecogs.com/gif.latex?S_{rgba}%20=%20Arg1%20\times%20Arg2" alt="" /></p>
<p>&nbsp;</p>
<p>其中COLORARG1设置为D3DTA_TEXTURE，也就是SetTexture(1, …)中设置的纹理，而COLORARG2为D3DTA_CURRENT，表示的是上一阶段的输出。这样经过这两个Stage之后，我们获得的输出就是两张贴图相乘的结果了。</p>
<p>接下来再用Ps2.0（需要DX9，如果采用DX8则需用ps1.4实现）实现一遍该效果：</p>
<p class="codearea">&nbsp;</p>
<pre><span style="color: #010001;">texture g_Tex0</span>;
<span style="color: #010001;">texture g_Tex1</span>;
<span style="color: #010001;">sampler g_Sampler0 </span>= <span style="color: #010001;">sampler_state </span>{<span style="color: #010001;">Texture </span>= <span style="color: #010001;">g_Tex0</span>; <span style="color: #010001;">MipFilter </span>= <span style="color: #010001;">LINEAR</span>; <span style="color: #010001;">MinFilter </span>= <span style="color: #010001;">LINEAR</span>; <span style="color: #010001;">MagFilter </span>= <span style="color: #010001;">LINEAR</span>;}
<span style="color: #010001;">sampler g_Sampler1 </span>= <span style="color: #010001;">sampler_state </span>{<span style="color: #010001;">Texture </span>= <span style="color: #010001;">g_Tex1</span>; <span style="color: #010001;">MipFilter </span>= <span style="color: #010001;">LINEAR</span>; <span style="color: #010001;">MinFilter </span>= <span style="color: #010001;">LINEAR</span>; <span style="color: #010001;">MagFilter </span>= <span style="color: #010001;">LINEAR</span>;}

<span style="color: blue;">struct </span><span style="color: #010001;">VS_OUTPUT
</span>{
    <span style="color: #010001;">float4 Position   </span>: <span style="color: #010001;">POSITION</span>;   <span style="color: green;">// vertex position
    </span><span style="color: #010001;">float2 TexCoord   </span>: <span style="color: #010001;">TEXCOORD0</span>;  <span style="color: green;">// vertex texture coords
</span>};

<span style="color: #010001;">float4 PS_Main_2_0</span>( <span style="color: #010001;">VS_OUTPUT Input </span>) : <span style="color: #010001;">COLOR0
</span>{
    <span style="color: #010001;">float4 color0 </span>= <span style="color: #010001;">tex2D</span>( <span style="color: #010001;">g_Sampler0</span>, <span style="color: #010001;">Input</span>.<span style="color: #010001;">TexCoord </span>);
    <span style="color: #010001;">float4 color1 </span>= <span style="color: #010001;">tex2D</span>( <span style="color: #010001;">g_Sampler1</span>, <span style="color: #010001;">Input</span>.<span style="color: #010001;">TexCoord </span>);
    <span style="color: blue;">return </span><span style="color: #010001;">float4</span>(<span style="color: #010001;">color0 </span>* <span style="color: #010001;">color1</span>);
}</pre>
<p>&nbsp;</p>
<p>使用ps的话，所需要做的工作非常直观，用预先定义好的<a href="http://msdn.microsoft.com/en-us/library/bb509644(VS.85).aspx">Sampler</a>以及uv坐标对纹理采样，并把颜色相乘输出即可。</p>
<p>这只是一个最简单的例子，实际上ps的用途非常广泛（实现ShaderMap，像素光照，诸多后期处理效果都需要采用ps实现），而更多的内容就不可能涵盖在本文的范围之内了，感兴趣的读者可以读一读GPUGems系列，ShaderX系列等经典书籍。</p>
<h5>5. Alpha测试，深度测试，以及Alpha混合</h5>
<p>走完了像素着色的过程之后，就到了最终的绘制步骤了。这里有几个因素决定我们是否，以及如何往BackBuffer/ZBuffer/StencilBuffer上绘制像素：AlphaTest，StencilTest，ZTest，Alpha混合模式。</p>
<p>关于上述测试的顺序和流程，由于OpenGl与D3D在上述测试的顺序上达成了一致，因此可以参考下图（图摘自<a href="http://www.opengl.org/documentation/specs/version2.0/glspec20.pdf">OpenGL2.0 spec Page 199</a>）：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/09/PreFragmentOperations.png"><img style="display: inline; border-width: 0px;" title="Pre-FragmentOperations" src="http://www.windameister.org/blog/wp-content/uploads/2010/09/PreFragmentOperations_thumb.png" border="0" alt="Pre-FragmentOperations" width="648" height="492" /></a></p>
<p>如果开启了AlphaTest，则首先做AlphaTest，根据像素的Alpha值与一个指定的D3DRS_ALPHAREF值比较的结果，将D3DRS_ALPHAFUNC的判断未能通过的像素直接砍掉。（不会进行后续的z-test以及z-write）</p>
<p>如果开启了StencilTest，则继续做StencilTest，如果不通过StencilTest，则也不会进行下一步ZTest，但是可能会修改StencilBuffer。</p>
<p>如果开启了ZTest，根据当前像素Z值，与DepthBuffer上该位置已有Z值做比较，如果D3DRS_ZFUNC的判断未能通过，则将该像素砍掉，但是根据D3DRS_STENCILZFAIL的状态，有可能会修改StencilBuffer。通过了ZBuffer的像素，如果开启了ZWrite，则该像素的Z值会写入DepthBuffer，否则（ZWrite关闭）该像素不会影响DepthBuffer（也就是说不会遮挡后续绘制的像素，尽管可能该像素离观察者比将来要绘制的像素更近）</p>
<p>最后根据D3DRS_ALPHABLENDENABLE决定是否开启Alpha混合。如果Alpha混合没有开启：则直接把像素的颜色透明度写入BackBuffer，如果Alpha混合开启了，则根据D3DRS_SRCBLEND以及D3DRS_DESTBLEND的选项，决定新写入像素如何与BackBuffer已有像素进行混合。</p>
<p>上述流程是标准流程，然而在较新的几代显卡里，针对StencilTest与ZTest又有了许多新的技术，比如EarlyZ优化等，由于这里牵扯到的显卡型号，各厂商可能都有不一致的地方，我就没有做更进一步的详细研究。下面有几个可以供参考的链接，感兴趣的同学可以自己了解一下：</p>
<p>amddeveloper的一篇文章在这里：<a href="http://developer.amd.com/media/gpu_assets/Depth_in-depth.pdf">http://developer.amd.com/media/gpu_assets/Depth_in-depth.pdf</a></p>
<p>beyond3d上的一个讨论帖看这里：<a href="http://forum.beyond3d.com/showthread.php?t=51025">http://forum.beyond3d.com/showthread.php?t=51025</a></p>
<p>&nbsp;</p>
<h5>6. 更多话题</h5>
<p>本文介绍了D3D流水线的一般过程，对比了固定管线与可编程管线的差别（当然有很多细节未能兼顾到），对D3D渲染流程的知识结构做了一个一般性的总结。</p>
<p>事实上，随着图形技术的发展，如今的3D图形技术已远走出很长一段路了，比如在DX9架构下就已经发展出很多成果的ShadowMap，NormalMap，Realtime Global Illumination等。再比如到DX10新增的Geometry Shader以及DX11架构下新增的Compute Shader，Tessellation等。</p>
<p>有时候学得越多，才越知道自己所知甚少。在撰写本文的过程中，我也把此前有些混淆的概念做了整理，自己也有不少收获。如果读者对本文所涉的话题有更多理解，或者发现了错漏之处，还望不吝告知。 : )</p>
<p>&nbsp;</p>
<p>#1 更正了文中的几处文字、公式错误，修改了针对高光概念的描述。(感谢<a href="http://1111h.blogspot.com/">Rainsing</a>的帮助)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2010/09/18/d3dbasic-lighting-material-shading/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>溶解效果的原理与实现#1</title>
		<link>http://www.windameister.org/blog/2010/09/11/dissolve-effect-implement-in-dx9/</link>
		<comments>http://www.windameister.org/blog/2010/09/11/dissolve-effect-implement-in-dx9/#comments</comments>
		<pubDate>Sat, 11 Sep 2010 04:21:30 +0000</pubDate>
		<dc:creator>windam</dc:creator>
				<category><![CDATA[shader]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[dissolve]]></category>
		<category><![CDATA[effect]]></category>
		<category><![CDATA[pixel shader]]></category>

		<guid isPermaLink="false">http://www.windameister.org/blog/2010/09/11/%e6%ba%b6%e8%a7%a3%e6%95%88%e6%9e%9c%e7%9a%84%e5%8e%9f%e7%90%86%e4%b8%8e%e5%ae%9e%e7%8e%b0/</guid>
		<description><![CDATA[在游戏中实现溶解效果，往往有两种选择：其一是采用多重纹理；其二是采用模板缓冲。 本文说明采用多重纹理方案时如何实现溶解效果，采用模板缓冲的方案容后再补。 上图是一个利用PixelShader达成的效果，其原理是，当我们把一个面片绘制到渲染表面上时，将特定像素的Alpha值设为0，从而在绘制到表面与背景混合时，达到镂空的效果。镂空的图案由美术指定一张Mask纹理确定。譬如在上图的效果中，我利用了下面这样的两张纹理图（左图是前景贴图，右图作为Mask），美术可以通过指定不同的Mask图，实现不同类型的逐渐消解/生成的效果： 实现此效果需要两张贴图，一张是物体表面的纹理，另一张作为溶解的Mask图。 &#160; &#160; PixelShader(ps_2_0)代码如下： float g_DissolveThreshold;    // 该参数作为阈值，与mask图上的当前像素比较大小以决定像素是否镂空 float4 PS_Main_2_0( VS_OUTPUT Input ) : COLOR0 { float4 DiffuseColor = tex2D( diffuse_sampler, Input.TexCoord ); float4 TexDissolve = tex2D( mask_sampler, Input.TexCoord ); DiffuseColor.rgb = DiffuseColor.rgb * Input.Diffuse.rgb; float originalalpha = Input.Diffuse.a * DiffuseColor.a; float dissolveDelta = TexDissolve.r &#8211; g_DissolveThreshold; if (dissolveDelta &#62;= 0) DiffuseColor.a [...]]]></description>
			<content:encoded><![CDATA[<p>在游戏中实现溶解效果，往往有两种选择：其一是采用多重纹理；其二是采用模板缓冲。</p>
<p>本文说明采用多重纹理方案时如何实现溶解效果，采用模板缓冲的方案容后再补。</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/09/DissolveMiddle.jpg"><img style="display: inline; border-width: 0px;" title="Dissolve-Middle" src="http://www.windameister.org/blog/wp-content/uploads/2010/09/DissolveMiddle_thumb.jpg" border="0" alt="Dissolve-Middle" width="244" height="223" /></a></p>
<p>上图是一个利用PixelShader达成的效果，其原理是，当我们把一个面片绘制到渲染表面上时，将特定像素的Alpha值设为0，从而在绘制到表面与背景混合时，达到镂空的效果。镂空的图案由美术指定一张Mask纹理确定。譬如在上图的效果中，我利用了下面这样的两张纹理图（左图是前景贴图，右图作为Mask），美术可以通过指定不同的Mask图，实现不同类型的逐渐消解/生成的效果：</p>
<p><a href="http://www.windameister.org/blog/wp-content/uploads/2010/09/06_11_2_moon.jpg"><img style="display: inline; border-width: 0px;" title="06_11_2_moon" src="http://www.windameister.org/blog/wp-content/uploads/2010/09/06_11_2_moon_thumb.jpg" border="0" alt="06_11_2_moon" width="231" height="244" /></a> <a href="http://www.windameister.org/blog/wp-content/uploads/2010/09/dissolve.jpg"><img style="display: inline; border-width: 0px;" title="dissolve" src="http://www.windameister.org/blog/wp-content/uploads/2010/09/dissolve_thumb.jpg" border="0" alt="dissolve" width="197" height="244" /></a></p>
<p><em>实现此效果需要两张贴图，一张是物体表面的纹理，另一张作为溶解的Mask图。</em></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span id="more-220"></span></p>
<p>PixelShader(ps_2_0)代码如下：</p>
<p>float g_DissolveThreshold;    // 该参数作为阈值，与mask图上的当前像素比较大小以决定像素是否镂空</p>
<p>float4 PS_Main_2_0( VS_OUTPUT Input ) : COLOR0<br />
{<br />
float4 DiffuseColor = tex2D( diffuse_sampler, Input.TexCoord );<br />
float4 TexDissolve = tex2D( mask_sampler, Input.TexCoord );<br />
DiffuseColor.rgb = DiffuseColor.rgb * Input.Diffuse.rgb;<br />
float originalalpha = Input.Diffuse.a * DiffuseColor.a;<br />
float dissolveDelta = TexDissolve.r &#8211; g_DissolveThreshold;<br />
if (dissolveDelta &gt;= 0)<br />
DiffuseColor.a = originalalpha;<br />
else<br />
DiffuseColor.a = 0;<br />
return DiffuseColor;<br />
};</p>
<p>该函数的原理是这样的：我们在光栅化三角形的时候，通过pixelshader给当前像素着色，首先分别取得两张纹理当前颜色（通过前一阶段VS输出的uv坐标Input.TexCoord，以及Sampler进行采样，<a href="http://msdn.microsoft.com/en-us/library/bb509644(VS.85).aspx">这里的diffuse_sampler, mask_sampler是此前定义的分别针对两张纹理的Sampler</a>他们指定了针对哪个纹理采样，以及如何采样），对Mask纹理，我们只取r通道的值作为判断依据(<strong>TexDissolve.r</strong>)——通常情况下作为Mask纹理的图可以采用8bit单通道图以节省空间，采用r通道是为了简便，实际上对于灰度图而言，无论采用哪个通道都是相同的。如果传入常量g_DissolveThreshold大于TexDissolve.r，则输出像素的Alpha被置为0。</p>
<p>事实上，上述溶解效果只考虑以Alpha作为因子的Alpha混合（AlphaBlending以D3DBLEND_SRCALPHA作为混合的因子的情况），因此输出像素的Alpha被置为0即可。如果需要考虑其他的混合模式，例如D3DBLEND_SRCCOLOR，则需将输出像素整体置为0。这里涉及到Alpha混合相关的知识，我会另外撰文总结。</p>
<p>其中g_DissolveThreshold是一个Pixel Shader常量，程序逻辑中可以控制该常量的变化，而后将值传入ps，以达到不同程度的溶解。改变该变量的行为方式，则可以实现各种不同的溶解/生成效果。</p>
<p>p.s.1使用上述逻辑实现溶解效果时，可以根据g_DissolveThreshold与Mask像素差的大小，增加一些判定从而实现边缘描边，边缘淡出等效果。</p>
<p>p.s.2 如果想针对Mesh实现该效果，其原理与面片的类似，可以利用相似的办法（Mask贴图以及针对模型的PixelShader），实现模型或物体在背景中溶解消失的效果</p>
<p>p.s.3 本文中所用ps如果在dx8.1版本或之前，需要采用ps1.4，则应当利用cmp指令解决alpha值的运算问题：</p>
<p><em>; ps1.4</em></p>
<p><em>; c0 is g_DissolveThreshold</em></p>
<p><em>; c1 is (0, 0, 0, 0)</em></p>
<p><em>texld r0, t0 ; diffuse texture</em></p>
<p><em>texld r1, t1 ; mask texture</em></p>
<p><em>mul r0, r0, v0 ; diffuse texture color * vertex diffuse color</em></p>
<p><em>add r2, r1, –c0 ; sub to get the dissolve delta</em></p>
<p><em>cmp r0.a r2, r0, c1 ; cmp using r2’s value r2.a &gt;= 0? use what is there (r0.a) , otherwise use 0</em></p>
<p>#1 增加了ps1.4版本的ps。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.windameister.org/blog/2010/09/11/dissolve-effect-implement-in-dx9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

