<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[replicon日记]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[关注NetBSD和linux股票软件]]></description>
<link>http://hi.baidu.com/fatbsd</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[寻Perl程序员一名]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/c7dc27a93d95b9fb1f17a231.html]]></link>
        <description><![CDATA[
		
		<p>寻Perl程序员一名.</p>
<p>工作地点：上海</p>
<p>有意向的请联系我<a href="mailto:ityufeng@gmail.com">ityufeng  .AT.  gmail.com</a></p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/%B9%A4%D7%F7">工作</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/c7dc27a93d95b9fb1f17a231.html#comment">查看评论</a>]]></description>
        <pubDate>2008-12-24  01:07</pubDate>
        <category><![CDATA[工作]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/c7dc27a93d95b9fb1f17a231.html</guid>
</item>

<item>
        <title><![CDATA[通货膨胀与价格管制：谨防一错再错(转）]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/13be06d03a2e078aa0ec9ca9.html]]></link>
        <description><![CDATA[
		
		<p><font size="2">最近的情况是，在通胀指数继续走高的形势下，一方面货币供给的增长速度依然很快，一方面政府实施了临时价格干预措施。具体看，2008年1月CPI同比增7.1%，PPI增6.1%，而广义货币供应量（M2）增18.94%，人民币贷款增16.74％，而银行的外汇贷款增加42.59％。这是在宣布从紧的货币政策之后发生的，容易使人认为&ldquo;从紧政策&rdquo;还有灵活余地。</font></p>
<p><font size="2">也是在2008年1月，政府宣布&ldquo;对部分重要商品及服务实行临时价格干预措施&rdquo;。到1月底，全国31省市全部实施了临时价格干预。这个事情也不是那样大，因为只是临时措施，还不是价格冻结。无非就是提价要报批，不过对于敏感的商品，不那么容易批准就是了。</font></p>
<p><font size="2">这两件事看来都不大，还是小问题。但是组合到一起，小问题有变成大问题的危险。一方面，货币政策的实际动向没有充分体现从紧的决心；另一方面，对市场的相对价格又实施了某种程度的管制。这样&ldquo;松货币供给，紧价格干预&rdquo;的政策组合，不是一个好的组合。</font></p>
<p><font size="2">在认识上，还是把货币总量引起的价格总水平上涨，与相对物价变动混为一谈。近几年来，&ldquo;结构性&rdquo;思维一直流行，从&ldquo;结构性过热&rdquo;、&ldquo;结构性房地产泡沫&rdquo;、&ldquo;结构性股市泡沫&rdquo;，一直到最近的&ldquo;结构性物价上涨&rdquo;。经济生活里永远有结构性问题，但不能因此忽略对总量形势的观察和判断。比如以&ldquo;结构性物价上涨&rdquo;的角度看问题，会认为无非就是一部分物价在涨，只要对症下药，管住了这部分物价就可以解决问题。这是价格管制措施的思想根源。</font></p>
<p><font size="2">价格管制会有什么效果呢？标准的分析说，偏离市场供求决定的价管制会产生不平衡的&ldquo;缺口&rdquo;。一般而言，政府管制的价格水平如果高于市场供求价，比如市价10元的商品，政府出于某种原因认为偏低，非规定要15元才可以成交，那么这种商品的需求量就要减少，供给量就增加，于是出现供过于求的&ldquo;缺口&rdquo;。反过来，管制价格低于市价，就出现供不应求，因为此时需求变大、供给变小。</font></p>
<p><font size="2">这个分析的好处是简明，让大家直观地了解对市场价格施加管制的后果。缺点是，现实的物价管制有许多具体形式，比如有些管制措施并没有直接干预价格，只是限制市场中人的某些行为，或限制市场合约的非价格条款，等等。这些看起来不是价管的办法，最后也要影响到价格走势。这要求我们在观察现象时，作变化的处理。</font></p>
<p><font size="2">今天我们简要讨论几种商品的价格管制及其效果。第一个是电力。电是非常基础的商品，生产生活都离不开的。但是电的矛盾有多年了，主要在定价机制方面，发电用煤的价格已经放开，但电价还由政府管制。市场煤价一直在变，可是政府决定的电价就远不能灵敏反映市场供求。2004年国家发改委有一个煤电价格联动方案，规定如果市场电煤的价格上升超过5%，其中30%由发电公司自己消化，70%由国家调高电价来补。但是这个方案一直没有执行，使这几年煤电之间的矛盾年年都成为一个大问题。</font></p>
<p><font size="2">2007年以来的情况是电煤的价格大幅上升。比如浙江绍兴的电煤要820元/吨，广州更高达1000元/吨。在这个情况下维持电价不变，发电就没有积极性，政府把发电作为政治任务来部署，问题是可以坚持多久？煤与电的矛盾早就存在，本来也要解决，无奈通胀一来，为了抑制物价上涨，政府更不敢同意提电价，这势必使电的供不应求更加严重。</font></p>
<p><font size="2">煤价固然是市场供求决定的，但其中也存在非价格管制的影响。年前我在山西听到反映，随着矿难的升级，关闭小煤矿的行动也升级。过去已经把10万吨以下的煤矿都关了，后来关20万吨以下的。去年洪洞煤矿特大矿难导致105人遇难，结果要求30万吨以下的煤矿全部关闭。矿难当然必须坚决治理，许多小煤矿的安全设施差，出事故的风险高，所以关闭也是一项重要政策。但是事情有另外一面，中小煤矿对煤炭供给量在边际上的影响很大。30万吨以下的煤矿中，也有安全设施达到标准、在过去各类检查中也办齐了许可证明的。一道命令说关就关了，也许安全风险减小了，当对生产的影响就过大。这里不讨论矿难治理政策，只是说明，煤价虽然是市场形成的，但其中也有类似价格下限管制的影响，其效果是把煤价顶起来的。</font></p>
<p><font size="2">第二是粮食。迄今为止，全国市场粮价上涨的幅度较低，差不多是所有农产品中价格涨幅最低的。2008年1月份的价格指数，肉禽升41.2％，猪肉58.8%，鲜菜13.7％，粮食只5.7％。粮价涨幅最低，是因为连年粮食丰收，粮库充裕，而从去年下半年后，国家粮库向市场大量拍卖粮食，压住了市场粮价的上升。这当然很重要，因为粮价的影响大，如果粮价像猪肉那样涨，对整个CPI的冲击就更大了。</font></p>
<p><font size="2">但是，这样的粮价态势，对未来粮食生产也有某种不利的影响。因为政府靠大手拍卖库存，与对粮价实行上限价格管制的效果是一样的。但是，政府对待别的农产品如食油、猪肉等，并没有使用同等的调控手段。反映到市场相对价格上，就是粮价上升偏慢，成为一个&ldquo;低谷&rdquo;。这对来年的粮食生产，就不是刺激增产的，而是减少生产的信号。加上政府对粮食生产的投入品如化肥、农药，也不能靠卖库存压价，所以这些投入品价格涨得远比粮价凶。南方下雪的时候，我们在浙江衢州访问1000亩规模的种粮大户，前几年他们一亩地的净利达300－400元，去年就减到100元以内。这预示2008年继续增产粮食的经济诱因不足。</font></p>
<p><font size="2">更重要的是，考虑粮食问题不仅要考虑生产，还要考虑一旦农民的通胀预期起来以后，就是多生产了粮食，也不愿意多卖。农民通过惜售来对付通胀，因为晚一点卖，预期的价格还要上升。在这种情况下，粮食就成为农民反通胀的手段。不可看轻了，每家农民少卖几袋、多存几袋粮食，加到一起对全国市场的影响就不得了。</font></p>
<p><font size="2">以上提到的电力和粮食，直接间接都是上限价格管制，就是政府不准卖得贵，效果是抑制生产，减少生产和供给的意愿。同时，经济生活里还有实施下限价格管制&mdash;&mdash;就是不许东西卖得便宜&mdash;&mdash;的情况。这里分析的第三个例子是劳力，因为已经开始出现不许劳力市价过低的管制倾向。</font></p>
<p><font size="2">大家知道，我国的劳动力市场是开放竞争的。不过，也已经有了最低工资的管制。就是各地政府根据当地的生活水平，规定了人工的最低工资标准。经济分析说，只要规定的最低工资与市场供求决定的水准间相差不远，&ldquo;最低工资&rdquo;对劳动力供需的影响就不那么大，因为政府管制的价格靠近市价水平，没有严重偏离，等于为劳力市场提供了一个标准合同。有时候劳务的供需双方，要发现合适的价格也很麻烦，干脆照最低工资起薪，还节约了一些交易费用。这是前几年很多地方的情况。</font></p>
<p><font size="2">但是通胀指数上涨、特别是对工人生活影响极大的食品价格飞涨之后 挛侍饩统鱿至恕Ｓ械牡胤阶畹凸ぷ实牡髡  簧衔锛鄣谋浠  笠等绻 故前垂 ス娑ǖ淖畹托剿 缎剿  と司筒桓桑 蛭  堑氖杖敫喜簧鲜称氛饫?ldquo;打工成本&rdquo;的上涨幅度，这时&ldquo;最低工资&rdquo;就变成了劳务的上限价格管制，有打击劳动供给的效果。另外一些地方，大幅提升最低工资来应对通胀压力，试图在通胀条件下维持下限价格管制。还有一些地方，已经提出要把通胀指数与最低工资挂钩，也就是对最低工资作通胀指数化的处理，使之可以自动反映通胀的变化。这后两种情况，相当于对劳务实行下限价管，有造成供大于求的效果，值得认真观察。</font></p>
<p><font size="2">当下反应比较强烈的，是国家对劳力市场的非价格管制，特别是从2008年1月生效的新劳动合同法。最近差不多家家都在谈，且受影响的还不单单是&ldquo;企业&rdquo;，还包括所有的&ldquo;用人单位&rdquo;。这个法案涉及的面很宽，需要专门讨论。这里只讨论它与通胀形势的关联。以最近了解的一个情况为例，港口一周七天都有船来，所以每天、包括周六和周日，都需要人工装卸。如果法例规定凡假日工作一定要加薪，那装卸的人工成本就高了。这样法定的条款，虽不是直接定价，但等于是一种非价格管制，人为提升人工成本。类似地，强化就业保障以及对劳动合同的法定干预，也有类似效果。</font></p>
<p><font size="2">舆论容易认为，通过法律干预人为提升劳动报酬的办法，对工人有利。但是仔细分析，对劳动关系的价格和非价格干预，除了有利于劳动者的一面，也还有不利的一面。因为劳动者固然可以依法提升劳动收入、改善劳动条件、增加就业保障，但由于这些立法限制相当于一种价格下限管制，它在提升人工价格的同时，也有减少对劳力需求的效果。这就意味着就业空间因此减少。这两面并存的正负效果，究竟孰轻孰重，要看具体环境。我国的情况是，虽然出现了局部地区&ldquo;民工荒&rdquo;，但每年新增就业的压力还是很大的。有报道说去年毕业的500万大学生，尚有100万还没找到工作。今年从&ldquo;用人单位&rdquo;的态度看，招工会更犹豫。本来，日趋激烈的产业重组、升级和调整，势必带来相当规模劳力的转岗和下岗。在这种情况下，在有岗位工人的利益提升与不得就业之门而入的工人利益之间，要有更谨慎的平衡考虑。从南方的情况看，因为市场变动带来的就业压力已经很大，加上新法规对就业量可能的影响，2008年增加就业的形势非常严峻。</font></p>
<p><font size="2">第四是土地。这个问题我们在过去的&ldquo;CCER中国经济观察&rdquo;上讨论过几次。去年政府宣布城镇居民不得购买农村的小产权房。这个政策的含义是什么？我们不妨问，农民为什么要把小产权房卖给城里人？原因无非是城里人出价高一点。所以，不准出售就限制了小产权房的卖家即农村人的利益。再问城里人为什么要买小产权房？原因无非价格相对便宜一些，政策不准城里人买，等于要他们买贵的，损害了城里人的利益。中国人不是农村人就是城里人，禁止小产权房卖给城里人的政策同时损害了城乡两个方面，所以从根本上我认为这不是一个好政策。当然这也许只是暂时的&ldquo;叫停&rdquo;，因为目前情况比较乱。农民土地一到流转的环节，非要&ldquo;集体&rdquo;出面不可。而&ldquo;集体&rdquo;制&mdash;&mdash;正如过去几十年的经验教训所显示的&mdash;&mdash;并不能自动保证农民的利益。像小产权房交易这样的事，到底农民得了多少，&ldquo;集体&rdquo;或少数村庄权力人物又得了多少，完全没有章法，不得已叫停一下也有道理。</font></p>
<p><font size="2">要讨论的是，维持国家征地和独家向市场供应建设用地的体制，实质上也是一种对土地要素实施下限价格管制的制度。它人为降低了土地供给之间的竞争，推高了地价。过去我们分析过，地价是不能决定房价的，因为房价首先由需求决定。不过给定市场对房屋的需求，地价越高，结果只有高价位的房屋需求才优先得到满足，于是观察得到的房屋成交价，就都是高价位的了。一面希望房价不要升得那么快，一面又规定土地决不能卖得便宜，这无论如何是加不到一起的。</font></p>
<p><font size="2">上面我们讨论的四种产品，电力和粮食是产出，劳力和土地是投入的要素。很有意思，目前的情况是对产出品实行价格的上限管制，也就是政府为了控制物价水平的过快上涨，用行政命令或法律手段限定了产出品的最高价位；同时又对投入的要素实行价格的下限管制，就是不准卖得便宜。</font></p>
<p><font size="2">这样两种价格管制的结合，将有什么结果呢？我认为最明显的后果就是打击生产。这其实是不难明白的&mdash;&mdash;出售之物不得低于市价，投入之物又必须高于市价，两头挤压生产者，人家还不是只好减少生产、退出生产？上世纪80年代中期，饲料粮价格先放开，但生猪还按政府定的低价收购，当时江苏农民就发牢骚说，&ldquo;议价饲料平价猪，谁养猪谁是猪&rdquo;。现在的&ldquo;饲料&rdquo;不但市场议价，而且非贵过市价不可，那岂不是&ldquo;谁养猪谁还不如猪&rdquo;了吗？</font></p>
<p><font size="2">这就是为什么说小问题可能变成大问题。因为通胀和通胀预期一旦起来，即使果断地釜底抽薪，紧缩货币供应量，已经发出去的货币和已经启动的通胀预期，还是要在市场上起作用。所以，通胀一旦起来，一般不会马上下去。这个时候，鼓励生产、增加生产很重要，因为只有拿出更多的商品和服务，才能对付市场上已经偏多的货币购买力。在这个紧要关头，不当价管打击生产，无异于为通胀火上浇油。</font></p>
<p><font size="2">这里有一个挑战性的问题，就是在通胀的背景下，还要不要充分发挥价格机制的功能？我们注意到，去年年底的时候，发改委坚持2008年要提升中国的能源和资源价格，校正长久以来的价格失真。这是对的，否则什么保护环境、节能减排，统统不过喊口号而已，没有经济机制要求人们普遍如此行为。但是通胀指数高了之后，政府的第一位任务转向&ldquo;摁住&rdquo;物价，原定的价格改革&mdash;&mdash;包括电价调整&mdash;&mdash;不得不押后。</font></p>
<p><font size="2">但是，我们认为物价管制不但替代不了货币管理，也永远消除不了通胀。相反，即使在通胀的情况下，也要充分发挥价格机制调节供求的作用，特别不能用不当的价管组合来打击生产，那样只会助长通胀和通胀预期，从而延长甚至加剧通胀。此事知易行难，70初美国尼克松总统在&ldquo;石油危机&rdquo;冲击后，宣布冻结美国的石油和工资价格，可是因为货币过多的问题没解决，结果物价管制打击了供给，使&ldquo;短缺&rdquo;更加严重&mdash;&mdash;人们都增加了囤积货物的倾向。等到物价管制实在守不住，通胀指数立刻迅猛上涨。这说明，气温高的时候试图把&ldquo;气温计&rdquo;压住，于事无补。瞒天不能过海，不准确的气温计，谁也不会当一回事，大家凭感觉行动。</font></p>
<p><font size="2">现在的困难是，人们对&ldquo;从紧&rdquo;的货币政策还有很大的保留，因为看到美国经济和国际市场下行的风险增加，中国的出口部门正面临严重调整，也出现了企业搬迁、就业困难等新问题。在此压力下，更倾向于&ldquo;灵活的&rdquo;货币政策，不时要求增加货币的供给。另一方面，传统思路又总把通胀看成物价现象，习惯用管制物价的办法来&ldquo;治理通胀&rdquo;。到了物价管制的层面，再来一个投入品限低价、产出品限高价&mdash;&mdash;所有这些因素凑到了一起，有可能有大麻烦。好比一口锅，已经烧得很热，但下不了决心撤火，反而锅下加把柴，锅上压个盖。那样的结局，不是把饭烧糊，就是把锅烧炸。因此，如果说&ldquo;松货币&rdquo;是一错，&ldquo;紧物价&rdquo;就是再错。对付通货膨胀要谨防一错再错，考虑&ldquo;釜底抽薪紧货币，松动价管促生产&rdquo;。</font></p> <a href="http://hi.baidu.com/fatbsd/blog/item/13be06d03a2e078aa0ec9ca9.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/%B2%C6%BE%AD">财经</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/13be06d03a2e078aa0ec9ca9.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-06  00:03</pubDate>
        <category><![CDATA[财经]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/13be06d03a2e078aa0ec9ca9.html</guid>
</item>

<item>
        <title><![CDATA[毫不含糊地反对通货膨胀(转）]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/8845b500de8c5b14728b65a8.html]]></link>
        <description><![CDATA[
		
		<p><font size="3">经济大势正在变化。当前要面对的问题，首推通货膨胀。超过5％的通胀率绝不是小事，当然也不好说已经是很了不得的大事。问题是，小事也可能转成大事。能否化解的影响因素很多，其中最重要的，是判断、措施和发出的信号不能含糊。含含糊糊要误事，这是本文题目的由来。</font></p>
<p><font size="3">话说国家统计局公布今年10月消费者物价指数为6.5%，高于9月的6.2%，与8月创下的十年最高点持平。众多解读中，很流行的一个说法是&ldquo;结构性通货膨胀&rdquo;。我的感受，在通胀指数不高的情况下，此说听听也无大碍；通胀指数超过了5％，还说什么结构性云云，就不能不提出一点公开的批评意见。</font></p>
<p><font size="3">&ldquo;结构性通胀&rdquo;提法的主要毛病，是太过含糊了。粗粗看去，这个提法似乎不过只是对市场现象的一种描述&mdash;&mdash;林林总总商品和服务的价格，有的升得快，有的升得慢，有的不升甚至还下跌。比如今年以来我国物价指数的变动中，食品价格升得急，一般工业品价格升得缓，其中一些商品服务的价格还下跌（比如北京市公交车和地铁车票大幅度降价）。</font></p>
<p><font size="3">为什么说这样一种描述是含糊之词呢？首先，世界上还有没有&ldquo;非结构性的&rdquo;通货膨胀？这是问，有没有那么一种通胀，是所有商品和服务的市价都以同一幅度全面上涨的？教科书上说的&ldquo;货币中性（monetary neutrality）&rdquo;，意思是一个经济一旦多发了一倍货币，所有商品服务的名义价格上涨一倍，但真实变量如总产品并不会上涨一倍。那样的通胀指数再高也没关系，无非是所有人把自己购买和出售的价格，一律加上相同的零就是了。</font></p>
<p><font size="3">但是，&ldquo;货币中性&rdquo;至少有一个理论前提，就是交易费用或信息成本为零。真实世界里没有这回事，所以真实的通胀，各种商品服务的价格上杨不是齐头并进，而总是参差不齐的。特别是通胀压力开始显现的时候，差不多都是从一些热门货开始，然后扩散、蔓延。比如我这个年龄的都经历过的1988年那次严重通胀，开始是名烟名酒提价，后来中央的一个公报宣布价格闯关，接下来就是市场抢购、银行挤兑。当时可观察到，消费量对价格变化弹性小的商品（比如粮食、手纸、盐）抢购就凶，而越抢购，价格越涨得越快。反之，雨伞、手电筒这些弹性小的商品，卖量就没有那样多，涨价幅度也较低&mdash;&mdash;都是&ldquo;结构性的&rdquo;，只不过当时人没有今天聪明，尚没有发明&ldquo;结构性通胀&rdquo;之说。</font></p>
<p><font size="3">当然，恶性通胀到了顶点，情况或许不同。例如1921年1月一份德国报纸卖价0.3马克，两年后的卖价达到7000万马克！曼昆在他那本出色的宏观经济教科书里接着补了一句，&ldquo;其他商品的上升幅度大致相同&rdquo;。我们无从考察当年细节，不过那时候德国流通中的纸币从1918年11月的292亿马克到1923年的49700兆亿（497后面加18个零），也是逐年加速度翻上去的。票子开始发毛的时候，我相信各种物价的上涨也不会整齐划一。曼昆说的&ldquo;大致相同&rdquo;，应该是结果&mdash;&mdash;货架上来什么抢光什么，均衡点就是什么商品服务都开出了天价，既然都是天价，谁比谁多几个零也就没甚意思了。所以曼昆说，&ldquo;货币中性&rdquo;从长期来看对得多一点，但也不完全对*。</font></p>
<p><font size="3">既然天下没有&ldquo;非结构性通胀&rdquo;这回事，为什么要说&ldquo;结构性通胀&rdquo;呢？听起来好像通货膨胀还有很多类别，而&ldquo;结构性通胀&rdquo;似乎只是其中一个不是那么严重的类别，似乎是比较可控的一个类别，甚至&ldquo;结构性通胀&rdquo;根本就算不得通胀。要说明一下，我不肯定这个提法的使用者真的有以上这个想法，但是从听的角度来体会，&ldquo;结构性通胀&rdquo;在含含糊糊中就有了太多丰富的意味。</font></p>
<p><font size="3">本来，&ldquo;通货膨胀指数&rdquo;已经是处理了结构信息以后的一个总量指标。&ldquo;2007年10月消费者物价指数（CPI）为6.5%&rdquo;的含义，就是所有被列入考核的商品服务的物价水平，比去年同期高出了6.5%。被列入考核的商品服务种类很多，所以在得出CPI的过程中，结构信息是先被统计部门处理过了的，比如肉价、菜价、米价、衣价、交通费用、房价（目前是房租）各自的变动，然后才是加权平均，得出一个反应物价总水平的指数来。很明显，没有哪个CPI是没有结构的。可是，结构加权平均的结果可能是截然不同的，既可能是总体平均为零，可能为正，也可能为负。现在国家统计局报告我国CPI为6.5%，就是报告经过结构性加权平均以后，消费者物价的总水平上涨了6.5%。</font></p>
<p><font size="3">&ldquo;结构性通胀&rdquo;的提法，恰恰混淆了总量信息与结构信息。当下我国的通胀，当然是各种物价有升有降情况下的通胀，不过既然CPI数值超过了正的5％，就是清清楚楚披露了各种物价的变动正负相抵之后，物价总水平还是上涨了。本来明明白白的通胀，非要加一个&ldquo;结构性&rdquo;的定语，实际效果就含糊不清了。通胀有结构性，通缩也有结构性，不涨不缩还有结构性，究竟物价总水平是怎么样的一个变动趋势呢？</font></p>
<p><font size="3">物价总水平这个总量指标有一个无可替代的功能，就是警示政府注意，一旦物价总水平出现上升势头，就一定要到&ldquo;货币&rdquo;里去寻找原因以及解决问题的办法。这里，警示政府非常重要，因为自从金本位结束以来，只有政府控制着货币；一旦货币供应量出现问题，个人、家庭、企业、地方对此都无能为力，所有&ldquo;微观行为者&rdquo;都校正不了货币出错，而且在物价总水平不对头的约束下，无数人在预期混乱条件下行为的总结果，可能增加经济的振荡和混乱。</font></p>
<p><font size="3">在知识上，经验和理论比较高度一致的地方，就是把&ldquo;通货膨胀（物价总水平上升）&rdquo;看作是一个货币现象。这里的因果关系很可靠：政府多发货币，一定引发物价总水平的上涨。经济学从古典的修谟（David Hume）到一年前去世的弗里德曼（Milton Friedman），大家之间少有分歧的共识就是这一点。20世纪各国的经验也充分证明，要把经济搞上去不容易，因为要满足很多条件；但要把经济搞下来，只要一条就足够，那就是滥发货币、大搞通胀。产权经济学对此的解释很简单，通胀在无形之中剥夺全体人民的财产，引起预期的普遍混乱，加剧交易费用。恶性通胀，万事皆休，什么也不要谈了。</font></p>
<p><font size="3">如果说作为物价总水平的&ldquo;通货膨胀&rdquo;指标，直指问题的根本（货币）是一个优点，那么含糊的&ldquo;结构性通货膨胀&rdquo;，却很容易把决策者的注意力拉向&ldquo;结构性解决方案&rdquo;。什么是结构性对策？就是头痛医头、脚痛医脚，从最终产品追到中间产品再追到资源产品，深入到所有涨价品的市场供求。结构性措施不是皆不可取，但是，要清楚再周全的结构性措施，也替代不了货币总量的控制。中国传统智慧说&ldquo;扬汤止沸，不如釜底抽薪&rdquo;，货币就是物价总水平的釜底之薪，此薪不除，&ldquo;结构性通胀&rdquo;就转来转去，摁下葫芦浮起瓢，永无宁日就是了。</font></p>
<p><font size="3">这就是含含糊糊的提法要误事的理由。牙痛就是牙痛，不要说什么结构性牙痛。就算满口都是好牙，只有一粒出了问题&mdash;&mdash;是结构性问题&mdash;&mdash;也不要说。因为只要有一粒牙出了问题，其他所有好牙都不能正常发挥功能，甚至全身不得安生。说结构性牙痛不能减轻痛苦，却可能动摇治疗的决心和注意力集中的方向。把满口好牙敲来敲去，就是怕那粒有问题的病牙，耽误功夫还不去病根。</font></p>
<p><font size="3">要看到，由于某些价格管制的存在，当前通胀的实际状况并没有在CPI里完全反映出来。举一个例子，个把月前和几位同学在校区餐厅吃饭，他们全部点了猪排。过去也一起吃饭，为什么没有发现有此偏好呢？同学说，最近食堂里没有猪肉供应。懂了，这是保障食堂饭菜价格不上涨的一个代价，猪肉涨得贵，干脆不供应猪肉，无价无市。还好，同学们说饭没涨价，菜、鸡、鱼、蛋还有供应。但是，这里肯定有一点信息没有进入CPI。举一反三，排长龙加不到汽油，通宵排队摇不到买房的号码，肉包子的馅变小了之类，CPI里都没有完全反映。房价目前没有算入CPI，过去也没有，但当物价总水平上涨的时候，房价涨得可比过去凶。这也是CPI没有完全反映出来的信息，但是市场中人的通胀预期，可不是完全看官方CPI才形成的。</font></p>
<p><font size="3">不少专家说，当前我国消费者物价指数里面就是食品价格涨得厉害，其他部分还不那么厉害，言下之意似乎就是不要紧。我不同意这个分析。食品价格上涨不是不要紧，而是很要紧。倒不是要在这里重弹&ldquo;民以食为天&rdquo;的老调，而是食品价格上涨已经、并将继续严重恶化收入分配。先不看复杂的统计，随便在身边找两户人家，一家2003年买了房的，对照另一家一直买不起房的，看这两家的收入差距，这两年怎么样了？从统计上看，问题更大：恩格尔系数超过40％的，在全部城镇居民家庭中占40％，在农村居民家庭中占80％以上（2005年）。食品价格涨了17％，直接影响全国62％家庭高达40％的消费开支，这还是小事情？恩格尔系数40％的家庭，近年当然也有买房的，但肯定比恩格尔系数在20％以内的家庭，少买很多。里外里，收入差距要增加几何！</font></p>
<p><font size="3">我一直不赞成拿收入差距（吉尼系数）来说事，也从不笼统地反对收入差距扩大。因为收入差距既可能由分配不公引起，也可能由才能、勤奋、机缘造成。不作区分地乱反一气，可能伤及生产力。这个立场从来不变。问题是，通胀带来的收入差距扩大，恰恰是分配不公带来的收入分配恶化。试想这几年房价涨得远比食品快，对于买得起房的家庭，至少还可以&ldquo;享受&rdquo;帐面家庭财产迅速增加的好处；买不起房子的呢？总还要吃饭吧，可食品价格上涨怎么也带不来帐面财产的增加。买不起房子的，这几年工资收入固然都增加了，不过要是以&ldquo;食品本位&rdquo;考核之，也没有涨那么多。</font></p>
<p><font size="3">相关联的还有一种分析也错，就是说食品价格上涨对农民有利，比如猪肉价格上杨，养猪的农民就多得钱了。此说错在似是而非。因为物价上涨对所有的卖家都有好处，岂止养猪的农民而已哉？但是，当物价上涨不是个别相对价格的调整，而是整体物价总水平的提升即通胀发生时，上述&ldquo;好处&rdquo;就要大打折扣了，因为所有卖给农民的商品和服务，价格也上涨了。农民卖猪的收入是增加了，但养猪的成本也增加&mdash;&mdash;举凡场地、饲料、人工、运费等等，全部要加价。更重要的是，今天养猪的农民也买肉吃，种粮的农民也买米吃&mdash;&mdash;没有看到报道吗，重庆家乐福不幸事件踩踏致死的3人之中，两个是农村居民！更一般地讲，天下哪一个卖家不同时又是买家呢？当物价指数环比上涨（一月高过一月）时，卖时贵，买时更贵，再卖非再贵不可&mdash;&mdash;轮番涨价就是这样练成的。</font></p>
<p><font size="3">所以，通货膨胀开始很像一味甜丝丝的毒药。因为物价总水平的提升，开始总是&ldquo;结构性的&rdquo;，总有一些卖家先得到甜头。政府最不容易对通胀敏感，因为通胀是一道隐形的税收，可以给库房带来大把白花花的银子。市场中人包括商人和企业家，思维定式是把多赚到的看作自己的&ldquo;本事&rdquo;。以我自己为例，教一些商学院课程，这两年商学院的学费升得惊人，莫非是我教书的本事进步那么多吗？自己当然心知肚明，就是不会告诉你（一笑）。股市的赢家们就更不得了了，你说那是水分？他数钱给你看时那可是真的。&ldquo;台风大的时候，牛都飞到天上去了&rdquo;，这句话不是拿来说笑的。</font></p>
<p><font size="3">但是，只要货币量过多，在市场相对价格调整的表象背后，或早或迟总会露出物价总水平上涨的狰狞面目。其间，偶发事件扮演着异乎寻常的重要角色，一些看似无关的消息、故事、传闻和突发事件，无端端影响到人群的心理，然后就转化为行动。这就是为什么对通胀指数过了5％不能掉以轻心，对食品价格急升不能马虎大意，因为涉及的人口面太广，通胀的心理预期比较容易传染和蔓延。</font></p>
<p><font size="3">毫不含糊地反对通货膨胀，在思维上就要到货币里去寻找物价总水平上涨的根源。这里的关键词是&ldquo;货币&rdquo;，不是&ldquo;物价&rdquo;。计划经济时代的思维，总是用&ldquo;物价管理&rdquo;来对付通胀。&ldquo;物价管理&rdquo;就是上文说到的结构性对策，无非分兵把口，见肉价涨抓肉，见房价涨抓房。麻烦的是，&ldquo;抓&rdquo;得不好，效果适得其反，比如抑制供给的价格管制，抓来抓去是火上浇油。打通供给障碍的&ldquo;抓&rdquo;法（如发改委最近处理成品油的供给），大为可取，但是若不管理需求，短期供给总有极限。需求管理要从总量下手，分兵把口，每一个行当的需求都是其他行当的供给，管了等于还是抑供给。货币总量控制不到位，下死命令&ldquo;抓&rdquo;，涨价压力会转移的。这几年我认为看得清楚，钢铁、水泥、电解铝、土地、汽车、房地产一路抓过来，政府很辛苦，但CPI还是上来了。樊纲说得对，要是不抓，问题可能更严重。不过也让我补一句，这不代表宏观调控已经到位，再没有改善的余地。</font></p>
<p><font size="3">关键还是货币。1990年到芝加哥大学经济系访问，知道那里的学科设置与众不同：没有宏观经济学，但有money即货币；也没有微观经济学，有price 即价格。这是货币主义大本营的风范，不知道现在是不是还守得住。宏观经济学问很多，但最重要是货币，也只是货币。宏观调控的事务多得不得了，唯有货币才是牛鼻子。一次大战后的法国总理讲过一句话，&ldquo;战争是不能拿来开玩笑的，所以要委托给军队&rdquo;。弗里德曼拿过来改了两个词，化出一个货币主义的警句&mdash;&mdash;&ldquo;货币是不能拿来开玩笑的，所以要交给中央银行&rdquo;。毫不含糊地反通胀，就是要全力支持央行乾纲独断，履行货币管理职责。</font></p>
<p><font size="3">最近一次见到吴敬琏教授的时候，得到他签字赠送的新书《呼唤法治的市场经济》（三联书店2007年版）。吴老师在书中提到一件往事，当初设计论证宏观调控部门的时候，几位中外专家对设置四个宏调部门（央行、财政部、计委、经委）提出过异议，认为宏观调控既然是间接调控、总量调控，就应该只设央行和财政部，不能有其他。不过这个意见没有被采纳（第111页）。这几年的实际情况是宏调部门越来越多，多部委联署的金牌一道接一道。2004年第一次看到国土部长讲国土部门也要参加宏观调控，我实在百思不得其解：一幅土地从批出到建成总要二、三年时间，这么一个&ldquo;慢变量&rdquo;，怎么可以拿来当宏观调控的工具？当时和北大几位同事受委托到几个地方调研，报告里特地写到，&ldquo;银根&rdquo;、&ldquo;土根&rdquo;并举不是好办法，因为&ldquo;土根&rdquo;实在太笨拙。更严重的问题，是多龙治水，十八般兵器一起上，到底是哪样政策工具发生了哪样效果，谁也搞不清楚。分工不明确，职责就不清楚，譬如当下CPI高了，人们总不好问责国土部吧？</font></p>
<p><font size="3">我以为这不是小事情。用行政手段调控经济，讲到底就是通过增加制度运行的摩擦力来使经济减速。这套不得已而为之的办法，对法治、政商关系、反腐倡廉，都有百弊而无一利。近期代价也不小，因为一旦经济&ldquo;失速&rdquo;，那些摩擦力很大的制度性刹车装置，挥之不去。1997年中国经济突然转向通缩，&ldquo;保八&rdquo;任务之艰难，历历在目。我们当然相信中国经济还有很长时期的高速增长机会，但是上帝也不敢打包票，说从此经济就有起无落，只热不冷。比较起来，利率、汇率等经济手段，摩擦力就很低，差不多可以收放自如。调控经济，用交易费用低的办法是上选。否则景气一旦有变，&ldquo;反应滞后症&rdquo;就难免&mdash;&mdash;对付&ldquo;过热&rdquo;时捆到经济身上的绳索，到底有多少、在哪里，一时搞不清楚。</font></p>
<p><font size="3">不要误解，以为明明白白说通胀，就是给中国经济抹黑。讲过了，物价总水平上涨是一个货币现象，但是货币过多的具体成因却各个不同。中国过去发生过的严重通胀，上个世纪四十年代末是老蒋为打内战滥印钞票；八十年代是原先货币超经济发行的惯性还在，又被用来作为价格开放的利益补偿办法；九十年代早期高达27％的通胀，主要是权力贷款，几乎等于每一间商业银行都敞着口子发钞票。成因不同，只有结果同：只要货币量过多，一定有通胀的后果。</font></p>
<p><font size="3">这一波中国的通胀，直接原因当然还是货币。但是此次货币过多的原因，又和以往不同。最大的变化，是中国经济大规模融入全球市场。3万亿美元GDP的经济，进出口占了60％以上，这样的事情经济史上少见。当然是中国改革开放的成果，具体讲就是要素成本低廉、制度成本急速下降，中国人的学习曲线上升，&ldquo;三合一&rdquo;成就了中国经济的崛起。不过，也正是这个伟大的成就，使&ldquo;人民币盯住美元&rdquo;这件原来穿着很舒服的衣裳，再也穿不进去了。</font></p>
<p><font size="3">2003年9月宋国青教授在北大提出讨论的汇率研究报告，系统分析了人民币汇率为什么意味日益严重的风险和社会福利损失，以及主动升值的选择和机会**。我在实体经济里东看西看比较多一点，觉得国青的逻辑没有丝毫难懂的地方。讲到底，是中国人生产率的提升惹来的&ldquo;祸&rdquo;。这当然不是说中国工人生产率的绝对水平已经超过了美国工人，但是比生产率的进步速度，1990年代后的中国人明显占了上风。如果汇率真的由市场决定，早就反映相对生产率的变动了。这就是说人民币升值有实体经济的基础。不是谁喜欢不喜欢的事情。非不喜欢，那就要有两个本事：要么让美国人生产率的进步速度提上来，要么让中国人的进步速度降下去。实际上，谁也没有这两个本事，人民币盯住美元的体制怎么守得住？非死守，国内通胀压力就无可避免。</font></p>
<p><font size="3">很奇怪，这样逻辑井然的分析，听得进去的人不多。主流的声音是当时的人民币不能升值。后来又说可以缓缓地、渐进地升&mdash;&mdash;难道不知道，人民币缓升的宣示等于是&ldquo;快快向中国搬钱&rdquo;的邀请函和动员令？果不其然，贸易顺差、外资直投、以及应邀来华分享人民币渐进增值好处的热钱，三股潮流合并，使中国的货币流动性有如&ldquo;黄河之水天上来&rdquo;。</font></p>
<p><font size="3">这里要插一句，汇率的影响是全面的。别的不提，近年那么多农民转向城市，可是今年中国的谷物居然还是净出口。细节问题很多，但汇率影响是根本的：因为所有出口看起来很合算，进口却很不合算，那还不是谷物净出口？几亿农民进了城，谷物还搞净出口，同时无数专家天天担心&ldquo;粮食安全&rdquo;，这个日子还怎么过？反正从短期看，今年我国谷物的净出口，对猪肉和食品价格的急升，做出了很大的&ldquo;贡献&rdquo;。</font></p>
<p><font size="3">今年2月北大中国经济研究中心每季一次的&ldquo;中国经济观察&rdquo;，请易纲作宏观经济报告。我仔细听完讲解，才明白近几年央行哪里是在&ldquo;发&rdquo;货币，根本就是&ldquo;收流动性&rdquo;都收不赢！当然人民币还是中国人发的，可是发多少并不完全由中国人决定。因为每一块进入中国结汇的美元，都换出一定数量的人民币去。究竟可换多少，那是由&ldquo;以市场供求为基础、参考一篮子货币进行调节、有管理的浮动汇率&rdquo;决定的。这个票子非发不可，天天发、月月发、年年发。央行当然不能容许这笔惊人庞大的高能货币全部留在市场上，于是不断发央票&ldquo;对冲&rdquo;，也就是&ldquo;回收流动性&rdquo;。收不干净的呢？就是&ldquo;结构性通货膨胀&rdquo;的货币基础。</font></p>
<p><font size="3">结论是，当下中国的通胀不是政府滥发钞票的结果，而是现有汇率形成机制容纳不下中国国际竞争力的表现。这说明，上好的经济形势也会带来严重的挑战。因为，即便是&ldquo;好&rdquo;带来的货币总量偏多，也一样引发物价总水平上涨的压力。在开放条件下，经济图像更为复杂，但物价总水平上涨依然还是一个货币现象。这条铁律不变，分析家和决策者就还是不能含糊，物价问题一定要到货币里才能找到答案。</font></p> <a href="http://hi.baidu.com/fatbsd/blog/item/8845b500de8c5b14728b65a8.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/%B2%C6%BE%AD">财经</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/8845b500de8c5b14728b65a8.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-06  00:02</pubDate>
        <category><![CDATA[财经]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/8845b500de8c5b14728b65a8.html</guid>
</item>

<item>
        <title><![CDATA[浅谈GCC预编译头技术]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/8880e21898b24fb14bedbc0c.html]]></link>
        <description><![CDATA[
		
		<p>所谓预编译头，就是把头文件事先编译成一种二进制的中间格式，供后续的编译过程使用。GCC编译头文件后的中间文件是*.gch。</p>
<p>如何将头文件编译为.gch文件呢？用g++编译，格式：</p>
<p>g++ xxx.h</p>
<p>把.h文件当成.cpp文件一样来编译。如果需要控制编译细节，比如常量定义之类，可加上其它选项。运行之后，会在同个目录里生成一个名叫xxx.h.gch的文件。</p>
<p>注意在编译.gch的过程中，GCC并没有使用环境变量或 -I 选项来查找被编译的头文件，被编译的头文件必须在当前目录下。然而，被编译的头文件所进一步包含的其它头文件，却可以通过以上途径找到。简言之，就是把直接编译的那个头文件以类似对待.cpp文件的方式处理了。</p>
<p>比如该如何编译iostream呢？方法是在当前目录里建立一个头文件，把它放到用户定义的头文件里，比如foo.h，在其里面写上：#include &lt;iostream&gt;，然后编译它：g++ foo.h。生成的foo.h.gch，就是我们要的了。其它文件需要用到iostream的，不要包含iostream，要包含foo.h。切记，不是去包含foo.h.gch！</p>
<p>使用过程中，照搬一些stdafx.h相关的注意事项，它们同样适用于.gch文件：应该把那些不常修改的（首当其冲，当然是系统的）头文件放在预编译头里，而那些属于你的程序的一部分的头文件，一般并不放在预编译头里，因为它们可能随时要被修改的。每修改一次就要重新生成预编译头，并没有速度优势可言，失去预编译头的意义了。另外重要的注意事项是：如果你生成预编译头的时候用了一些选项，比如宏定义，那么使用这个预编译头的其它源代码文件，被编译的时候也要使用这些选项，否则会因为不匹配而编译失败。</p>
<p>使用预编译后的文件时，只要包含其所对应的.h文件即可！比如头文件叫foo.h，另外有一大堆其它文件都包含了这个foo.h，原来没有<a name="baidusnap0"></a><strong style="color: black; background-color: #ffff66">使用预编译头</strong>技术，现在忽然想使用了，于是把foo.h编译成了foo.h.gch。那其它文件要做怎样的修改？&mdash;&mdash;什么都不用，一切照旧！聪明的GCC编译器在查找一个.h文件之前，会自动查找其目录里有没有对应的.gch文件，如有，且可用，则用之；没有，才用到真正的.h头文件。&mdash;&mdash;慢着，&ldquo;如有，且可用&rdquo;，什么叫&ldquo;可用&rdquo;？&mdash;&mdash;就是指这个.gch格式要正确，版本要兼容，而且如上所述，编译两者要用同样的选项。如果.gch不可用，编译器会给出一条警告，告诉我们：这个预编译头不能用！我只好用原有的.h头文件啦！什么？你说看不到这个警告？&mdash;&mdash;当然，要先打开 -Winvalid-pch 选项才行，其默认是关闭的。</p>
<p>用 -H 选项感受一下预编译头的清爽吧！再没有滚不完的头文件了，明显提高的速度，绝对会让你有种翻身解放的感觉，原来MinGW也可以和蜗牛般的速度说再见的。</p>
<p>本文出自jorge的博客：blog.csdn.net/jorge，进行了删减和部分修改。</p> <a href="http://hi.baidu.com/fatbsd/blog/item/8880e21898b24fb14bedbc0c.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/Bsd">Bsd</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/8880e21898b24fb14bedbc0c.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-05  21:30</pubDate>
        <category><![CDATA[Bsd]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/8880e21898b24fb14bedbc0c.html</guid>
</item>

<item>
        <title><![CDATA[static_cast、dynamic_cast、reinterpret_cast、和const_cast]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/3a099203dbe53d723812bb6c.html]]></link>
        <description><![CDATA[
		
		<p>(转自<a href="http://hi.baidu.com/seekvista/blog/item/87845a60ae248845ebf8f8dd.html">http://hi.baidu.com/seekvista/blog/item/87845a60ae248845ebf8f8dd.html</a>)</p>
<p>关于强制类型转换的问题，很多书都讨论过，写的最详细的是C++ 之父的《C++ 的设计和演化》。最好的解决方法就是不要使用C风格的强制类型转换，而是使用标准C++的类型转换符：static_cast, dynamic_cast。标准C++中有四个类型转换符：<strong>static_cast</strong>、<strong>dynamic_cast</strong>、<strong>reinterpret_cast</strong>、和<strong>const_cast</strong>。下面对它们一一进行介绍。<br>
<br>
<span style="font-size: 16pt"><strong>static_cast</strong></span><br>
<br>
用法：<strong>static_cast </strong>&lt; type-id &gt; ( expression )<br>
<br>
该运算符把expression转换为type-id类型，但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法：</p>
<ul class="ubb-list">
    <li>用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换（把子类的指针或引用转换成基类表示）是安全的；进行下行转换（把基类指针或引用转换成子类表示）时，由于没有动态类型检查，所以是不安全的。</li>
    <li>用于基本数据类型之间的转换，如把int转换成char，把int转换成enum。这种转换的安全性也要开发人员来保证。</li>
    <li>把空指针转换成目标类型的空指针。</li>
    <li>把任何类型的表达式转换成void类型。</li>
</ul>
<p>注意：static_cast不能转换掉expression的const、volitale、或者__unaligned属性。<br>
<br>
<span style="font-size: 16pt"><strong>dynamic_cast</strong></span><br>
<br>
用法：<strong>dynamic_cast </strong>&lt; type-id &gt; ( expression )<br>
<br>
该 运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *；如果type-id是类指针类型，那么expression也必须是一个指针，如果type-id是一个引用，那么expression也必须是一个 引用。<br>
<br>
dynamic_cast主要用于类层次间的上行转换和下行转换，还可以用于类之间的交叉转换。<br>
<br>
在类层次间进行上行转换时，dynamic_cast和static_cast的效果是一样的；在进行下行转换时，dynamic_cast具有类型检查的功能，比static_cast更安全。</p>
<div class="code">class B{<br>
<br>
public:<br>
<br>
int m_iNum;<br>
<br>
virtual void foo();<br>
<br>
};<br>
<br>
class D:public B{<br>
<br>
public:<br>
<br>
char *m_szName[100];<br>
<br>
};<br>
<br>
<br>
<br>
void func(B *pb){<br>
<br>
D *pd1 = static_cast&lt;D *&gt;(pb);<br>
<br>
D *pd2 = dynamic_cast&lt;D *&gt;(pb);<br>
<br>
}</div>
<p><br>
在 上面的代码段中，如果pb指向一个D类型的对象，pd1和pd2是一样的，并且对这两个指针执行D类型的任何操作都是安全的；但是，如果pb指向的是一个 B类型的对象，那么pd1将是一个指向该对象的指针，对它进行D类型的操作将是不安全的（如访问m_szName），而pd2将是一个空指针。另外要注 意：B要有虚函数，否则会编译出错；static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息，而这个信息存储在类的虚函数表 （关于虚函数表的概念，详细可见&lt;Inside c++ object model&gt;）中，只有定义了虚函数的类才有虚函数表，没有定义虚函数的类是没有虚函数表的。<br>
<br>
另外，<strong>dynamic_cast</strong>还支持交叉转换（cross cast）。如下代码所示。</p>
<div class="code">class A{<br>
<br>
public:<br>
<br>
int m_iNum;<br>
<br>
virtual void f(){}<br>
<br>
};<br>
<br>
<br>
<br>
class B:public A{<br>
<br>
};<br>
<br>
<br>
<br>
class D:public A{<br>
<br>
};<br>
<br>
<br>
<br>
void foo(){<br>
<br>
B *pb = new B;<br>
<br>
pb-&gt;m_iNum = 100;<br>
<br>
D *pd1 = static_cast&lt;D *&gt;(pb); //copile error<br>
<br>
D *pd2 = dynamic_cast&lt;D *&gt;(pb); //pd2 is NULL<br>
<br>
delete pb;<br>
<br>
}</div>
<p><br>
在函数foo中，使用<strong>static_cast</strong>进行转换是不被允许的，将在编译时出错；而使用 <strong>dynamic_cast</strong>的转换则是允许的，结果是空指针。<br>
<br>
<span style="font-size: 16pt"><strong>reinpreter_cast</strong></span><br>
<br>
用法：<strong>reinpreter_cast</strong>&lt;type-id&gt; (expression)<br>
<br>
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数，也可以把一个整数转换成一个指针（先把一个指针转换成一个整数，在把该整数转换成原类型的指针，还可以得到原先的指针值）。<br>
<br>
该运算符的用法比较多。<br>
<br>
<span style="font-size: 16pt"><strong>const_cast</strong></span><br>
<br>
用法：<strong>const_cast</strong>&lt;type_id&gt; (expression)<br>
<br>
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外， type_id和expression的类型是一样的。<br>
<br>
常量指针被转化成非常量指针，并且仍然指向原来的对象；常量引用被转换成非常量引用，并且仍然指向原来的对象；常量对象被转换成非常量对象。<br>
<br>
Voiatile和const类试。举如下一例：</p>
<div class="code">class B{<br>
<br>
public:<br>
<br>
int m_iNum;<br>
<br>
}<br>
<br>
void foo(){<br>
<br>
const B b1;<br>
<br>
b1.m_iNum = 100; //comile error<br>
<br>
B b2 = const_cast&lt;B&gt;(b1);<br>
<br>
b2. m_iNum = 200; //fine<br>
}</div>
<p><br>
上面的代码编译时会报错，因为b1是一个常量对象，不能对它进行改变；使用const_cast把它转换成一个常量对象，就可以对它的数据成员任意改变。注意：b1和b2是两个不同的对象。</p> <a href="http://hi.baidu.com/fatbsd/blog/item/3a099203dbe53d723812bb6c.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/Windows">Windows</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/3a099203dbe53d723812bb6c.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-05  12:51</pubDate>
        <category><![CDATA[Windows]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/3a099203dbe53d723812bb6c.html</guid>
</item>

<item>
        <title><![CDATA[关于如何下载招财猫和摇钱树软件,请务必看一下,谢谢!]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/7caae344c9f64549510ffec9.html]]></link>
        <description><![CDATA[
		
		<p>到mofile下载;</p>
<p>摇钱树股票软件: <a href="http://pickup.mofile.com/0009587911195661" target="_blank">http://pickup.mofile.com/0009587911195661</a></p>
<p>招财猫股票软件: <a href="http://pickup.mofile.com/7382641955311023">http://pickup.mofile.com/7382641955311023</a></p>
<p>招财猫股票软件体积比较大,(因为包含了数据,以及上市公司发布过的所有公告),下载请耐心一点.</p>
<p>招财猫股票软件第一次使用时可能时间比较长,因为他要下载3月11到现在之间空缺的公告和数据.</p>
<p>论坛<a href="http://bigbug.xo51.com/" target="_blank">http://bigbug.xo51.com/</a>现在不能用,谁有好用的请推荐一下,非常感谢!</p>
<p>摇钱树股票软件不知道现在还能否连接上服务器,请使用的兄弟告之.(因为工作的原因最近又转到windows上干活,所以很少使用linux了,)如果不行了那我要抓紧编写下一个版本.</p>
<p>因为很忙,(也不知道整天忙什么,要吃饭呀,没办法),所以不能及时更新,大家海涵:(</p>
<p>qq很少上,需要联系的话msn可以使用,gmail.com的信箱,用户名是ityufeng</p>
<p>有什么建议也可以提,谢谢!</p> <a href="http://hi.baidu.com/fatbsd/blog/item/7caae344c9f64549510ffec9.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/%D5%D0%B2%C6%C3%A8%28dollarcat%29%2Dlinux%CF%C2%B5%C4%B9%C9%C6%B1%C8%ED%BC%FE">招财猫(dollarcat)-linux下的股票软件</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/7caae344c9f64549510ffec9.html#comment">查看评论</a>]]></description>
        <pubDate>2008-05-16  00:08</pubDate>
        <category><![CDATA[招财猫(dollarcat)-linux下的股票软件]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/7caae344c9f64549510ffec9.html</guid>
</item>

<item>
        <title><![CDATA[C++字符串完全指引二]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/fd28af13be8cd627dc540113.html]]></link>
        <description><![CDATA[
		
		<p>　　使用cast来实现类型转换是不好的做法，除非有文档明确指出这种转换可以使用。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>促使我写这两篇文章的原因是字符串类型转换中经常遇到的一些问题。当我们使用cast把字符串从类型X转换到类型Z的时候，我们不知道为什么代码不能正常工作。各种各样的字符串类型，尤其是BSTR，几乎没有在任何一个地方的文档中被明确的指出可以用cast来实现类型转换。所以我想一些人可能会使用 cast来实现类型转换并希望这种转换能够正常工作。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　除非源字符串是一个被明确指明支持转换操作符的字符串包装类，否则cast不对字符串做任何转换。对常量字符串使用cast不会起到任何作用，所以下面的代码：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>void SomeFunc ( LPCWSTR widestr );
    main()
    {
    SomeFunc ( (LPCWSTR) &quot;C:\foo.txt&quot; );  // WRONG!
    }</pre>
<p>　　肯定会失败。它可以被编译，因为cast操作会撤消编译器的类型检查。但是，编译可以通过并不能说明代码是正确的。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　在下面的例子中，我将会指明cast在什么时候使用是合法的。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>C-style strings and typedefs</pre>
<p>　　正如我在第一部分中提到的，windows APIs 是用TCHARs来定义的，在编译时，它可以根据你是否定义_MBCS或者_UNICODE被编译成MBCS或者Unicode字符。你可以参看第一部分中对TCHAR的完整描述，这里为了方便，我列出了字符的typedefs<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="19%"><strong>Type</strong></td>
            <td align="center" width="81%"><strong>Meaning</strong></td>
        </tr>
        <tr>
            <td align="center" width="19%">WCHAR</td>
            <td align="center" width="81%">Unicode character (wchar_t)</td>
        </tr>
        <tr>
            <td align="center" width="19%">TCHAR</td>
            <td align="center" width="81%">MBCS or Unicode character, depending on preprocessor settings</td>
        </tr>
        <tr>
            <td align="center" width="19%">LPSTR</td>
            <td align="center" width="81%">string of char (char*)</td>
        </tr>
        <tr>
            <td align="center" width="19%">LPCSTR</td>
            <td align="center" width="81%">constant string of char (const char*)</td>
        </tr>
        <tr>
            <td align="center" width="19%">LPWSTR</td>
            <td align="center" width="81%">string of WCHAR (WCHAR*)</td>
        </tr>
        <tr>
            <td align="center" width="19%">LPCWSTR</td>
            <td align="center" width="81%">constant string of WCHAR (const WCHAR*)</td>
        </tr>
        <tr>
            <td align="center" width="19%">LPTSTR</td>
            <td align="center" width="81%">string of TCHAR (TCHAR*)</td>
        </tr>
        <tr>
            <td align="center" width="19%">LPCTSTR</td>
            <td align="center" width="81%">constant string of TCHAR (const TCHAR*)</td>
        </tr>
    </tbody>
</table>
<p>　　一个增加的字符类型是OLETYPE。它表示自动化接口（如word提供的可以使你操作文档的接口）中使用的字符类型。这种类型一般被定义成 wchar_t，然而如果你定义了OLE2ANSI预处理标记，OLECHAR将会被定义成char类型。我知道现在已经没有理由定义OLE2ANSI （从MFC3以后，微软已经不使用它了），所以从现在起我将把OLECHAR当作Unicode字符。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>这里给出你将会看到的一些OLECHAR相关的typedefs：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="18%"><strong>Type</strong></td>
            <td align="center" width="82%"><strong>Meaning</strong></td>
        </tr>
        <tr>
            <td align="center" width="18%">OLECHAR</td>
            <td align="center" width="82%">Unicode character (wchar_t)</td>
        </tr>
        <tr>
            <td align="center" width="18%">LPOLESTR</td>
            <td align="center" width="82%">string of OLECHAR (OLECHAR*)</td>
        </tr>
        <tr>
            <td align="center" width="18%">LPCOLESTR</td>
            <td align="center" width="82%">constant string of OLECHAR (const OLECHAR*)</td>
        </tr>
    </tbody>
</table>
<p><a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　还有两个用于包围字符串和字符常量的宏定义，它们可以使同样的代码被用于MBCS和Unicode builds ：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="18%"><strong>Type</strong></td>
            <td align="center" width="82%"><strong>Meaning</strong></td>
        </tr>
        <tr>
            <td align="center" width="18%">OLECHAR</td>
            <td align="center" width="82%">Unicode character (wchar_t)</td>
        </tr>
        <tr>
            <td align="center" width="18%">LPOLESTR</td>
            <td align="center" width="82%">string of OLECHAR (OLECHAR*)</td>
        </tr>
        <tr>
            <td align="center" width="18%">LPCOLESTR</td>
            <td align="center" width="82%">constant string of OLECHAR (const OLECHAR*)</td>
        </tr>
    </tbody>
</table>
<p><a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　在文档或例程中，你还会看到好多_T的变体。有四个等价的宏定义，它们是TEXT, _TEXT, __TEXT和__T，它们都起同样的做用。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>COM 中的字符串 ?? BSTR 和 VARIANT</h3>
<p>　　很多自动化和COM接口使用BSTR来定义字符串。BSTRs中有几个&quot;陷阱&quot;，所以这里我用单独的部分来说明它。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　BSTR 是 Pascal-style 字符串（字符串长度被明确指出）和C-style字符串（字符串的长度要通过寻找结束符来计算）的混合产物。一个BSTR是一个Unicode字符串，它的长度是预先考虑的，并且它还有一个0字符作为结束标记。下面是一个BSTR的示例：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="20%">06 00 00 00</td>
            <td align="center" width="20%">42 00</td>
            <td align="center" width="20%">6F 00</td>
            <td align="center" width="20%">62 00</td>
            <td align="center" width="20%">00 00</td>
        </tr>
        <tr>
            <td align="center" width="20%">--length--</td>
            <td align="center" width="20%">B</td>
            <td align="center" width="20%">o</td>
            <td align="center" width="20%">b</td>
            <td align="center" width="20%">EOS</td>
        </tr>
    </tbody>
</table>
<p>　　注意字符串的长度是如何被加到字符串数据中的。长度是DWORD类型的，保存了字符串中包含的字节数，但不包括结束标记。在这个例子中，&quot;Bob&quot;包含 3个Unicode字符（不包括结束符），总共6个字节。字符串的长度被预先存储好，以便当一个BSTR在进程或者计算机之间被传递时，COM库知道多少数据需要传送。（另一方面，一个BSTR能够存储任意数据块，而不仅仅是字符，它还可以包含嵌入在数据中的0字符。然而，由于这篇文章的目的，我将不考虑那些情况）。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　在 C++ 中，一个 BSTR 实际上就是一个指向字符串中第一个字符的指针。它的定义如下：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>BSTR bstr = NULL;
    bstr = SysAllocString ( L&quot;Hi Bob!&quot; ); 
    if ( NULL == bstr )
    // out of memory error 
    // Use bstr here...
    SysFreeString ( bstr );</pre>
<p>自然的，各种各样的BSTR封装类为你实现内存管理。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　另外一个用在自动化接口中的变量类型是VARIANT。它被用来在无类型（typeless）语言，如Jscript和VBScript，来传递数据。一个VARIANT可能含有很多不同类型的数据，例如long和IDispatch*。当一个VARIANT包含一个字符串，字符串被存成一个 BSTR。当我后面讲到VARIANT封装类时，我会对VARIANT多些介绍。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>字符串封装类</h3>
<p>　　到目前为止，我已经介绍了各种各样的字符串。下面，我将说明封装类。对于每个封装类，我将展示怎样创建一个对象及怎样把它转换成一个C语言风格的字符串指针。C语言风格的字符串指针对于API的调用，或者创建一个不同的字符串类对象经常是必需的。我不会介绍字符串类提供的其他操作，比如排序和比较。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　重复一遍，除非你确切的明白结果代码将会做什么，否则不要盲目地使用cast来实现类型转换。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>CRT提供的类</h3>
<h3>_bstr_t</h3>
<p>　　 _bstr_t是一个对BSTR的完整封装类，实际上它隐藏了底层的BSTR。它提供各种构造函数和操作符来访问底层的C语言风格的字符串。然而， _bstr_t却没有访问BSTR本身的操作符，所以一个_bstr_t类型的字符串不能被作为输出参数传给一个COM方法。如果你需要一个BSTR*参数，使用ATL类CComBSTR是比较容易的方式。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　一个_bstr_t字符串能够传给一个接收参数类型为BSTR的函数，只是因为下列3个条件同时满足。首先，_bstr_t有一个向wchar_t* 转换的转换函数；其次，对编译器而言，因为BSTR的定义，wchar_t*和BSTR有同样的含义；第三，_bstr_t内部含有的wchar_t*指向一片按BSTR的形式存储数据的内存。所以，即使没有文档说明，_bstr_t可以转换成BSTR，这种转换仍然可以正常进行。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    _bstr_t bs1 = &quot;char string&quot;;       // construct from a LPCSTR
    _bstr_t bs2 = L&quot;wide char string&quot;; // construct from a LPCWSTR
    _bstr_t bs3 = bs1;                 // copy from another _bstr_t
    _variant_t v = &quot;Bob&quot;;
    _bstr_t bs4 = v;                   // construct from a _variant_t that has a string
    
    // Extracting data
    LPCSTR psz1 = bs1;              // automatically converts to MBCS string
    LPCSTR psz2 = (LPCSTR) bs1;     // cast OK, same as previous line
    LPCWSTR pwsz1 = bs1;            // returns the internal Unicode string
    LPCWSTR pwsz2 = (LPCWSTR) bs1;  // cast OK, same as previous line
    BSTR    bstr = bs1.copy();      // copies bs1, returns it as a BSTR
    
    // ...
    SysFreeString ( bstr );</pre>
<p>　　注意_bstr_t也提供char*和wchar_t*之间的转换操作符。这是一个值得怀疑的设计，因为即使它们是非常量字符串指针，你也一定不能使用这些指针去修改它们指向的缓冲区的内容，因为那将破坏内部的BSTR结构。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>_variant_t</h3>
<p>　　_variant_t是一个对VARIANT的完整封装，它提供很多构造函数和转换函数来操作一个VARIANT可能包含的大量的数据类型。这里，我将只介绍与字符串有关的操作。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    _variant_t v1 = &quot;char string&quot;;       // construct from a LPCSTR
    _variant_t v2 = L&quot;wide char string&quot;; // construct from a LPCWSTR
    _bstr_t bs1 = &quot;Bob&quot;;
    _variant_t v3 = bs1;                 // copy from a _bstr_t object
    
    // Extracting data
    _bstr_t bs2 = v1;           // extract BSTR from the VARIANT
    _bstr_t bs3 = (_bstr_t) v1; // cast OK, same as previous line</pre>
<p>注意： 　　 如果类型转换不能被执行，_variant_t方法能够抛出异常t所以应该准备捕获_com_error异常。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>还需要注意的是：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　没有从一个_variant_t变量到一个MBCS字符串的直接转换。你需要创建一个临时的_bstr_t变量，使用提供Unicode到MBCS转换的另一个字符串类或者使用一个ATL转换宏。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　不像_bstr_t，一个_variant_t变量可以被直接作为参数传递给一个COM方法。_variant_t继承自VARIANT类型，所以传递一个_variant_t来代替VARIANT变量是C++语言所允许的。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>STL 类</h3>
<p>　　STL只有一个字符串类，basic_string。一个basic_string管理一个以0做结束符的字符串数组。字符的类型是 basic_string模般的参数。总的来说，一个basic_string类型的变量应该被当作不透明的对象。你可以得到一个指向内部缓冲区的只读指针，但是任何写操作必须使用basic_string的操作符和方法。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　basic_string有两个预定义的类型：包含char的string类型和包含wchar_t的wstring类型。这里没有内置的包含TCHAR的类型，但是你可以使用下面列出的代码来实现。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Specializations
    typedef basic_string tstring; // string of TCHARs
    
    // Constructing
    string str = &quot;char string&quot;;         // construct from a LPCSTR
    wstring wstr = L&quot;wide char string&quot;; // construct from a LPCWSTR
    tstring tstr = _T(&quot;TCHAR string&quot;);  // construct from a LPCTSTR
    
    // Extracting data
    LPCSTR psz = str.c_str();    // read-only pointer to str''s buffer
    LPCWSTR pwsz = wstr.c_str(); // read-only pointer to wstr''s buffer
    LPCTSTR ptsz = tstr.c_str(); // read-only pointer to tstr''s buffer</pre>
<p>　　不像_bstr_t，一个basic_string变量不能在字符集之间直接转换。然而，你可以传递由c_str()返回的指针给另外一个类的构造函数（如果这个类的构造函数接受这种字符类型）。例如：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Example, construct _bstr_t from basic_string
    _bstr_t bs1 = str.c_str();  // construct a _bstr_t from a LPCSTR
    _bstr_t bs2 = wstr.c_str(); // construct a _bstr_t from a LPCWSTR</pre>
<h3>ATL 类</h3>
<h3>CComBSTR</h3>
<p>　　CComBSTR 是 ATL 中的 BSTR 封装类，它在某些情况下比_bstr_t有用的多。最引人注意的是CComBSTR允许访问底层的BSTR，这意味着你可以传递一个CComBSTR对象给COM的方法。CComBSTR对象能够替你自动的管理BSTR的内存。例如，假设你想调用下面这个接口的方法：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Sample interface:
    struct IStuff : public IUnknown
    {
    // Boilerplate COM stuff omitted...
    STDMETHOD(SetText)(BSTR bsText);
    STDMETHOD(GetText)(BSTR* pbsText);
    };</pre>
<p>　　CComBSTR有一个操作符--BSTR方法，所以它能直接被传给SetText()函数。还有另外一个操作--&amp;，这个操作符返回一个 BSTR*。所以，你可以对一个CComBSTR对象使用&amp;操作符，然后把它传给需要BSTR*参数的函数。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>CComBSTR bs1;
    CComBSTR bs2 = &quot;new text&quot;;
    
    pStuff-&gt;GetText ( &amp;bs1 );       // ok, takes address of internal BSTR
    pStuff-&gt;SetText ( bs2 );        // ok, calls BSTR converter
    pStuff-&gt;SetText ( (BSTR) bs2 ); // cast ok, same as previous line</pre>
<p>　　CComBSTR有和_bstr_t相似的构造函数，然而却没有内置的向MBCS字符串转换的函数。因此，你需要使用一个ATL转换宏。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    CComBSTR bs1 = &quot;char string&quot;;       // construct from a LPCSTR
    CComBSTR bs2 = L&quot;wide char string&quot;; // construct from a LPCWSTR
    CComBSTR bs3 = bs1;                 // copy from another CComBSTR
    CComBSTR bs4;
 
    bs4.LoadString ( IDS_SOME_STR );  // load string from string table
    // Extracting data
    BSTR bstr1 = bs1;        // returns internal BSTR, but don''t modify it!
    BSTR bstr2 = (BSTR) bs1; // cast ok, same as previous line
    BSTR bstr3 = bs1.Copy(); // copies bs1, returns it as a BSTR
    BSTR bstr4;
    bstr4 = bs1.Detach();  // bs1 no longer manages its BSTR
    // ...
    SysFreeString ( bstr3 );
    SysFreeString ( bstr4 );</pre>
<p>　　注意在上个例子中使用了Detach()方法。调用这个方法后，CComBSTR对象不再管理它的BSTR字符串或者说它对应的内存。这就是bstr4需要调用SysFreeString()的原因。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　做一个补充说明：重载的&amp;操作符意味着在一些STL容器中你不能直接使用CComBSTR变量，比如list。容器要求&amp;操作符返回一个指向容器包含的类的指针，但是对CComBSTR变量使用&amp;操作符返回的是BSTR*，而不是CComBSTR*。然而，有一个ATL类可以解决这个问题，这个类是CAdapt。例如，你可以这样声明一个CComBSTR的list：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>std::list&lt; CAdapt<ccombstr></ccombstr> &gt; bstr_list;</pre>
<p>　　CAdapt提供容器所需要的操作符，但这些操作符对你的代码是透明的。你可以把一个bstr_list当作一个CComBSTR的list来使用。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>CComVariant</h3>
<p>　　CComVariant是VARIANT的封装类。然而，不像_variant_t，在CComVariant中VARIANT没有被隐藏。事实上你需要直接访问VARIANT的成员。CComVariant提供了很多构造函数来对VARIANT能够包含的多种类型进行处理。这里，我将只介绍和字符串相关的操作。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    CComVariant v1 = &quot;char string&quot;;       // construct from a LPCSTR
    CComVariant v2 = L&quot;wide char string&quot;; // construct from a LPCWSTR
    CComBSTR bs1 = &quot;BSTR bob&quot;;
    CComVariant v3 = (BSTR) bs1;          // copy from a BSTR
    
    // Extracting data
    CComBSTR bs2 = v1.bstrVal;            // extract BSTR from the VARIANT</pre>
<p>　　不像_variant_t，这里没有提供针对VARIANT包含的各种类型的转换操作符。正如上面介绍的，你必须直接访问VARIANT的成员并且确保这个VARIANT变量保存着你期望的类型。如t你需要把一个CComVariant类型的数据转换成一个BSTR类型的数据，你可以调用 ChangeType()方法。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>CComVariant v4 = ... // Init v4 from somewhere
    CComBSTR bs3;
    
    if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))
    bs3 = v4.bstrVal;</pre>
<p>　　像_variant_t一样，CComVariant也没有提供向MBCS字符串转换的转换操作。你需要创建一个_bstr_t类型的中间变量，使用提供从Unicode到MBCS转换的另一个字符串类，或者使用一个ATL的转换宏。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>ATL转换宏</h3>
<p>　　ATL：转换宏是各种字符编码之间进行转换的一种很方便的方式，在函数调用时，它们显得非常有用。ATL转换宏的名称是根据下面的模式来命名的[源类型]2[新类型]或者[源类型]2C[新类型]。据有第二种形式的名字的宏的转换结果是常量指针（对应名字中的&quot;C&quot;）。各种类型的简称如下：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>A: MBCS string, char* (A for ANSI)
    W: Unicode string, wchar_t* (W for wide)
    T: TCHAR string, TCHAR*
    OLE: OLECHAR string, OLECHAR* (in practice, equivalent to W)
    BSTR: BSTR (used as the destination type only)</pre>
<p>　　所以，W2A()宏把一个Unicode字符串转换成一个MBCS字符串。T2CW()宏把一个TCHAR字符串转转成一个Unicode字符串常量。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　为了使用这些宏，需要先包含atlconv.h头文件。你甚至可以在非ATL工程中包含这个头文件来使用其中定义的宏，因为这个头文件独立于ATL中的其他部分，不需要一个_Module全局变量。当你在一个函数中使用转换宏时，需要把USES_CONVERSION宏放在函数的开头。它定义了转换宏所需的一些局部变量。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　当转换的目的类型是除了BSTR以外的其他类型时，被转换的字符串是存在栈中的。所以，如果你想让字符串的生命周期比当前的函数长，你需要把这个字符串拷贝到其他的字符串类中。当目的类型是BSTR时，内存不会自动被释放，你必须把返回值赋给一个BSTR变量或者一个BSTR封装类以避免内存泄漏。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　下面是一些各种转换宏的使用例子：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Functions taking various strings:
    void Foo ( LPCWSTR wstr );
    void Bar ( BSTR bstr );
    // Functions returning strings:
    void Baz ( BSTR* pbstr );
    #include <atlconv.h></atlconv.h>
    main()
    {
    using std::string;
    USES_CONVERSION;    // declare locals used by the ATL macros
    // Example 1: Send an MBCS string to Foo()
    LPCSTR psz1 = &quot;Bob&quot;;
    string str1 = &quot;Bob&quot;;
    
    Foo ( A2CW(psz1) );
    Foo ( A2CW(str1.c_str()) );
  
    // Example 2: Send a MBCS and Unicode string to Bar()
    LPCSTR psz2 = &quot;Bob&quot;;
    LPCWSTR wsz = L&quot;Bob&quot;;
    BSTR bs1;
    CComBSTR bs2;
  
    bs1 = A2BSTR(psz2);         // create a BSTR
    bs2.Attach ( W2BSTR(wsz) ); // ditto, assign to a CComBSTR 
    Bar ( bs1 );
    Bar ( bs2 );
  
    SysFreeString ( bs1 );      // free bs1 memory
    // No need to free bs2 since CComBSTR will do it for us.
  
    // Example 3: Convert the BSTR returned by Baz()
    BSTR bs3 = NULL;
    string str2;
    Baz ( &amp;bs3 );          // Baz() fills in bs3
    str2 = W2CA(bs3);      // convert to an MBCS string
    SysFreeString ( bs3 ); // free bs3 memory
    }</pre>
<p>　　正如你所看见的，当你有一个和函数所需的参数类型不同的字符串时，使用这些转换宏是非常方便的。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>MFC类</h3>
<h3>CString</h3>
<p>　　因为一个MFC CString类的对象包含TCHAR类型的字符，所以确切的字符类型取决于你所定义的预处理符号。大体来说，CString 很像STL string，这意味着你必须把它当成不透明的对象，只能使用CString提供的方法来修改CString对象。CString有一个string所不具备的优点：CString具有接收MBCS和Unicode两种字符串的构造函数，它还有一个LPCTSTR转换符，所以你可以把CString对象直接传给一个接收LPCTSTR的函数而不需要调用c_str()函数。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    CString s1 = &quot;char string&quot;;  // construct from a LPCSTR
    CString s2 = L&quot;wide char string&quot;;  // construct from a LPCWSTR
    CString s3 ( '' '', 100 );  // pre-allocate a 100-byte buffer, fill with spaces
    CString s4 = &quot;New window text&quot;;
    
    // You can pass a CString in place of an LPCTSTR:
    SetWindowText ( hwndSomeWindow, s4 );
  
    // Or, equivalently, explicitly cast the CString:
    SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 );</pre>
<p>　　你可以从你的字符串表中装载一个字符串，CString的一个构造函数和LoadString()函数可以完成它。Format()方法能够从字符串表中随意的读取一个具有一定格式的字符串。　　　　　<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing/loading from string table
    CString s5 ( (LPCTSTR) IDS_SOME_STR );  // load from string table
    CString s6, s7; 
    // Load from string table.
    s6.LoadString ( IDS_SOME_STR );
  
    // Load printf-style format string from the string table:
    s7.Format ( IDS_SOME_FORMAT, &quot;bob&quot;, nSomeStuff, ... );</pre>
<p>　　第一个构造函数看起来有点奇怪，但是这实际上是文档说明的装入一个字符串的方法。注意，对一个CString变量，你可以使用的唯一合法转换符是LPCTSTR。转换成LPTSTR（非常量指针）是错误的。养成把一个CString变量转换成LPTSTR的习惯将会给你带来伤害，因为当你的程序后来崩溃时，你可能不知道为什么，因为你到处都使用同样的代码而那时它们都恰巧正常工作。正确的得到一个指向缓冲区的非常量指针的方法是调用GetBuffer()方法。下面是正确的用法的一个例子，这段代码是给一个列表控件中的项设定文字：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>CString str = _T(&quot;new text&quot;);
    LVITEM item = {0};
    item.mask = LVIF_TEXT;
    item.iItem = 1;
    item.pszText = (LPTSTR)(LPCTSTR) str; // WRONG!
    item.pszText = str.GetBuffer(0);      // correct
  
    ListView_SetItem ( &amp;item );
    str.ReleaseBuffer();  // return control of the buffer to str</pre>
<p>　　pszText成员是一个LPTSTR变量，一个非常量指针，因此你需要对str调用GetBuffer()。GetBuffer()的参数是你需要 CString为缓冲区分配的最小长度。如果因为某些原因，你需要一个可修改的缓冲区来存放1K TCHARs，你需要调用GetBuffer(1024)。把0作为参数时，GetBuffer()返回的是指向字符串当前内容的指针。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　上面划线的语句可以被编译，在这种情况下，甚至可以正常起作用。但这并不意味着这行代码是正确的。通过使用非常量转换，你已经破坏了面向对象的封装，并对 CString的内部实现作了某些假定。如果你有这样的转换习惯，你终将会陷入代码崩溃的境地。你会想代码为什么不能正常工作了，因为你到处都使用同样的代码而那些代码看起来是正确的。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　你知道人们总是抱怨现在的软件的bug是多么的多吗？软件中的bug是因为程序员写了不正确的代码。难道你真的想写一些你知道是错误的代码来为所有的软件都满是bug这种认识做贡献吗？花些时间来学习使用CString的正确方法让你的代码在任何时间都正常工作把。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　CString 有两个函数来从一个 CString 创建一个 BSTR。它们是 AllocSysString() 和SetSysString()。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Converting to BSTR
    CString s5 = &quot;Bob!&quot;;
    BSTR bs1 = NULL, bs2 = NULL;
    bs1 = s5.AllocSysString();
    s5.SetSysString ( &amp;bs2 );
    SysFreeString ( bs1 );
    SysFreeString ( bs2 ); 
 
    COleVariant</pre>
<p>　　COleVariant和CComVariant.很相似。COleVariant继承自VARIANT，所以它可以传给接收VARIANT的函数。然而，不像CComVariant，COleVariant只有一个LPCTSTR构造函数。没有对LPCSTR 和LPCWSTR的构造函数。在大多数情况下这不是一个问题，因为不管怎样你的字符串很可能是LPCTSTRs，但这是一个需要意识到的问题。 COleVariant还有一个接收CString参数的构造函数。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    CString s1 = _T(&quot;tchar string&quot;);
    COleVariant v1 = _T(&quot;Bob&quot;); // construct from an LPCTSTR
    COleVariant v2 = s1; // copy from a CString</pre>
<p>　　像CComVariant一样，你必须直接访问VARIANT的成员。如果需要把VARIANT转换成一个字符串，你应该使用ChangeType()方法。然而，COleVariant::ChangeType()如果失败会抛出异常，而不是返回一个表示失败的HRESULT代码。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Extracting data
    COleVariant v3 = ...; // fill in v3 from somewhere
    BSTR bs = NULL;
    try
    {
    v3.ChangeType ( VT_BSTR );
    bs = v3.bstrVal;
    }
    catch ( COleException* e )
    {
    // error, couldn''t convert
    }
    SysFreeString ( bs );</pre>
<h3>WTL 类</h3>
<h3>CString</h3>
<p>　　WTL的CString的行为和MFC的 CString完全一样，所以你可以参考上面关于MFC的 CString的介绍。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h3>CLR 和 VC 7 类</h3>
<p>　　System::String是用来处理字符串的.NET类。在内部，一个String对象包含一个不可改变的字符串序列。任何对String对象的操作实际上都是返回了一个新的String对象，因为原始的对象是不可改变的。String的一个特性是如果你有不止一个String对象包含相同的字符序列，它们实际上是指向相同的对象的。相对于C++的使用扩展是增加了一个新的字符串常量前缀S，S用来代表一个受控的字符串常量（a managed string literal）。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>// Constructing
    String* ms = S&quot;This is a nice managed string&quot;;</pre>
<p>　　你可以传递一个非受控的字符串来创建一个String对象，但是样会比使用受控字符串来创建String对象造成效率的微小损失。这是因为所有以S作为前缀的相同的字符串实例都代表同样的对象，但这对非受控对象是不适用的。下面的代码清楚地阐明了这一点：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>String* ms1 = S&quot;this is nice&quot;;
    String* ms2 = S&quot;this is nice&quot;;
    String* ms3 = L&quot;this is nice&quot;;
    Console::WriteLine ( ms1 == ms2 ); // prints true
    Console::WriteLine ( ms1 == ms3);  // prints false</pre>
<p>正确的比较可能没有使用S前缀的字符串的方法是使用String::CompareTo()<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>Console::WriteLine ( ms1-&gt;CompareTo(ms2) );
    Console::WriteLine ( ms1-&gt;CompareTo(ms3) );</pre>
<p>　　上面的两行代码都会打印0，0表示两个字符串相等。 String和MFC 7 CString之间的转换是很容易的。CString有一个向LPCTSTR的转换操作，而String有两个接收char* 和 wchar_t*的构造函数，因此你可以把一个CString变量直接传给一个String的构造函数。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>CString s1 ( &quot;hello world&quot; );
    String* s2 ( s1 );  // copy from a CString</pre>
<p>反方向的转换也很类似<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>String* s1 = S&quot;Three cats&quot;;
    CString s2 ( s1 );</pre>
<p>　　这也许会使你感到一点迷惑，但是它确实是起作用的。因为从VS.NET 开始，CString 有了一个接收String 对象的构造函数。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>CStringT ( System::String* pString );</pre>
<p>对于一些快速操作，你可能想访问底层的字符串：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>String* s1 = S&quot;Three cats&quot;;
    Console::WriteLine ( s1 );
    const __wchar_t __pin* pstr = PtrToStringChars(s1);
    for ( int i = 0; i &lt; wcslen(pstr); i++ )
    (*const_cast&lt;__wchar_t*&gt;(pstr+i))++;
    Console::WriteLine ( s1 );</pre>
<p>　　PtrToStringChars()返回一个指向底层字符串的const __wchar_t* ，我们需要固定它，否则垃圾收集器或许会在我们正在管理它的内容的时候移动了它。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>在 printf-style 格式函数中使用字符串类<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　当你在printf()或者类似的函数中使用字符串封装类时你必须十分小心。这些函数包括sprintf()和它的变体，还有TRACE和 ATLTRACE宏。因为这些函数没有对添加的参数的类型检查，你必须小心，只能传给它们C语言风格的字符串指针，而不是一个完整的字符串类。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<p>　　例如，要把一个_bstr_t 字符串传给ATLTRACE()，你必须使用显式转换(LPCSTR) 或者(LPCWSTR)：<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<pre>_bstr_t bs = L&quot;Bob!&quot;;
    ATLTRACE(&quot;The string is: %s in line %dn&quot;, (LPCSTR) bs, nLine);</pre>
<p>　　如果你忘了使用转换符而把整个_bstr_t对象传给了函数，将会显示一些毫无意义的输出，因为_bstr_t保存的内部数据会全部被输出。<a class="w" href="http://www.w3sky.com/">265817669</a></p>
<h2>所有类的总结</h2>
<p>　　两个字符串类之间进行转换的常用方式是：先把源字符串转换成一个C语言风格的字符串指针，然后把这个指针传递给目的类型的构造函数。下面这张表显示了怎样把一个字符串转换成一个C语言风格的字符串指针以及哪些类具有接收C语言风格的字符串指针的构造函数。 265817669</p>


<div > </div>
 <a href="http://hi.baidu.com/fatbsd/blog/item/fd28af13be8cd627dc540113.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/Windows">Windows</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/fd28af13be8cd627dc540113.html#comment">查看评论</a>]]></description>
        <pubDate>2008-03-25  19:53</pubDate>
        <category><![CDATA[Windows]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/fd28af13be8cd627dc540113.html</guid>
</item>

<item>
        <title><![CDATA[C++字符串完全指引一]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/8347d08f669b4beaf11f360a.html]]></link>
        <description><![CDATA[
		
		<h3>引言</h3>
<p>　　毫无疑问，我们都看到过像 TCHAR, std::string, BSTR 等各种各样的字符串类型，还有那些以 _tcs 开头的奇怪的宏。你也许正在盯着显示器发愁。本指引将总结引进各种字符类型的目的，展示一些简单的用法，并告诉您在必要时，如何实现各种字符串类型之间的转换。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　在第一部分，我们将介绍3种字符编码类型。了解各种编码模式的工作方式是很重要的事情。即使你已经知道一个字符串是一个字符数组，你也应该阅读本部分。一旦你了解了这些，你将对各种字符串类型之间的关系有一个清楚地了解。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　在第二部分，我们将单独讲述string类，怎样使用它及实现他们相互之间的转换。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>字符基础 -- ASCII, DBCS, Unicode</h3>
<p>　　所有的 string 类都是以C-style字符串为基础的。C-style 字符串是字符数组。所以我们先介绍字符类型。这里有3种编码模式对应3种字符类型。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　第一种编码类型是单字节字符集（single-byte character set or SBCS）。在这种编码模式下，所有的字符都只用一个字节表示。ASCII是SBCS。一个字节表示的0用来标志SBCS字符串的结束。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　第二种编码模式是多字节字符集（multi-byte character set or MBCS）。一个MBCS编码包含一些一个字节长的字符，而另一些字符大于一个字节的长度。用在Windows里的MBCS包含两种字符类型，单字节字符（single-byte characters）和双字节字符（double-byte characters）。由于Windows里使用的多字节字符绝大部分是两个字节长，所以MBCS常被用DBCS代替。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　在DBCS编码模式中，一些特定的值被保留用来表明他们是双字节字符的一部分。例如，在Shift-JIS编码中（一个常用的日文编码模式），0x81-0x9f之间和 0xe0-oxfc之间的值表示&quot;这是一个双字节字符，下一个字节是这个字符的一部分。&quot;这样的值被称作&quot;leading bytes&quot;,他们都大于0x7f。跟随在一个leading byte字节后面的字节被称作&quot;trail byte&quot;。在DBCS中，trail byte可以是任意非0值。像SBCS一样，DBCS字符串的结束标志也是一个单字节表示的0。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　第三种编码模式是Unicode。Unicode是一种所有的字符都使用两个字节编码的编码模式。Unicode字符有时也被称作宽字符，因为它比单字节字符宽（使用了更多的存储空间）。注意，Unicode不能被看作MBCS。MBCS的独特之处在于它的字符使用不同长度的字节编码。Unicode 字符串使用两个字节表示的0作为它的结束标志。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　单字节字符包含拉丁文字母表，accented characters及ASCII标准和DOS操作系统定义的图形字符。双字节字符被用来表示东亚及中东的语言。Unicode被用在COM及Windows NT操作系统内部。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　你一定已经很熟悉单字节字符。当你使用char时，你处理的是单字节字符。双字节字符也用char类型来进行操作（这是我们将会看到的关于双字节字符的很多奇怪的地方之一）。Unicode字符用wchar_t来表示。Unicode字符和字符串常量用前缀L来表示。例如：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>wchar_t wch = L''1''; // 2 bytes, 0x0031
    wchar_t* wsz = L&quot;Hello&quot;; // 12 bytes, 6 wide characters</pre>
<p><a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>字符在内存中是怎样存储的</h3>
<p>　　单字节字符串：每个字符占一个字节按顺序依次存储，最后以单字节表示的0结束。例如。&quot;Bob&quot;的存贮形式如下：<br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="25%">42</td>
            <td align="center" width="25%">6F</td>
            <td align="center" width="25%">62</td>
            <td align="center" width="25%">00</td>
        </tr>
        <tr>
            <td align="center" width="25%">B</td>
            <td align="center" width="25%">o</td>
            <td align="center" width="25%">b</td>
            <td align="center" width="25%">BOS</td>
        </tr>
    </tbody>
</table>
<p>Unicode的存储形式，L&quot;Bob&quot;<br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="25%">42 00</td>
            <td align="center" width="25%">6F 00</td>
            <td align="center" width="25%">62 00</td>
            <td align="center" width="25%">00 00</td>
        </tr>
        <tr>
            <td align="center" width="25%">B</td>
            <td align="center" width="25%">o</td>
            <td align="center" width="25%">b</td>
            <td align="center" width="25%">BOS</td>
        </tr>
    </tbody>
</table>
<p>使用两个字节表示的0x0000来做结束标志。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　一眼看上去，DBCS 字符串很像 SBCS 字符串，但是我们一会儿将看到 DBCS 字符串的微妙之处，它使得使用字符串操作函数和永字符指针遍历一个字符串时会产生预料之外的结果。字符串&quot;日本语 &quot; (&quot;nihongo&quot;)在内存中的存储形式如下（LB和TB分别用来表示 leading byte 和 trail byte）<br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="25%" height="20">93 FA</td>
            <td align="center" width="25%" height="20">96 7B</td>
            <td align="center" width="25%" height="20">8C EA</td>
            <td align="center" width="25%" height="20">00</td>
        </tr>
        <tr>
            <td align="center" width="25%" height="20">LB TB</td>
            <td align="center" width="25%" height="20">LB TB</td>
            <td align="center" width="25%" height="20">LB TB</td>
            <td align="center" width="25%" height="20">EOS</td>
        </tr>
        <tr>
            <td align="center" width="25%" height="20">日</td>
            <td align="center" width="25%" height="20">本</td>
            <td align="center" width="25%" height="20">语</td>
            <td align="center" width="25%" height="20">EOS</td>
        </tr>
    </tbody>
</table>
<p>值得注意的是，&quot;ni&quot;的值不能被解释成WORD型值0xfa93，而应该看作两个值93和fa以这种顺序被作为&quot;ni&quot;的编码。(So on a big-endian CPU, the bytes would still be in the order shown above.)<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>使用字符串处理函数</h3>
<p>　　我们都已经见过C语言中的字符串函数，strcpy(), sprintf(), atoll()等。这些字符串只应该用来处理单字节字符字符串。标准库也提供了仅适用于Unicode类型字符串的函数，比如wcscpy(), swprintf(), wtol()等。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　微软还在它的CRT(C runtime library)中增加了操作DBCS字符串的版本。Str***()函数都有对应名字的DBCS版本_mbs***()。如果你料到可能会遇到DBCS 字符串（如果你的软件会被安装在使用DBCS编码的国家，如中国，日本等，你就可能会），你应该使用_mbs***()函数，因为他们也可以处理SBCS 字符串。（一个DBCS字符串也可能含有单字节字符，这就是为什么_mbs***()函数也能处理SBCS字符串的原因）<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　让我们来看一个典型的字符串来阐明为什么需要不同版本的字符串处理函数。我们还是使用前面的Unicode字符串 L&quot;Bob&quot;：<br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<table cellspacing="0" cellpadding="0" width="500" border="1">
    <tbody>
        <tr>
            <td align="center" width="25%">42 00</td>
            <td align="center" width="25%">6F 00</td>
            <td align="center" width="25%">62 00</td>
            <td align="center" width="25%">00 00</td>
        </tr>
        <tr>
            <td align="center" width="25%">B</td>
            <td align="center" width="25%">o</td>
            <td align="center" width="25%">b</td>
            <td align="center" width="25%">BOS</td>
        </tr>
    </tbody>
</table>
<p><br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　因为x86CPU是little-endian，值0x0042在内存中的存储形式是42 00。你能看出如果这个字符串被传给strlen()函数会出现什么问题吗？它将先看到第一个字节42，然后是00，而00是字符串结束的标志，于是 strlen()将会返回1。如果把&quot;Bob&quot;传给wcslen()，将会得出更坏的结果。wcslen()将会先看到0x6f42，然后是 0x0062，然后一直读到你的缓冲区的末尾，直到发现00 00结束标志或者引起了GPF。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　到目前为止，我们已经讨论了str***()和wcs***()的用法及它们之间的区别。Str***()和_mbs**()之间的有区别区别呢？明白他们之间的区别，对于采用正确的方法来遍历DBCS字符串是很重要的。下面，我们将先介绍字符串的遍历，然后回到str***()与_mbs***() 之间的区别这个问题上来。<br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>正确的遍历和索引字符串</h3>
<p>　　因为我们中大多数人都是用着SBCS字符串成长的，所以我们在遍历字符串时，常常使用指针的++-和-操作。我们也使用数组下标的表示形式来操作字符串中的字符。这两种方式是用于SBCS和Unicode字符串，因为它们中的字符有着相同的宽度，编译器能正确的返回我们需要的字符。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　然而，当碰到DBCS字符串时，我们必须抛弃这些习惯。这里有使用指针遍历DBCS字符串时的两条规则。违背了这两条规则，你的程序就会存在DBCS有关的bugs。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3># 1．在前向遍历时，不要使用++操作，除非你每次都检查lead byte；</h3>
<h3># 2．永远不要使用-操作进行后向遍历。</h3>
<p>　　我们先来阐述规则2，因为找到一个违背它的真实的实例代码是很容易的。假设你有一个程序在你自己的目录里保存了一个设置文件，你把安装目录保存在注册表中。在运行时，你从注册表中读取安装目录，然后合成配置文件名，接着读取该文件。假设，你的安装目录是C:Program FilesMyCoolApp，那么你合成的文件名应该是C:Program FilesMyCoolAppconfig.bin。当你进行测试时，你发现程序运行正常。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　现在，想象你合成文件名的代码可能是这样的：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>bool GetConfigFileName ( char* pszName, size_t nBuffSize )
    {
    char szConfigFilename[MAX_PATH];
  
    // Read install dir from registry... we''ll assume it succeeds.
  
    // Add on a backslash if it wasn''t present in the registry value.
    // First, get a pointer to the terminating zero.
    char* pLastChar = strchr ( szConfigFilename, '''' );
  
    // Now move it back one character.
    pLastChar--; 
  
    if ( *pLastChar != ''\'' )
    strcat ( szConfigFilename, &quot;\&quot; );
  
    // Add on the name of the config file.
    strcat ( szConfigFilename, &quot;config.bin&quot; );
  
    // If the caller''s buffer is big enough, return the filename.
    if ( strlen ( szConfigFilename ) &gt;= nBuffSize )
    return false;
    else
    {
    strcpy ( pszName, szConfigFilename );
    return true;
    }
    }</pre>
<p>　　这是一段很健壮的代码，然而在遇到 DBCS 字符时它将会出错。让我们来看看为什么。假设一个中国用户使用了你的程序，把它安装在 C:伟大祖国。下面是这个名字在内存中的存储形式：<br>
　 <br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<table bordercolor="#010000" cellspacing="0" cellpadding="0" width="500">
    <tbody>
        <tr>
            <td align="center" width="12%">43</td>
            <td align="center" width="12%">3A</td>
            <td align="center" width="12%"><span class="STYLE1">5C</span></td>
            <td align="center" width="12%">83 88</td>
            <td align="center" width="13%">83 45</td>
            <td align="center" width="13%">83 52</td>
            <td align="center" width="13%">83 <span class="STYLE1">5C</span></td>
            <td align="center" width="13%">00</td>
        </tr>
        <tr>
            <td align="center" width="12%">　</td>
            <td align="center" width="12%">　</td>
            <td align="center" width="12%">　</td>
            <td align="center" width="12%">LB TB</td>
            <td align="center" width="13%">LB TB</td>
            <td align="center" width="13%">LB TB</td>
            <td align="center" width="13%">LB TB</td>
            <td align="center" width="13%">　</td>
        </tr>
        <tr>
            <td align="center" width="12%">C</td>
            <td align="center" width="12%">:</td>
            <td align="center" width="12%"> </td>
            <td align="center" width="12%">伟</td>
            <td align="center" width="13%">大</td>
            <td align="center" width="13%">祖</td>
            <td align="center" width="13%">国</td>
            <td align="center" width="13%"><span>EOS</span></td>
        </tr>
    </tbody>
</table>
<p><br>
<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　当使用 GetConfigFileName() 检查尾部的''\''时，它寻找安装目录名中最后的非0字节，看它是等于''\''的，所以没有重新增加一个''\''。结果是代码返回了错误的文件名。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　哪里出错了呢？看看上面两个被用蓝色高量显示的字节。斜杠''\''的值是0x5c。''国 ''的值是83 5c。上面的代码错误的读取了一个 trail byte，把它当作了一个字符。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　正确的后向遍历方法是使用能够识别DBCS字符的函数，使指针移动正确的字节数。下面是正确的代码。（指针移动的地方用红色标明）<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )
    {
    char szConfigFilename[MAX_PATH];
  
    // Read install dir from registry... we''ll assume it succeeds.
  
    // Add on a backslash if it wasn''t present in the registry value.
    // First, get a pointer to the terminating zero.
    char* pLastChar = _mbschr ( szConfigFilename, '''' );
  
    // Now move it back one double-byte character.
    <span class="STYLE2">pLastChar = CharPrev ( szConfigFilename, pLastChar );</span>
  
    if ( *pLastChar != ''\'' )
    _mbscat ( szConfigFilename, &quot;\&quot; );
  
    // Add on the name of the config file.
    _mbscat ( szConfigFilename, &quot;config.bin&quot; );
 
 // If the caller''s buffer is big enough, return the filename.
    if ( _mbslen ( szInstallDir ) &gt;= nBuffSize )
    return false;
    else
    {
    _mbscpy ( pszName, szConfigFilename );
    return true;
    }
    }</pre>
<p>　　上面的函数使用CharPrev() API使pLastChar向后移动一个字符，这个字符可能是两个字节长。在这个版本里，if条件正常工作，因为lead byte永远不会等于0x5c。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　让我们来想象一个违背规则1的场合。例如，你可能要检测一个用户输入的文件名是否多次出现了'':''。如果，你使用++操作来遍历字符串，而不是使用CharNext()，你可能会发出不正确的错误警告如果恰巧有一个trail byte它的值的等于'':''的值。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>与规则2相关的关于字符串索引的规则：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>2a. 永远不要使用减法去得到一个字符串的索引。</h3>
<p>违背这条规则的代码和违背规则2的代码很相似。例如，<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>char* pLastChar = &amp;szConfigFilename [strlen(szConfigFilename) - 1];</pre>
<p>这和向后移动一个指针是同样的效果。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>回到关于str***()和_mbs***()的区别<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　现在，我们应该很清楚为什么_mbs***()函数是必需的。Str***()函数根本不考虑DBCS字符，而_mbs***()考虑。如果，你调用strrchr(&quot;C:\ &quot;, ''\'')，返回结果可能是错误的，然而_mbsrchr()将会认出最后的双字节字符，返回一个指向真的''\''的指针。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　关于字符串函数的最后一点：str***()和_mbs***()函数认为字符串的长度都是以char来计算的。所以，如果一个字符串包含3个双字节字符，_mbslen()将会返回6。Unicode函数返回的长度是按wchar_t来计算的。例如，wcslen(L&quot;Bob&quot;)返回3。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>Win32 API中的MBCS和Unicode</h3>
<h3>两组 APIs：</h3>
<p>　　尽管你也许从来没有注意过，Win32中的每个与字符串相关的API和message都有两个版本。一个版本接受MBCS字符串，另一个接受 Unicode字符串。例如，根本没有SetWindowText()这个API，相反，有SetWindowTextA()和 SetWindowTextW()。后缀A表明这是MBCS函数，后缀W表示这是Unicode版本的函数。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　当你 build 一个 Windows 程序，你可以选择是用 MBCS 或者 Unicode APIs。如果，你曾经用过VC向导并且没有改过预处理的设置，那表明你用的是MBCS版本。那么，既然没有 SetWindowText() API，我们为什么可以使用它呢？winuser.h头文件包含了一些宏，例如：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );
    BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString );
    
    #ifdef UNICODE
    #define SetWindowText  SetWindowTextW
    #else
    #define SetWindowText  SetWindowTextA
    #endif</pre>
<p>当使用MBCS APIs来build程序时，UNICODE没有被定义，所以预处理器看到：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>#define SetWindowText SetWindowTextA</pre>
<p>　　这个宏定义把所有对SetWindowText的调用都转换成真正的API函数SetWindowTextA。（当然，你可以直接调用SetWindowTextA() 或者 SetWindowTextW()，虽然你不必那么做。）<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　所以，如果你想把默认使用的API函数变成Unicode版的，你可以在预处理器设置中，把_MBCS从预定义的宏列表中删除，然后添加UNICODE和_UNICODE。(你需要两个都定义，因为不同的头文件可能使用不同的宏。) 然而，如果你用char来定义你的字符串，你将会陷入一个尴尬的境地。考虑下面的代码：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>HWND hwnd = GetSomeWindowHandle();
    char szNewText[] = &quot;we love Bob!&quot;;
    SetWindowText ( hwnd, szNewText );</pre>
<p>在预处理器把SetWindowText用SetWindowTextW来替换后，代码变成：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>HWND hwnd = GetSomeWindowHandle();
    char szNewText[] = &quot;we love Bob!&quot;;
    SetWindowTextW ( hwnd, szNewText );</pre>
<p>　　看到问题了吗？我们把单字节字符串传给了一个以Unicode字符串做参数的函数。解决这个问题的第一个方案是使用 #ifdef 来包含字符串变量的定义：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>HWND hwnd = GetSomeWindowHandle();
    #ifdef UNICODE
    wchar_t szNewText[] = L&quot;we love Bob!&quot;;
    #else
    char szNewText[] = &quot;we love Bob!&quot;;
    #endif
    SetWindowText ( hwnd, szNewText );</pre>
<p>你可能已经感受到了这样做将会使你多么的头疼。完美的解决方案是使用TCHAR.<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>使用TCHAR</h3>
<p>　　TCHAR是一种字符串类型，它让你在以MBCS和UNNICODE来build程序时可以使用同样的代码，不需要使用繁琐的宏定义来包含你的代码。TCHAR的定义如下：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>#ifdef UNICODE
    typedef wchar_t TCHAR;
    #else
    typedef char TCHAR;
    #endif</pre>
<p>所以用MBCS来build时，TCHAR是char，使用UNICODE时，TCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>#ifdef UNICODE
    #define _T(x) L##x
    #else
    #define _T(x) x
    #endif</pre>
<p>　　##是一个预处理操作符，它可以把两个参数连在一起。如果你的代码中需要字符串常量，在它前面加上_T宏。如果你使用Unicode来build，它会在字符串常量前加上L前缀。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<pre>TCHAR szNewText[] = _T(&quot;we love Bob!&quot;);</pre>
<p>　　像是用宏来隐藏SetWindowTextA/W的细节一样，还有很多可以供你使用的宏来实现str***()和_mbs***()等字符串函数。例如，你可以使用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根据你预定义的宏是_MBCS 还是UNICODE来扩展成正确的函数，就像SetWindowText所作的一样。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　不仅str***()函数有TCHAR宏。其他的函数如， _stprintf（代替sprinft()和swprintf()）,_tfopen（代替fopen()和_wfopen()）。 MSDN中&quot;Generic-Text Routine Mappings.&quot;标题下有完整的宏列表。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>字符串和TCHAR typedefs</h3>
<p>　　由于Win32 API文档的函数列表使用函数的常用名字（例如，&quot;SetWindowText&quot;），所有的字符串都是用TCHAR来定义的。（除了XP中引入的只适用于 Unicode的API）。下面列出一些常用的typedefs，你可以在msdn中看到他们。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<table cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td align="center" width="16%"><strong>type </strong></td>
            <td align="center" width="42%"><strong>Meaning in MBCS builds </strong></td>
            <td align="center" width="42%"><strong>Meaning in Unicode builds</strong></td>
        </tr>
        <tr>
            <td width="16%">WCHAR</td>
            <td width="42%">wchar_t</td>
            <td width="42%">wchar_t</td>
        </tr>
        <tr>
            <td width="16%">LPSTR</td>
            <td width="42%">zero-terminated string of char (char*)</td>
            <td width="42%">zero-terminated string of char (char*)</td>
        </tr>
        <tr>
            <td width="16%">LPCSTR</td>
            <td width="42%">constant zero-terminated string of char (const char*)</td>
            <td width="42%">constant zero-terminated string of char (const char*)</td>
        </tr>
        <tr>
            <td width="16%">LPWSTR</td>
            <td width="42%">zero-terminated Unicode string (wchar_t*)</td>
            <td width="42%">zero-terminated Unicode string (wchar_t*)</td>
        </tr>
        <tr>
            <td width="16%">LPCWSTR</td>
            <td width="42%">constant zero-terminated Unicode string (const wchar_t*)</td>
            <td width="42%">constant zero-terminated Unicode string (const wchar_t*)</td>
        </tr>
        <tr>
            <td width="16%">TCHAR</td>
            <td width="42%">char</td>
            <td width="42%">wchar_t</td>
        </tr>
        <tr>
            <td width="16%">LPTSTR</td>
            <td width="42%">zero-terminated string of TCHAR (TCHAR*)</td>
            <td width="42%">zero-terminated string of TCHAR (TCHAR*)</td>
        </tr>
        <tr>
            <td width="16%">LPCTSTR</td>
            <td width="42%">constant zero-terminated string of TCHAR (const TCHAR*)</td>
            <td width="42%">constant zero-terminated string of TCHAR (const TCHAR*)</td>
        </tr>
    </tbody>
</table>
<p><a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<h3>何时使用 TCHAR 和 Unicode</h3>
<p>　　到现在，你可能会问，我们为什么要使用Unicode。我已经用了很多年的char。下列3种情况下，使用Unicode将会使你受益：<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p># 1．你的程序只运行在Windows NT系统中。<br>
# 2． 你的程序需要处理超过MAX_PATH个字符长的文件名。<br>
# 3． 你的程序需要使用XP中引入的只有Unicode版本的API.<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　Windows 9x 中大多数的 API 没有实现 Unicode 版本。所以，如果你的程序要在windows 9x中运行，你必须使用MBCS APIs。然而，由于NT系统内部都使用Unicode，所以使用Unicode APIs将会加快你的程序的运行速度。每次，你传递一个字符串调用MBCS API，操作系统会把这个字符串转换成Unicode字符串，然后调用对应的Unicode API。如果一个字符串被返回，操作系统还要把它转变回去。尽管这个转换过程被高度优化了，但它对速度造成的损失是无法避免的。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　只要你使用Unicode API，NT系统允许使用非常长的文件名（突破了MAX_PATH的限制，MAX_PATH=260）。使用Unicode API的另一个优点是你的程序会自动处理用户输入的各种语言。所以一个用户可以输入英文，中文或者日文，而你不需要额外编写代码去处理它们。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　最后，随着windows 9x产品的淡出，微软似乎正在抛弃MBCS APIs。例如，包含两个字符串参数的SetWindowTheme() API只有Unicode版本的。使用Unicode来build你的程序将会简化字符串的处理，你不必在MBCS和Unicdoe之间相互转换。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>
<p>　　即使你现在不使用Unicode来build你的程序，你也应该使用TCHAR及其相关的宏。这样做不仅可以的代码可以很好地处理DBCS，而且如果将来你想用Unicode来build你的程序，你只需要改变一下预处理器中的设置就可以实现了。<a class="w" href="http://www.w3sky.com/">2005089632</a></p>


<div >  </div>
 <a href="http://hi.baidu.com/fatbsd/blog/item/8347d08f669b4beaf11f360a.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/Windows">Windows</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/8347d08f669b4beaf11f360a.html#comment">查看评论</a>]]></description>
        <pubDate>2008-03-25  19:39</pubDate>
        <category><![CDATA[Windows]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/8347d08f669b4beaf11f360a.html</guid>
</item>

<item>
        <title><![CDATA[VC命名规则]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/79bdcf18add5080334fa41f8.html]]></link>
        <description><![CDATA[
		
		<p><font size="2">一、程序风格：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  1、严格采用阶梯层次组织程序代码：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  各层次缩进的分格采用VC的缺省风格，即每层次缩进为4格，括号位于下一行。要求相匹配的大括号在同一列，对继行则要求再缩进4格。例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  2、提示信息字符串的位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  在程序中需要给出的提示字符串，为了支持多种语言的开发，除了一些给调试用的临时信息外，其他所有的提示信息必须定义在资源中。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  3、对变量的定义，尽量位于函数的开始位置。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></p>
<p><font size="2">二、命名规则：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  1、变量名的命名规则&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ①、变量的命名规则要求用&ldquo;匈牙利法则&rdquo;。即开头字母用变量的类型，其余部分用变量的英文意思或其英文意思的缩写,尽量避免用中文的拼音,要求单词的第一个字母应大写。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  即：&nbsp;&nbsp;&nbsp;&nbsp;  变量名=变量类型+变量的英文意思（或缩写）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对非通用的变量，在定义时加入注释说明，变量定义尽量可能放在函数的开始处。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  见下表：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  bool(BOOL)&nbsp;&nbsp;&nbsp;&nbsp;  用b开头&nbsp;&nbsp;&nbsp;&nbsp;  bIsParent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  byte(BYTE)&nbsp;&nbsp;&nbsp;&nbsp;  用by开头&nbsp;&nbsp;&nbsp;&nbsp;  byFlag&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  short(int)&nbsp;&nbsp;&nbsp;&nbsp;  用n开头&nbsp;&nbsp;&nbsp;&nbsp;  nStepCount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  long(LONG)&nbsp;&nbsp;&nbsp;&nbsp;  用l开头&nbsp;&nbsp;&nbsp;&nbsp;  lSum&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  char(CHAR)&nbsp;&nbsp;&nbsp;&nbsp;  用c开头&nbsp;&nbsp;&nbsp;&nbsp;  cCount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  float(FLOAT)&nbsp;&nbsp;&nbsp;&nbsp;  用f开头&nbsp;&nbsp;&nbsp;&nbsp;  fAvg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  double(DOUBLE)&nbsp;&nbsp;&nbsp;&nbsp;  用d开头&nbsp;&nbsp;&nbsp;&nbsp;  dDeta&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  void(VOID)&nbsp;&nbsp;&nbsp;&nbsp;  用v开头&nbsp;&nbsp;&nbsp;&nbsp;  vVariant&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  unsigned&nbsp;&nbsp;&nbsp;&nbsp;  int（WORD）&nbsp;&nbsp;&nbsp;&nbsp;  用w开头&nbsp;&nbsp;&nbsp;&nbsp;  wCount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  unsigned&nbsp;&nbsp;&nbsp;&nbsp;  long(DWORD)&nbsp;&nbsp;&nbsp;&nbsp;  用dw开头&nbsp;&nbsp;&nbsp;&nbsp;  dwBroad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  HANDLE（HINSTANCE）&nbsp;&nbsp;&nbsp;&nbsp;  用h开头&nbsp;&nbsp;&nbsp;&nbsp;  hHandle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  DWORD&nbsp;&nbsp;&nbsp;&nbsp;  用dw开头&nbsp;&nbsp;&nbsp;&nbsp;  dwWord&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  LPCSTR(LPCTSTR)&nbsp;&nbsp;&nbsp;&nbsp;  用str开头&nbsp;&nbsp;&nbsp;&nbsp;  strString&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  用0结尾的字符串&nbsp;&nbsp;&nbsp;&nbsp;  用sz开头&nbsp;&nbsp;&nbsp;&nbsp;  szFileName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对未给出的变量类型要求提出并给出命名建议给技术委员会。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ②、指针变量命名的基本原则为：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对一重指针变量的基本原则为：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  &ldquo;p&rdquo;+变量类型前缀+命名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如一个float*型应该表示为pfStat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对多重指针变量的基本规则为：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  二重指针：&nbsp;&nbsp;&nbsp;&nbsp;  &ldquo;pp&rdquo;+变量类型前缀+命名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  三重指针：&nbsp;&nbsp;&nbsp;&nbsp;  &ldquo;ppp&rdquo;+变量类型前缀+命名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ......&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ③、全局变量用g_开头,如一个全局的长型变量定义为g_lFailCount,即：变量名=g_+变量类型+变量的英文意思（或缩写）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ④、静态变量用s_开头,如一个静态的指针变量定义为s_plPerv_Inst,即：&nbsp;&nbsp;&nbsp;&nbsp;  变量名=s_+变量类型+变量的英文意思（或缩写）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑤、成员变量用m_开头,如一个长型成员变量定义为m_lCount;即：变量名=m_+变量类型+变量的英文意思（或缩写）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑥、对枚举类型（enum）中的变量，要求用枚举变量或其缩写做前缀。并且要求用大写。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如：enum&nbsp;&nbsp;&nbsp;&nbsp;  cmEMDAYS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  EMDAYS_MONDAY;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  EMDAYS_TUESDAY;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ……&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  };&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑦、对struct、union、class变量的命名要求定义的类型用大写。并要加上前缀，其内部变量的命名规则与变量命名规则一致。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  结构一般用S开头&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如：struct&nbsp;&nbsp;&nbsp;&nbsp;  ScmNPoint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  int&nbsp;&nbsp;&nbsp;&nbsp;  nX;//点的X位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  int&nbsp;&nbsp;&nbsp;&nbsp;  nY;&nbsp;&nbsp;&nbsp;&nbsp;  //点的Y位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  };&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  联合体一般用U开头&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如:&nbsp;&nbsp;&nbsp;&nbsp;  union&nbsp;&nbsp;&nbsp;&nbsp;  UcmLPoint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  long&nbsp;&nbsp;&nbsp;&nbsp;  lX;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  long&nbsp;&nbsp;&nbsp;&nbsp;  lY;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  类一般用C开头&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  class&nbsp;&nbsp;&nbsp;&nbsp;  CcmFPoint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  public:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  float&nbsp;&nbsp;&nbsp;&nbsp;  fPoint;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  };&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对一般的结构应该定义为类模板，为以后的扩展性考虑&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  template&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  class&nbsp;&nbsp;&nbsp;&nbsp;  CcmTVector3d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  public:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  TYPE&nbsp;&nbsp;&nbsp;&nbsp;  x,y,z;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  };&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑧、对常量（包括错误的编码）命名，要求常量名用大写，常量名用英文表达其意思。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如：#define&nbsp;&nbsp;&nbsp;&nbsp;  CM_FILE_NOT_FOUND&nbsp;&nbsp;&nbsp;&nbsp;  CMMAKEHR(0X20B)&nbsp;&nbsp;&nbsp;&nbsp;  其中CM表示类别。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑨、对const&nbsp;&nbsp;&nbsp;&nbsp;  的变量要求在变量的命名规则前加入c_,即：c_+变量命名规则；例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  const&nbsp;&nbsp;&nbsp;&nbsp;  char*&nbsp;&nbsp;&nbsp;&nbsp;  c_szFileName;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  2、&nbsp;&nbsp;&nbsp;&nbsp;  函数的命名规范：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  函数的命名应该尽量用英文表达出函数完成的功能。遵循动宾结构的命名法则，函数名中动词在前,并在命名前加入函数的前缀，函数名的长度不得少于8个字母。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  long&nbsp;&nbsp;&nbsp;&nbsp;  cmGetDeviceCount(……);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  3、函数参数规范：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ①、&nbsp;&nbsp;&nbsp;&nbsp;  参数名称的命名参照变量命名规范。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ②、&nbsp;&nbsp;&nbsp;&nbsp;  为了提高程序的运行效率，减少参数占用的堆栈，传递大结构的参数，一律采用指针或引用方式传递。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ③、&nbsp;&nbsp;&nbsp;&nbsp;  为了便于其他程序员识别某个指针参数是入口参数还是出口参数，同时便于编译器检查错误，应该在入口参数前加入const标志。如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ……cmCopyString(const&nbsp;&nbsp;&nbsp;&nbsp;  char&nbsp;&nbsp;&nbsp;&nbsp;  *&nbsp;&nbsp;&nbsp;&nbsp;  c_szSource,&nbsp;&nbsp;&nbsp;&nbsp;  char&nbsp;&nbsp;&nbsp;&nbsp;  *&nbsp;&nbsp;&nbsp;&nbsp;  szDest)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  4、引出函数规范：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对于从动态库引出作为二次开发函数公开的函数，为了能与其他函数以及Windows的函数区分，采用类别前缀+基本命名规则的方法命名。例如：在对动态库中引出的一个图象编辑的函数定义为&nbsp;&nbsp;&nbsp;&nbsp;  imgFunctionname(其中img为image缩写)。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  现给出三种库的命名前缀：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ①、&nbsp;&nbsp;&nbsp;&nbsp;  对通用函数库，采用cm为前缀。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ②、&nbsp;&nbsp;&nbsp;&nbsp;  对三维函数库，采用vr为前缀。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ③、&nbsp;&nbsp;&nbsp;&nbsp;  对图象函数库，采用img为前缀。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对宏定义，结果代码用同样的前缀。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  5、文件名(包括动态库、组件、控件、工程文件等)的命名规范：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  文件名的命名要求表达出文件的内容，要求文件名的长度不得少于5个字母，严禁使用象file1,myfile之类的文件名。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></p>
<p><font size="2">三、注释规范：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  1、函数头的注释&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对于函数，应该从&ldquo;功能&rdquo;，&ldquo;参数&rdquo;，&ldquo;返回值&rdquo;、&ldquo;主要思路&rdquo;、&ldquo;调用方法&rdquo;、&ldquo;日期&rdquo;六个方面用如下格式注释：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //程序说明开始&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //================================================================//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  功能：&nbsp;&nbsp;&nbsp;&nbsp;  从一个String&nbsp;&nbsp;&nbsp;&nbsp;  中删除另一个String。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  参数：&nbsp;&nbsp;&nbsp;&nbsp;  strByDelete,strToDelete&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  （入口）&nbsp;&nbsp;&nbsp;&nbsp;  strByDelete:&nbsp;&nbsp;&nbsp;&nbsp;  被删除的字符串（原来的字符串）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  （出口）&nbsp;&nbsp;&nbsp;&nbsp;  strToDelete:&nbsp;&nbsp;&nbsp;&nbsp;  要从上个字符串中删除的字符串。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  返回：&nbsp;&nbsp;&nbsp;&nbsp;  找到并删除返回1，否则返回0。（对返回值有错误编码的要//&nbsp;&nbsp;&nbsp;&nbsp;  求列出错误编码）。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  主要思路：本算法主要采用循环比较的方法来从strByDelete中找到&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  与strToDelete相匹配的字符串，对多匹配strByDelete&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  中有多个strToDelete子串）的情况没有处理。请参阅：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  书名......&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  调用方法：......&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  日期：起始日期，如：2000/8/21.9:40--2000/8/23.21:45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //================================================================//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  函数名(……)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //程序说明结束&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ①、&nbsp;&nbsp;&nbsp;&nbsp;  对于某些函数，其部分参数为传入值，而部分参数为传出值，所以对参数要详细说明该参数是入口参数，还是出口参数，对于某些意义不明确的参数还要做详细说明（例如：以角度作为参数时，要说明该角度参数是以弧度（PI）,还是以度为单位）,对既是入口又是出口的变量应该在入口和出口处同时标明。等等。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ②、&nbsp;&nbsp;&nbsp;&nbsp;  函数的注释应该放置在函数的头文件中，在实现文件中的该函数的实现部分应该同时放置该注释。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ③、&nbsp;&nbsp;&nbsp;&nbsp;  在注释中应该详细说明函数的主要实现思路、特别要注明自己的一些想法，如果有必要则应该写明对想法产生的来由。对一些模仿的函数应该注释上函数的出处。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ④、&nbsp;&nbsp;&nbsp;&nbsp;  在注释中详细注明函数的适当调用方法，对于返回值的处理方法等。在注释中要强调调用时的危险方面，可能出错的地方。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑤、&nbsp;&nbsp;&nbsp;&nbsp;  对日期的注释要求记录从开始写函数到结束函数的测试之间的日期。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ⑥、&nbsp;&nbsp;&nbsp;&nbsp;  对函数注释开始到函数命名之间应该有一组用来标识的特殊字符串。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  如果算法比较复杂，或算法中的变量定义与位置有关，则要求对变量的定义进行图解。对难以理解的算法能图解尽量图解。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  2、变量的注释：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对于变量的注释紧跟在变量的后面说明变量的作用。原则上对于每个变量应该注释，但对于意义非常明显的变量，如：i,j等循环变量可以不注释。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  例如：&nbsp;&nbsp;&nbsp;&nbsp;  long&nbsp;&nbsp;&nbsp;&nbsp;  lLineCount&nbsp;&nbsp;&nbsp;&nbsp;  //线的根数。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  　3、文件的注释：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  文件应该在文件开头加入以下注释：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  /////////////////////////////////////////////////////////////////////&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  工程:&nbsp;&nbsp;&nbsp;&nbsp;  文件所在的项目名。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  作者：**，修改者：**&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  描述:说明文件的功能。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  主要函数：…………&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  版本:&nbsp;&nbsp;&nbsp;&nbsp;  说明文件的版本，完成日期。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  修改:&nbsp;&nbsp;&nbsp;&nbsp;  说明对文件的修改内容、修改原因以及修改日期。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //&nbsp;&nbsp;&nbsp;&nbsp;  参考文献：&nbsp;&nbsp;&nbsp;&nbsp;  ......&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  /////////////////////////////////////////////////////////////////////&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  为了头文件被重复包含要求对头文件进行定义如下:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  #ifndef&nbsp;&nbsp;&nbsp;&nbsp;  __FILENAME_H__&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  #define&nbsp;&nbsp;&nbsp;&nbsp;  __FILENAME_H__&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  其中FILENAME为头文件的名字。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  　　　4、其他注释：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  在函数内我们不需要注释每一行语句。但必须在各功能模块的每一主要部分之前添加块注释，注释每一组语句，在循环、流程的各分支等，尽可能多加以注释。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  其中的循环、条件、选择等位置必须注释。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对于前后顺序不能颠倒的情况，建议在注释中增加序号。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  在其他顺序执行的程序中，每隔3&mdash;5行语句，必须加一个注释，注明这一段语句所组成的小模块的作用。对于自己的一些比较独特的思想要求在注释中标明。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></p>
<p><font size="2">四、程序健壮性：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  1、函数的返回值规范：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对于函数的返回位置，尽量保持单一性，即一个函数尽量做到只有一个返回位置。(单入口单出口)。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  要求大家统一函数的返回值，所有的函数的返回值都将以编码的方式返回。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  例如编码定义如下：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  #define&nbsp;&nbsp;&nbsp;&nbsp;  CM_POINT_IS_NULL&nbsp;&nbsp;&nbsp;&nbsp;  CMMAKEHR(0X200)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  建议函数实现如下：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  long&nbsp;&nbsp;&nbsp;&nbsp;  函数名(参数,……)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  long&nbsp;&nbsp;&nbsp;&nbsp;  lResult;&nbsp;&nbsp;&nbsp;&nbsp;  //保持错误号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  lResult=CM_OK;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  //如果参数有错误则返回错误号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  if(参数==NULL)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  lResult=CM_POINT_IS_NULL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  goto&nbsp;&nbsp;&nbsp;&nbsp;  END;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  ……&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  END:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  return&nbsp;&nbsp;&nbsp;&nbsp;  lResult;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  2、关于goto的应用：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对goto语句的应用，我们要求尽量少用goto语句。对一定要用的地方要求只能向后转移。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  3、资源变量的处理（资源变量是指消耗系统资源的变量）：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  对资源变量一定赋初值。分配的资源在用完后必须马上释放，并重新赋值。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  4、对复杂的条件判断，为了程序的可读性，应该尽量使用括号。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  例：if(((szFileName!=NULL)&amp;&amp;(lCount&gt;=0)))||(bIsReaded==TRUE))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;<br>
五、可移植性：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  1、高质量的代码要求能够跨平台，所以我们的代码应该考虑到对不同的平台的支持，特别是对windows98和windowsnt的支持。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  2、由于C语言的移植性比较好，所以对算法函数要求用C代码，不能用C++代码。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  3、对不同的硬件与软件的函数要做不同的处理&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
</font></p> <a href="http://hi.baidu.com/fatbsd/blog/item/79bdcf18add5080334fa41f8.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/Windows">Windows</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/79bdcf18add5080334fa41f8.html#comment">查看评论</a>]]></description>
        <pubDate>2008-03-24  13:50</pubDate>
        <category><![CDATA[Windows]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/79bdcf18add5080334fa41f8.html</guid>
</item>

<item>
        <title><![CDATA[c++ 字符类型总结]]></title>
        <link><![CDATA[http://hi.baidu.com/fatbsd/blog/item/065fc3ef209a4812fcfa3c44.html]]></link>
        <description><![CDATA[
		
		<div class="t_msgfont" ><strong>1.区别wchar_t,char,WCHAR</strong><br>
<br>
&nbsp;&nbsp; ANSI：即 char，可用字符串处理函数：strcat( ),strcpy( ), strlen( )等以str打头的函数。<br>
&nbsp;&nbsp; UNICODE：wchar_t是Unicode字符的数据类型，它实际定义在里：<br>
&nbsp;&nbsp; typedef unsigned short wchar_t;<br>
&nbsp;&nbsp; 另外，在头文件中有这样的定义：typedef wchar_t WCHAR; 所以WCHAR实际就是wchar_t<br>
&nbsp;&nbsp; wchar_t 可用字符串处理函数：wcscat(),wcscpy(),wcslen()等以wcs打头的函数。为了让编译器识别Unicode字符串，必须以在前面加一个&ldquo;L&rdquo;,例如: wchar_t *szTest=L&quot;This is a Unicode string.&quot;;<br>
<br>
<strong>2.TCHAR</strong><br>
<br>
在C语言里面提供了 _UNICODE宏（有下划线），在Windows里面提供了UNICODE宏（无下划线），只要定了_UNICODE宏和UNICODE宏，系统就会自 动切换到UNICODE版本，否则，系统按照ANSI的方式进行编译和运行。只定义了宏并不能实现自动的转换，他还需要一系列的字符定义支持。<br>
   1． TCHAR<br>
   如果定义了UNICODE宏则TCHAR被定义为wchar_t。<br>
   typedef wchar_t TCHAR;<br>
&nbsp;&nbsp; 否则TCHAR被定义为char typedef char TCHAR;<br>
   2． LPTSTR<br>
&nbsp;&nbsp; 如果定义了UNICODE宏则LPTSTR被定义为LPWSTR。<br>
&nbsp;&nbsp; typedef LPTSTR LPWSTR;<br>
&nbsp;&nbsp; 否则TCHAR被定义为char typedef LPTSTR LPSTR;<br>
&nbsp;&nbsp; 说明：在使用字符串常量的时候需要使用_TEXT(&ldquo;MyStr&rdquo;)或者_T(&quot;&quot;)来支持系统的自动转换。<br>
<br>
<strong>3.BSTR</strong><br>
<br>
&nbsp;&nbsp; BSTR是一个带长度前缀的字符串,主要由操作系统来管理的,所以要用api.主要用来和VB打交道的(VB里的string就是指它)要操作它的API函数有很多.比如SysAllocString,SysFreeString等等.<br>
&nbsp;&nbsp; vc里封装它的类如_bstr_t,及ATL中的CComBSTR等.<br>
&nbsp;&nbsp; 一个 BSTR 由头部和字符串组成，头部包含了字符串的长度信息，字符串中可以包含嵌入的 null 值。<br>
&nbsp;&nbsp; BSTR 是以指针的形式进行传递的。(指针是一个变量，包含另外一个变量的内存地址，而不是数据。) BSTR 是 Unicode 的，即每个字符需要两个字节。 BSTR 通常以两字节的 null 字符结束。 wstr是宽字符，以双字节表示一个字符 bstr是为了与原先的basic字符兼容，它的最前面的4个字节为其长度，以'\0'结束.<br>
<br>
<strong>4.更进一步的字符串以及其指针的类型定义　</strong><br>
<br>
由于Win32 API文档的函数列表使用函数的常用名字（例如， &quot;SetWindowText&quot;），所有的字符串都是用TCHAR来定义的。（除了XP中引入的只适用于Unicode的API）。下面列出一些常用的typedefs，你可以在msdn中看到他们。<br>
<br>
<table class="t_table" cellspacing="0" width="471" align="center">
    <tbody>
        <tr>
            <td>type</td>
            <td>Meaning in MBCS builds</td>
            <td>Meaning in Unicode builds</td>
        </tr>
        <tr>
            <td>WCHAR</td>
            <td>wchar_t</td>
            <td>wchar_t</td>
        </tr>
        <tr>
            <td>LPSTR</td>
            <td>char*</td>
            <td>char*</td>
        </tr>
        <tr>
            <td>LPCSTR</td>
            <td>const char*</td>
            <td>const char*</td>
        </tr>
        <tr>
            <td>LPWSTR</td>
            <td>wchar_t*</td>
            <td>wchar_t*</td>
        </tr>
        <tr>
            <td>LPCWSTR</td>
            <td>wchar_t*</td>
            <td>wchar_t*</td>
        </tr>
        <tr>
            <td>TCHAR</td>
            <td>TCHAR char</td>
            <td>wchar_t</td>
        </tr>
        <tr>
            <td>LPTSTR</td>
            <td>TCHAR*</td>
            <td>TCHAR*</td>
        </tr>
        <tr>
            <td>LPCTSTR</td>
            <td>const TCHAR*</td>
            <td>const TCHAR*</td>
        </tr>
    </tbody>
</table>
<br>
<br>
<strong>5.相互转换</strong><br>
<br>
(1) char*转换成CString<br>
　　若将char*转换成CString，除了直接赋值外，还可使用CString::Format进行。例如：<br>
char chArray[] = &quot;This is a test&quot;;<br>
char * p = &quot;This is a test&quot;;<br>
　　或<br>
LPSTR p = &quot;This is a test&quot;;<br>
　　或在已定义Unicode应的用程序中<br>
TCHAR * p = _T(&quot;This is a test&quot;);<br>
　　或<br>
LPTSTR p = _T(&quot;This is a test&quot;);<br>
CString theString = chArray;<br>
theString.Format(_T(&quot;%s&quot;), chArray);<br>
theString = p;<br>
　　(2) CString转换成char*<br>
　　若将CString类转换成char*(LPSTR)类型，常常使用下列三种方法：<br>
　　方法一，使用强制转换。例如：<br>
CString theString( &quot;This is a test&quot; );<br>
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString; <br>
　　方法二，使用strcpy。例如：<br>
CString theString( &quot;This is a test&quot; );<br>
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];<br>
_tcscpy(lpsz, theString);<br>
　　需要说明的是，strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI)，系统编译器将会自动对其进行转换。<br>
　　方法三，使用CString::GetBuffer。例如：<br>
CString s(_T(&quot;This is a test &quot;));<br>
LPTSTR p = s.GetBuffer();<br>
// 在这里添加使用p的代码<br>
if(p != NULL) *p = _T('\0');<br>
s.ReleaseBuffer();<br>
// 使用完后及时释放，以便能使用其它的CString成员函数<br>
　　(3) BSTR转换成char*<br>
　　方法一，使用ConvertBSTRToString。例如：<br>
#include<br>
#pragma comment(lib, &quot;comsupp.lib&quot;)<br>
int _tmain(int argc, _TCHAR* argv[]){<br>
BSTR bstrText = ::SysAllocString(L&quot;Test&quot;);<br>
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);<br>
SysFreeString(bstrText); // 用完释放<br>
delete[] lpszText2;<br>
return 0;<br>
} <br>
　　方法二，使用_bstr_t的赋值运算符重载。例如：<br>
_bstr_t b = bstrText;<br>
char* lpszText2 = b;<br>
　　(4) char*转换成BSTR<br>
　　方法一，使用SysAllocString等API函数。例如：<br>
BSTR bstrText = ::SysAllocString(L&quot;Test&quot;);<br>
BSTR bstrText = ::SysAllocStringLen(L&quot;Test&quot;,4);<br>
BSTR bstrText = ::SysAllocStringByteLen(&quot;Test&quot;,4);<br>
　　方法二，使用COleVariant或_variant_t。例如：<br>
//COleVariant strVar(&quot;This is a test&quot;);<br>
_variant_t strVar(&quot;This is a test&quot;);<br>
BSTR bstrText = strVar.bstrVal;<br>
　　方法三，使用_bstr_t，这是一种最简单的方法。例如：<br>
BSTR bstrText = _bstr_t(&quot;This is a test&quot;);<br>
　　方法四，使用CComBSTR。例如：<br>
BSTR bstrText = CComBSTR(&quot;This is a test&quot;);<br>
　　或<br>
CComBSTR bstr(&quot;This is a test&quot;);<br>
BSTR bstrText = bstr.m_str;<br>
　　方法五，使用ConvertStringToBSTR。例如：<br>
char* lpszText = &quot;Test&quot;;<br>
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);<br>
　　(5) CString转换成BSTR<br>
　　通常是通过使用CStringT::AllocSysString来实现。例如：<br>
CString str(&quot;This is a test&quot;);<br>
BSTR bstrText = str.AllocSysString();<br>
…<br>
SysFreeString(bstrText); // 用完释放 <br>
　　(6) BSTR转换成CString<br>
　　一般可按下列方法进行：<br>
BSTR bstrText = ::SysAllocString(L&quot;Test&quot;);<br>
CStringA str;<br>
str.Empty();<br>
str = bstrText; <br>
　　或<br>
CStringA str(bstrText);<br>
　　(7) ANSI、Unicode和宽字符之间的转换<br>
　　方法一，使用MultiByteToWideChar将ANSI字符转换成Unicode字符，使用WideCharToMultiByte将Unicode字符转换成ANSI字符。<br>
　　方法二，使用&ldquo;_T&rdquo;将ANSI转换成&ldquo;一般&rdquo;类型字符串，使用&ldquo;L&rdquo;将ANSI转换成Unicode，而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如：<br>
TCHAR tstr[] = _T(&quot;this is a test&quot;);<br>
wchar_t wszStr[] = L&quot;This is a test&quot;;<br>
String* str = S&rdquo;This is a test&rdquo;;<br>
　　方法三，使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类，它具有如图3所示的统一形式：<br>
　　其中，第一个C表示&ldquo;类&rdquo;，以便于ATL 3.0宏相区别，第二个C表示常量，2表示&ldquo;to&rdquo;，EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、 T、W和OLE，其含义分别是ANSI、Unicode、&ldquo;一般&rdquo;类型和OLE字符串。例如，CA2CT就是将ANSI转换成一般类型的字符串常量。下面 是一些示例代码：<br>
LPTSTR tstr= CA2TEX&lt;16&gt;(&quot;this is a test&quot;);<br>
LPCTSTR tcstr= CA2CT(&quot;this is a test&quot;);<br>
wchar_t wszStr[] = L&quot;This is a test&quot;;<br>
char* chstr = CW2A(wszStr);</div> <a href="http://hi.baidu.com/fatbsd/blog/item/065fc3ef209a4812fcfa3c44.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/fatbsd/blog/category/Windows">Windows</a>&nbsp;<a href="http://hi.baidu.com/fatbsd/blog/item/065fc3ef209a4812fcfa3c44.html#comment">查看评论</a>]]></description>
        <pubDate>2008-03-21  13:35</pubDate>
        <category><![CDATA[Windows]]></category>
        <author><![CDATA[fatbsd]]></author>
		<guid>http://hi.baidu.com/fatbsd/blog/item/065fc3ef209a4812fcfa3c44.html</guid>
</item>


</channel>
</rss>