﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Richard He-文章分类-[再转]</title><link>http://www.cppblog.com/richardhe/category/7632.html</link><description>学无止境!永远学下去!</description><language>zh-cn</language><lastBuildDate>Tue, 30 Jun 2009 11:44:15 GMT</lastBuildDate><pubDate>Tue, 30 Jun 2009 11:44:15 GMT</pubDate><ttl>60</ttl><item><title>用C++实现插件体系结构</title><link>http://www.cppblog.com/richardhe/articles/88887.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 30 Jun 2009 05:41:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/88887.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/88887.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/88887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/88887.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/88887.html</trackback:ping><description><![CDATA[<pre id="line283">http://www.yuanma.org/data/2007/0807/article_2796.htm<br>本文讨论一种简单却有效的插件体系结构，它使用C++,动态链接库，基于面向对象编程的思想<br>&lt;<span class="start-tag">BR</span>&gt;首先来看一下使用插件机制能给我们带来哪些方面的好处，从而在适当时候合理的选择使用<br>。&lt;<span class="start-tag">BR</span>&gt;1，&amp;<span class="entity">nbsp;</span>&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #0000ff"</span>&gt;增强代码的透明度与一致性&lt;/<span class="end-tag">SPAN</span>&gt;<br>：因为插件通常会封装第三方类库或是其他人编写的代码，需要清晰地定义出接口，用清晰一致的接口来面对所有事情。<br>你的代码也不会被转换程序或是库的特殊定制需求弄得乱七糟。<br>改善工程的模块化&lt;/<span class="end-tag">SPAN</span>&gt;：你的代码被清析地分成多个独立的模块，可以把它们安置在子工程中的文件组中。<br>这种解耦处理使得创建出的组件更加容易重用<br>更短的编译时间&lt;/<span class="end-tag">SPAN</span>&gt;：如果仅仅是为了解释某些类的声明，而这些类内部使用了外部库，<br>编译器不再需要解析外部库的头文件了，因为具体实现是以私有的形式完成。<br>更换与增加组件&lt;/<span class="end-tag">SPAN</span>&gt;：假如你需要向用户发布补丁，那么更新单独的插件而不是替代每一个安装了的文件更为有效。<br>当使用新的渲染器或是新的单元类型来扩展你的游戏时，能过向引擎提供一组插件，可以很容易的实现。<br>在关闭源代码的工程中使用GPL代码&lt;/<span class="end-tag">SPAN</span>&gt;：一般，假如你使用了GPL发布的代码，那么你也需要开放你的源代码。<br>然而，如果把GPL组件封装在插件中，你就不必发布插件的源码。<br>介绍&lt;<span class="start-tag">BR</span>&gt;&lt;/<span class="end-tag">SPAN</span>&gt;先简单解释一下什么是插件系统以及它如何工作：在普通的程序中，假如你需要代码执行一项特殊的任务，<br>你有两种选择：要么你自己编写，要么你寻找一个已经存在的满足你需要的库。现在，你的要求变了，那你只好重写代码或是寻找另一个不同的库。<br>无论是哪种方式，都会导致你框架代码中的那些依赖外部库的代码重写。&lt;<span class="start-tag">BR</span>&gt;现在，我们可以有另外一种选择：在插件系统中，<br>工程中的任何组件不再束缚于一种特定的实现（像渲染器既可以基于OpenGL,也可以选择Direct3D）,它们会从框架代码中剥离出来，<br>通过特定的方法被放入动态链接库之中。&lt;<span class="start-tag">BR</span>&gt;所谓的特定方法包括在框架代码中创建接口，这些接口使得框架与动态库解耦。<br>插件提供接口的实现。我们把插件与普通的动态链接库区分开来是因为它们的加载方式不同：程序不会直接链接插件，<br>而可能是在某些目录下查找，如果发现便进行加载。所有插件都可以使用一种共同的方法与应用进行联结。<br>常见的错误&lt;<span class="start-tag">BR</span>&gt;&lt;/<span class="end-tag">SPAN</span>&gt;一些程序员，当进行插件系统的设计时，可能会给每一个作为插件使用的动态库添加一个如下函数类似的函数：<br>PluginClass *createInstance(const char*);<br>然后它们让插件去提供一些类的实现。引擎用期望的对象名对加载的插件逐个进行查询，<br>直到某个插件返回，这是典型的设计模式中&#8220;职责链&#8221;模式的做法。一些更聪明的程序员会做出新的设计，使插件在引擎中注册自己，<br>或是用定制的实现替代引擎内部缺省实现：<br>Void dllStartPlugin(PluginManager &amp;<span class="entity">amp;</span>pm);<br>Void dllStopPlugin(PluginManager &amp;<span class="entity">amp;</span>pm);<br>第一种设计的主要问题是：插件工厂创建的对象需要使用reinterpret_cast<br><span class="entity"></span><span class="entity">;</span>来进行转换。通常，插件从共同基类（这里指PluginClass）派生，会引用一些不安全的感觉。实际上，这样做也是没意义的，<br>插件应该&#8220;默默&#8221;地响应输入设备的请求，然后提交结果给输出设备。&lt;<span class="start-tag">BR</span>&gt;在这种结构下，为了提供相同接口的多个不同实现，需要的工作变得异常复杂，<br>如果插件可以用不同名字注册自己（如Direct3DRenderer and OpenGLRenderer）,但是引擎不知道哪个具体实现对用户的选择是有效的。<br>假如把所有可能的实现列表硬编码到程序中，那么使用插件结构的目的也没有意义了。&lt;<span class="start-tag">BR</span>&gt;假如插件系统通过一个框架或是库(如游戏引擎) 实现，<br>架构师也肯定会把功能暴露给应用程序使用。这样，会带来一些问题像如何在应用程序中使用插件，插件作者如何引擎的头文件等，<br>这包含了潜在的三者之间版本冲突的可能性。&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #0000ff"</span>&gt;单独的工厂&lt;/<span class="end-tag">SPAN</span>&gt;&lt;<span class="start-tag">BR</span>&gt;接口，是被引擎清楚定义的，而不是插件。<br>引擎通过定义接口来指导插件做什么工作，插件具体实现功能。我们让插件注册自己的引擎接口的特殊实现。当然直接创建插件实现类的实例并注册是比较笨的做法。<br>这样使得同一时刻所有可能的实现同时存在，占用内存与CPU资源。解决的办法是工厂类，它唯一的目的是在请求时创建另外类的实例。<br>如果引擎定义了接口与插件通信，那么也应该为工厂类定义接口：<br>typename Interface Factory { virtual Interface *create() = 0; }; <br>class Renderer { virtual void  beginScene() = 0; virtual void  endScene() = 0;};<br>typedef  Factory<span class="entity">;</span>Renderer<span class="entity">;</span> RendererFactory;<br>选择1: 插件管理器<br>接下来应该考虑插件如何在引擎中注册它们的工厂，引擎又如何实际地使用这些注册的插件。一种选择是与存在的代码很好的接合，<br>这通过写插件管理器来完成。这使得我们可以控制哪些组件允许被扩展。<br>class  PluginManager <br>{void  registerRenderer(std::auto_ptr <span class="entity">;</span>RendererFactory <span class="entity">;</span> RF);<br>void  registerSceneManager(std::auto_ptr <span class="entity">;</span>SceneManagerFactory <span class="entity">;</span> SMF); };<br>当引擎需要一个渲染器时，它会访问插件管理器，看哪些渲染器已经通过插件注册了。<br>然后要求插件管理器创建期望的渲染器，插件管理器于是使用工厂类来生成渲染器，插件管理器甚至不需要知道实现细节。<br>插件由动态库组成，后者导出一个可以被插件管理器调用的函数，用以注册自己：<br>void   registerPlugin(PluginManager <span class="entity">;</span>PM);<br>&gt;插件管理器简单地在特定目录下加载所有dll文件，检查它们是否有一个名为registerPlugin()的导出函数。<br>当然也可用xml文档来指定哪些插件要被加载。　<br>选择 2: 完整地集成Fully Integrated 除了使用插件管理器，<br>也可以从头设计代码框架以支持插件。最好的方法是把引擎分成几个子系统<br>，构建一个系统核心来管理这些子系统。可能像下面这样：<br>class Kernel {StorageServer &amp;<span class="entity">amp;</span>getStorageServer() const<span class="entity">;</span> GraphicsServer &amp;<span class="entity">amp;</span>getGraphicsServer() const;};<br>class StorageServer {&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #008000"</span>&gt;<span class="entity">;</span> //提供给插件使用，注册新的读档器<br>void addArchiveReader(std::auto_ptr&amp;<span class="entity">lt;</span>ArchiveReader&amp;<span class="entity">gt;</span> AL);// 查询所有注册的读档器，直到找到可以打开指定格式的读档器<br> std::auto_ptr&amp;<span class="entity">lt;</span>Archive&amp;<span class="entity">gt;</span> openArchive(const std::string &amp;<span class="entity">amp;</span>sFilename);<br>&lt;<span class="start-tag">BR</span>&gt;};&lt;<span class="start-tag">BR</span>&gt;&amp;<span class="entity">nbsp;</span>&lt;<span class="start-tag">BR</span>&gt;class GraphicsServer {&lt;<span class="start-tag">BR</span>&gt;&amp;<span class="entity">nbsp;</span>&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #008000"</span>&gt; // 供插件使用，用来添加驱动&lt;<span class="start-tag">BR</span>&gt;&lt;/<span class="end-tag">SPAN</span>&gt;&amp;<span class="entity">nbsp;</span> <br>void addGraphicsDriver(std::auto_ptr&amp;<span class="entity">lt;</span>GraphicsDriver&amp;<span class="entity">gt;</span> AF);&lt;<span class="start-tag">BR</span>&gt;&amp;<span class="entity">nbsp;</span> &lt;<span class="start-tag">BR</span>&gt;&amp;<span class="entity">nbsp;</span> &lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #008000"</span>&gt;// 获取有效图形驱动的数目<br>&lt;<span class="start-tag">BR</span>&gt;&lt;/<span class="end-tag">SPAN</span>&gt;&amp;<span class="entity">nbsp;</span> size_t getDriverCount() const;&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #008000"</span>&gt;&amp;<span class="entity">nbsp;</span>//返回驱动&lt;<span class="start-tag">BR</span>&gt;&lt;/<span class="end-tag">SPAN</span>&gt;&amp;<span class="entity">nbsp;</span> <br>GraphicsDriver &amp;<span class="entity">amp;</span>getDriver(size_t Index);&lt;<span class="start-tag">BR</span>&gt;};&lt;<span class="start-tag">BR</span>&gt;这里有两个子系统，它们使用&#8221; Server&#8221;作为后缀。<br>第一个Server内部维护一个有效图像加载器的列表，每次当用户希望加载一幅图片时，图像加载器被一一查询，<br>直到发现一个特定的实现可以处理特定格式的图片。另一个子系统有一个GraphicsDrivers的列表，它们作为Renderers的工厂来使用。<br>可以是Direct3DgraphicsDriver或是OpenGLGraphicsDrivers,它们分别负责Direct3Drenderer与OpenGLRenderer的创建。引擎提供有效的驱动列表供用户选择使用，<br>通过安装一个新的插件，新的驱动也可以被加入。&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #0000ff"</span>&gt;版本&lt;/<span class="end-tag">SPAN</span>&gt;&lt;<span class="start-tag">BR</span>&gt;在上面两个可选择的方法中，<br>不强制要求你把特定的实现放到插件中。假如你的引擎提供一个读档器的默认实现，以支持自定义文件包格式。你可以把它放到引擎本身，<br>当StorageServer 启动时自动进行注册。&lt;<span class="start-tag">BR</span>&gt;现在还有一个问题没有讨论：假如你不小心的话，与引擎不匹配（例如，已经过时的）插件会被加载<br>子系统类的一些变化或是插件管理器的改变足以导致内存布局的改变，当不匹配的插件试图注册时可能发生冲突甚至崩溃。比较讨厌的是，这些在调试时难与发现。<br>&nbsp;幸运的是，辨认过时或不正确的插件非常容易。最可靠的是方法是在你的核心系统中放置一个预处理常量。任何插件都有一个函数，<br>它可以返回这个常量给引擎：&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #008000"</span>&gt;// Somewhere in your core system&lt;<span class="start-tag">BR</span>&gt;<br>&lt;/<span class="end-tag">SPAN</span>&gt;#define MyEngineVersion 1;&lt;<span class="start-tag">BR</span>&gt;&amp;<span class="entity">nbsp;</span>&lt;<span class="start-tag">BR</span>&gt;&lt;<span class="start-tag">SPAN</span><span class="attribute-name"> style</span>=<span class="attribute-value">"COLOR: #008000"</span>&gt;// The plugin&lt;/<span class="end-tag">SPAN</span>&gt;&lt;<span class="start-tag">BR</span>&gt;extern int getExpectedEngineVersion()<br>&nbsp;{&lt;<span class="start-tag">BR</span>&gt;&amp;<span class="entity">nbsp;</span> return MyEngineVersion;&lt;<span class="start-tag">BR</span>&gt;}&lt;<span class="start-tag">BR</span>&gt;在这个常量被编译到插件后，当引擎中的常量改变时，任何没有进行重新编译的插件它的　<br>getExpectedEngineVersion ()方法会返回以前的那个值。引擎可以根据这个值，拒绝加载不匹配的插件。为了使插件可以重新工作，必须重新编译它。<br>当然，最大的危险是你忘记了更新常量值。无论如何，你应该有个自动版本管理工具帮助你。 &lt;/<span class="end-tag">P</span>&gt;<br></pre>
<pre id="line284"><br></pre><img src ="http://www.cppblog.com/richardhe/aggbug/88887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2009-06-30 13:41 <a href="http://www.cppblog.com/richardhe/articles/88887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式30分钟入门教程</title><link>http://www.cppblog.com/richardhe/articles/72109.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Thu, 15 Jan 2009 09:36:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/72109.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/72109.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/72109.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/72109.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/72109.html</trackback:ping><description><![CDATA[<div class="postText">
<div class="postbody">
<h1>正则表达式30分钟入门教程</h1>
<p id="meta">版本：v2.3 (2008-4-13) 作者：<a  href="http://www.unibetter.com/members/deerchao.aspx"><u><font color="#0000ff">deerchao</font></u></a> 转载请注明<a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm"><u><font color="#0000ff">来源</font></u></a></p>
<h2 id="contents">目录</h2>
<p class="note" id="skipContents"><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#mission" title="转到正文内容"><u><font color="#0000ff">跳过目录</font></u></a></p>
<ol>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#mission"><u><font color="#0000ff">本文目标</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#howtouse"><u><font color="#0000ff">如何使用本教程</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#introduction"><u><font color="#0000ff">正则表达式到底是什么东西？</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#getstarted"><u><font color="#0000ff">入门</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#testing"><u><font color="#0000ff">测试正则表达式</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#metacode"><u><font color="#0000ff">元字符</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#escape"><u><font color="#0000ff">字符转义</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#repeat"><u><font color="#0000ff">重复</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#charclass"><u><font color="#0000ff">字符类</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#alternative"><u><font color="#0000ff">分枝条件</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#negation"><u><font color="#0000ff">反义</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#grouping"><u><font color="#0000ff">分组</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#backreference"><u><font color="#0000ff">后向引用</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#lookaround"><u><font color="#0000ff">零宽断言</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#negativelookaround"><u><font color="#0000ff">负向零宽断言</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#commenting"><u><font color="#0000ff">注释</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#greedyandlazy"><u><font color="#0000ff">贪婪与懒惰</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#regexoptions"><u><font color="#0000ff">处理选项</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#balancedgroup"><u><font color="#0000ff">平衡组/递归匹配</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#more"><u><font color="#0000ff">还有些什么东西没提到</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#contact"><u><font color="#0000ff">联系作者</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#ad"><u><font color="#0000ff">最后,来点广告...</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#resources"><u><font color="#0000ff">网上的资源及本文参考文献</font></u></a>
    </li>
    <li><a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#updatelog"><u><font color="#0000ff">更新说明</font></u></a></li>
</ol>
<h2 id="mission">本文目标</h2>
<p>30分钟内让你明白正则表达式是什么，并对它有一些基本的了解，让你可以在自己的程序或网页里使用它。</p>
<h2 id="howtouse">如何使用本教程</h2>
<p class="important note" id="giveMe30Minutes">最重要的是——请给我<em>30分钟</em>，如果你没有使用正则表达式的经验，请不要试图在30<em>秒</em>内入门——除非你是超人 :)</p>
<p>别被下面那些复杂的表达式吓倒，只要跟着我一步一步来，你会发现正则表达式其实并<span lang="zh-cn">没有</span>你想像
中的那么困难。当然，如果你看完了这篇教程之后，发现自己明白了很多，却又几乎什么都记不得，那也是很正常的——我认为，没接触过正则表达式的人在看完这
篇教程后，能把提到过的语法记住80%以上的可能性为零。这里只是让你明白基本的原理，以后你还需要多练习，多使用，才能熟练掌握正则表达式。</p>
<p>除了作为入门教程之外，本文还试图成为可以在日常工作中使用的正则表达式语法参考手册。就作者本人的经历来说，这个目标还是完成得不错的——你看，我自己也没能把所有的东西记下来，不是吗？</p>
<p><a  href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm" id="clearButton" onclick="return clearFormats();"><u><font color="#0000ff">清除格式</font></u></a>&nbsp;文本格式约定：<span class="name">专业术语</span>&nbsp;<span class="code">元字符/语法格式</span>&nbsp;<span class="regex">正则表达式</span>&nbsp;<span class="part">正则表达式中的一部分(用于分析)</span>&nbsp;<span class="string">对其进行匹配的源字符串</span>&nbsp;<span class="desc">对正则表达式或其中一部分的说明</span></p>
<p><a  href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm" id="hideButton" onclick="return hideNotes();"><u><font color="#0000ff">隐藏边注</font></u></a>&nbsp;本文右边有一些注释，主要是用来提供一些相关信息，或者给没有程序员背景的读者解释一些基本概念，通常可以忽略。</p>
<h2 id="introduction">正则表达式到底是什么东西？</h2>
<p class="note"><span class="name">字符</span>是计算机软件处理文字时最基本的单位，可能是字母，数字，标点符号，空格，换行符，汉字等等。<span class="name">字符串</span>是0个或更多个字符的序列。<span class="name">文本</span>也就是文字，字符串。说某个字符串<span class="name">匹配</span>某个正则表达式，通常是指这个字符串里有一部分（或几部分分别）能满足表达式给出的条件。</p>
<p>在编写处理字符串的程序或网页时，经常会有查找符合某些复杂规则的字符串的需要。<span class="name">正则表达式</span>就是用于描述这些规则的工具。换句话说，正则表达式就是记录文本规则的代码。</p>
<p>很可能你使用过Windows/Dos下用于文件查找的<span class="name">通配符(wildcard)</span>，也就是<span class="code">*</span>和<span class="code">?</span>。如果你想查找某个目录下的所有的Word文档的话，你会搜索<span style="color: red;">*.doc</span>。在这里，<span class="code">*</span>会被解释成任意的字符串。和通配符类似，正则表达式也是用来进行文本匹配的工具，只不过比起通配符，它能更精确地描述你的需求——当然，代价就是更复杂——比如你可以编写一个正则表达式，用来查找<span class="desc">所有以0开头，后面跟着2-3个数字，然后是一个连字号&#8220;-&#8221;，最后是7或8位数字的字符串</span>(像<span class="string">010-12345678</span>或<span class="string">0376-7654321</span>)。</p>
<h2 id="getstarted">入门</h2>
<p>学习正则表达式的最好方法是从例子开始，理解例子之后再自己对例子进行修改，实验。下面给出了不少简单的例子，并对它们作了详细的说明。</p>
<p>假设你在一篇英文小说里查找<span class="desc">hi</span>，你可以使用正则表达式<span class="regex">hi</span>。</p>
<p>这几乎是最简单的正则表达式了，它可以精确匹配这样的字符串：<span class="desc">由两个字符组成，前一个字符是h,后一个是i</span>。通常，处理正则表达式的工具会提供一个忽略大小写的选项，如果选中了这个选项，它可以匹配<span class="string">hi</span>,<span class="string">HI</span>,<span class="string">Hi</span>,<span class="string">hI</span>这四种情况中的任意一种。</p>
<p>不幸的是，很多单词里包含<span class="string">hi</span>这两个连续的字符，比如<span class="string">him</span>,<span class="string">history</span>,<span class="string">high</span>等等。用<span class="regex">hi</span>来查找的话，这里边的<span class="string">hi</span>也会被找出来。如果要<span class="desc">精确地查找hi这个单词</span>的话，我们应该使用<span class="regex">\bhi\b</span>。</p>
<p><span class="part">\b</span>是正则表达式规定的一个特殊代码（好吧，某些人叫它<span class="name">元字符，metacharacter</span>），代表着<span class="desc">单词的开头或结尾，也就是单词的分界处</span>。虽然通常英文的单词是由空格，标点符号或者换行来分隔的，但是<span class="code">\b</span>并不匹配这些单词分隔字符中的任何一个，它<strong>只匹配一个位置</strong>。</p>
<p class="note">如果需要更精确的说法，<span class="code">\b</span>匹配这样的位置：它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)<span class="code">\w</span>。</p>
<p>假如你要找的是<span class="desc">hi后面不远处跟着一个Lucy</span>，你应该用<span class="regex">\bhi\b.*\bLucy\b</span>。</p>
<p>这里，<span class="part">.</span>是另一个元字符，匹配<span class="desc">除了换行符以外的任意字符</span>。<span class="part">*</span>同样是元字符，不过它代表的不是字符，也不是位置，而是数量——它指定*<span class="desc">前边的内容可以连续重复出现任意次以使整个表达式得到匹配</span>。因此，<span class="part">.*</span>连在一起就意味着<span class="desc">任意数量的不包含换行的字符</span>。现在<span class="regex">\bhi\b.*\bLucy\b</span>的意思就很明显了：<span class="desc">先是一个单词hi,然后是任意个任意字符(但不能是换行)，最后是Lucy这个单词</span>。</p>
<p class="note">换行符就是'\n',ASCII编码为10(十六进制0x0A)的字符。</p>
<p>如果同时使用其它元字符，我们就能构造出功能更强大的正则表达式。比如下面这个例子：</p>
<p><span class="regex">0\d\d-\d\d\d\d\d\d\d\d</span>匹配这样的字符串：<span class="desc">以0开头，然后是两个数字，然后是一个连字号&#8220;-&#8221;，最后是8个数字</span>(也就是中国的电话号码。当然，这个例子只能匹配区号为3位的情形)。</p>
<p>这里的<span class="part">\d</span>是个新的元字符，匹配<span class="desc">一位数字(0，或1，或2，或&#8230;&#8230;)</span>。<span class="part">-</span>不是元字符，只匹配它本身——连字符或者减号。</p>
<p>为了避免那么多烦人的重复，我们也可以这样写这个表达式：<span class="regex">0\d{2}-\d{8}</span>。 这里<span class="part">\d</span>后面的<span class="part">{2}</span>(<span class="part">{8}</span>)的意思是前面<span class="part">\d</span><span class="desc">必须连续重复匹配2次(8次)</span>。</p>
<h2 id="testing">测试正则表达式</h2>
<div class="note">
<p>其它可用的测试工具:</p>
<ul>
    <li><a  href="http://www.regexbuddy.com/"><u><font color="#0000ff">RegexBuddy</font></u></a>
    </li>
    <li><a  href="http://regexpal.com/"><u><font color="#0000ff">Javascript正则表达式在线测试工具</font></u></a></li>
</ul>
</div>
<p>如果你不觉得正则表达式很难读写的话，要么你是一个天才，要么，你不是地球人。正则表达式的语法很令人头疼，即使对经常使用它的人来说也是如此。由于难于读写，容易出错，所以找一种工具对正则表达式进行测试是很有必要的。</p>
<p>由于在不同的环境下正则表达式的一些细节是不相同的，本教程介绍的是微软 .Net Framework 2.0下正则表达式的行为，所以，我向你介绍一个.Net下的工具<a  href="http://www.dotnet2themax.com/blogs/fbalena/PermaLink,guid,13bce26d-7755-441e-92b3-1eb5f9e859f9.aspx" title="转到RegexTester的官方网站（英文）"><u><font color="#0000ff">Regex Tester</font></u></a>。首先你确保已经安装了<a  href="http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&amp;FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5" title="转到下载.Net Framework 2.0的页面"><u><font color="#0000ff">.Net Framework 2.0</font></u></a>，然后<a  href="http://www.unibetter.com/deerchao/downloads/RegexTester.zip" title="从www.unibetter.com下载Regex Tester, 75KB"><u><font color="#0000ff">下载Regex Tester</font></u></a>。这是个绿色软件，下载完后打开压缩包,直接运行RegexTester.exe就可以了。</p>
<p>下面是Regex Tester运行时的截图：</p>
<p><img  src="http://unibetter.com/deerchao/images/RegexTester.jpg" alt="Regex Tester运行时的截图"></p>
<h2 id="metacode">元字符</h2>
<p>现在你已经知道几个很有用的元字符了，如<span class="code">\b</span>,<span class="code">.</span>,<span class="code">*</span>，还有<span class="code">\d</span>.正则表达式里还有更多的元字符，比如<span class="code">\s</span>匹配<span class="desc">任意的空白符，包括空格，制表符(Tab)，换行符，中文全角空格等</span>。<span class="code">\w</span>匹配<span class="desc">字母或数字或下划线或汉字等</span>。</p>
<p class="note">对中文/汉字的特殊处理是由.Net提供的正则表达式引擎支持的，其它环境下的具体情况请查看相关文档。</p>
<p>下面来看看更多的例子：</p>
<p><span class="regex">\ba\w*\b</span>匹配<span class="desc">以字母<span class="part">a</span>开头的单词——先是某个单词开始处(<span class="part">\b</span>)，然后是字母<span class="part">a</span>,然后是任意数量的字母或数字(<span class="part">\w*</span>)，最后是单词结束处(<span class="part">\b</span>)</span>。</p>
<p class="note">好吧，现在我们说说正则表达式里的单词是什么意思吧：就是多于一个的连续的<span class="code">\w</span>。不错，这与学习英文时要背的成千上万个同名的东西的确关系不大 :)</p>
<p><span class="regex">\d+</span>匹配<span class="desc">1个或更多连续的数字</span>。这里的<span class="part">+</span>是和<span class="code">*</span>类似的元字符，不同的是<span class="code">*</span>匹配<span class="desc">重复任意次(可能是0次)</span>，而<span class="code">+</span>则匹配<span class="desc">重复1次或更多次</span>。</p>
<p><span class="regex">\b\w{6}\b</span> 匹配<span class="desc">刚好6个字母/数字的单词</span>。</p>
<table cellspacing="0">
    <caption>表1.常用的元字符</caption>
    <thead>
        <tr>
            <th scope="col">代码</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code">.</span></td>
            <td><span class="desc">匹配除换行符以外的任意字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\w</span></td>
            <td><span class="desc">匹配字母或数字或下划线或汉字</span></td>
        </tr>
        <tr>
            <td><span class="code">\s</span></td>
            <td><span class="desc">匹配任意的空白符</span></td>
        </tr>
        <tr>
            <td><span class="code">\d</span></td>
            <td><span class="desc">匹配数字</span></td>
        </tr>
        <tr>
            <td><span class="code">\b</span></td>
            <td><span class="desc">匹配单词的开始或结束</span></td>
        </tr>
        <tr>
            <td><span class="code">^</span></td>
            <td><span class="desc">匹配字符串的开始</span></td>
        </tr>
        <tr>
            <td><span class="code">$</span></td>
            <td><span class="desc">匹配字符串的结束</span></td>
        </tr>
    </tbody>
</table>
<p>元字符<span class="code">^</span>（和数字6在同一个键位上的符号）和<span class="code">$</span>都匹配一个位置，这和<span class="code">\b</span>有点类似。<span class="code">^</span>匹配你要用来查找的字符串的开头，<span class="code">$</span>匹配结尾。这两个代码在验证输入的内容时非常有用，比如一个网站如果要求你填写的QQ号必须为5位到12位数字时，可以使用：<span class="regex">^\d{5,12}$</span>。</p>
<p>这里的<span class="part">{5,12}</span>和前面介绍过的<span class="part">{2}</span>是类似的，只不过<span class="part">{2}</span>匹配<span class="desc">只能不多不少重复2次</span>，<span class="part">{5,12}</span>则是<span class="desc">重复的次数不能少于5次，不能多于12次</span>，否则都不匹配。</p>
<p>因为使用了<span class="part">^</span>和<span class="part">$</span>，所以输入的整个字符串都要用来和<span class="part">\d{5,12}</span>来匹配，也就是说整个输入<span class="desc">必须是5到12个数字</span>，因此如果输入的QQ号能匹配这个正则表达式的话，那就符合要求了。</p>
<p>和忽略大小写的选项类似，有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项，<span class="code">^</span>和<span class="code">$</span>的意义就变成了<span class="desc">匹配行的开始处和结束处</span>。</p>
<h2 id="escape">字符转义</h2>
<p>如果你想查找元字符本身的话，比如你查找<span class="desc">.</span>,或者<span class="desc">*</span>,就出现了问题：你没办法指定它们，因为它们会被解释成别的意思。这时你就得使用<span class="code">\</span>来取消这些字符的特殊意义。因此，你应该使用<span class="regex">\.</span>和<span class="regex">\*</span>。当然，要查找<span class="desc">\</span>本身，你也得用<span class="regex">\\</span>.</p>
<p>例如：<span class="regex">unibetter\.com</span>匹配<span class="desc">unibetter.com</span>，<span class="regex">C:\\Windows</span>匹配<span class="desc">C:\Windows</span>。</p>
<h2 id="repeat">重复</h2>
<p>你已经看过了前面的<span class="code">*</span>,<span class="code">+</span>,<span class="code">{2}</span>,<span class="code">{5,12}</span>这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码，例如*,{5,12}等)：</p>
<table cellspacing="0">
    <caption>表2.常用的限定符</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code">*</span></td>
            <td><span class="desc">重复零次或更多次</span></td>
        </tr>
        <tr>
            <td><span class="code">+</span></td>
            <td><span class="desc">重复一次或更多次</span></td>
        </tr>
        <tr>
            <td><span class="code">?</span></td>
            <td><span class="desc">重复零次或一次</span></td>
        </tr>
        <tr>
            <td><span class="code">{n}</span></td>
            <td><span class="desc">重复n次</span></td>
        </tr>
        <tr>
            <td><span class="code">{n,}</span></td>
            <td><span class="desc">重复n次或更多次</span></td>
        </tr>
        <tr>
            <td><span class="code">{n,m}</span></td>
            <td><span class="desc">重复n到m次</span></td>
        </tr>
    </tbody>
</table>
<p>下面是一些使用重复的例子：</p>
<p><span class="regex">Windows\d+</span>匹配<span class="desc">Windows后面跟1个或更多数字</span></p>
<p><span class="regex">^\w+</span>匹配<span class="desc">一行的第一个单词(或整个字符串的第一个单词，具体匹配哪个意思得看选项设置)</span></p>
<h2 id="charclass">字符类</h2>
<p>要想查找数字，字母或数字，空白是很简单的，因为已经有了对应这些字符集合的元字符，但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办？</p>
<p>很简单，你只需要在方括号里列出它们就行了，像<span class="regex">[aeiou]</span>就匹配<span class="desc">任何一个英文元音字母</span>，<span class="regex">[.?!]</span>匹配<span class="desc">标点符号(.或?或!)</span>。</p>
<p>我们也可以轻松地指定一个字符<span class="name">范围</span>，像<span class="regex">[0-9]</span>代表的含意与<span class="regex">\d</span>就是完全一致的：<span class="desc">一位数字</span>；同理<span class="regex">[a-z0-9A-Z_]</span>也完全等同于<span class="code">\w</span>（如果只考虑英文的话）。</p>
<p>下面是一个更复杂的表达式：<span class="regex">\(?0\d{2}[) -]?\d{8}</span>。</p>
<p class="note">&#8220;(&#8221;和&#8220;)&#8221;也是元字符，后面的<a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#grouping"><u><font color="#0000ff">分组节</font></u></a>里会提到，所以在这里需要使用<a  href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#escape"><u><font color="#0000ff">转义</font></u></a>。</p>
<p>这个表达式可以匹配<span class="desc">几种格式的电话号码</span>，像<span class="string">(010)88886666</span>，或<span class="string">022-22334455</span>，或<span class="string">02912345678</span>等。我们对它进行一些分析吧：首先是一个转义字符<span class="part">\(</span>,它能出现0次或1次(<span class="part">?</span>),然后是一个<span class="part">0</span>，后面跟着2个数字(<span class="part">\d{2}</span>)，然后是<span class="part">)</span>或<span class="part">-</span>或<span class="part">空格</span>中的一个，它出现1次或不出现(<span class="part">?</span>)，最后是8个数字(<span class="part">\d{8}</span>)。</p>
<h2 id="alternative">分枝条件</h2>
<p>不幸的是，刚才那个表达式也能匹配<span class="string">010)12345678</span>或<span class="string">(022-87654321</span>这样的&#8220;不正确&#8221;的格式。要解决这个问题，我们需要用到<span class="name">分枝条件</span>。正则表达式里的<span class="name">分枝条件</span>指的是有几种规则，如果满足其中任意一种规则都应该当成匹配，具体方法是用<span class="code">|</span>把不同的规则分隔开。听不明白？没关系，看例子：</p>
<p><span class="regex">0\d{2}-\d{8}|0\d{3}-\d{7}</span>这个表达式能<span class="desc">匹配两种以连字号分隔的电话号码：一种是三位区号，8位本地号(如010-12345678)，一种是4位区号，7位本地号(0376-2233445)</span>。</p>
<p><span class="regex">\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}</span>这个表达式<span class="desc">匹配3位区号的电话号码，其中区号可以用小括号括起来，也可以不用，区号与本地号间可以用连字号或空格间隔，也可以没有间隔</span>。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。</p>
<p><span class="regex">\d{5}-\d{4}|\d{5}</span>这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字，或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题：<strong>使用分枝条件时，要注意各个条件的顺序</strong>。如果你把它改成<span class="regex">\d{5}|\d{5}-\d{4}</span>的话，那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时，将会从左到右地测试每个条件，如果满足了某个分枝的话，就不会去再管其它的条件了。</p>
<h2 id="grouping">分组</h2>
<p>我们已经提到了怎么重复单个字符（直接在字符后面加上限定符就行了）；但如果想要重复多个字符又该怎么办？你可以用小括号来指定<span class="name">子表达式</span>(也叫做<span class="name">分组</span>)，然后你就可以指定这个子表达式的重复次数了，你也可以对子表达式进行其它一些操作(后面会有介绍)。</p>
<p><span class="regex">(\d{1,3}\.){3}\d{1,3}</span>是一个<span class="desc">简单的IP地址匹配</span>表达式。要理解这个表达式，请按下列顺序分析它：<span class="part">\d{1,3}</span>匹配<span class="desc">1到3位的数字</span>，<span class="part">(\d{1,3}\.){3}</span>匹配<span class="desc">三位数字加上一个英文句号(这个整体也就是这个<span class="name">分组</span>)重复3次</span>，最后再加上<span class="desc">一个一到三位的数字</span>(<span class="part">\d{1,3}</span>)。</p>
<p class="note">IP地址中每个数字都不能大于255，大家千万不要被《24》第三季的编剧给忽悠了...</p>
<p>不幸的是，它也将匹配<span class="string">256.300.888.999</span>这种不可能存在的IP地址。如果能使用算术比较的话，或许能简单地解决这个问题，但是正则表达式中并不提供关于数学的任何功能，所以只能使用冗长的分组，选择，字符类来描述一个正确的IP地址：<span class="regex">((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)</span>。</p>
<p>理解这个表达式的关键是理解<span class="part">2[0-4]\d|25[0-5]|[01]?\d\d?</span>，这里我就不细说了，你自己应该能分析得出来它的意义。</p>
<h2 id="negation">反义</h2>
<p>有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外，其它任意字符都行的情况，这时需要用到<span class="name">反义</span>：</p>
<table cellspacing="0">
    <caption>表3.常用的反义代码</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code">\W</span></td>
            <td><span class="desc">匹配任意不是字母，数字，下划线，汉字的字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\S</span></td>
            <td><span class="desc">匹配任意不是空白符的字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\D</span></td>
            <td><span class="desc">匹配任意非数字的字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\B</span></td>
            <td><span class="desc">匹配不是单词开头或结束的位置</span></td>
        </tr>
        <tr>
            <td><span class="code">[^x]</span></td>
            <td><span class="desc">匹配除了x以外的任意字符</span></td>
        </tr>
        <tr>
            <td><span class="code">[^aeiou]</span></td>
            <td><span class="desc">匹配除了aeiou这几个字母以外的任意字符</span></td>
        </tr>
    </tbody>
</table>
<p>例子：<span class="regex">\S+</span>匹配<span class="desc">不包含空白符的字符串</span>。</p>
<p><span class="regex">&lt;a[^&gt;]+&gt;</span>匹配<span class="desc">用尖括号括起来的以a开头的字符串</span>。</p>
<h2 id="backreference">后向引用</h2>
<p>使用小括号指定一个子表达式后，<strong>匹配这个子表达式的文本</strong>(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下，每个分组会自动拥有一个<span class="name">组号</span>，规则是：从左向右，以分组的左括号为标志，第一个出现的分组的组号为1，第二个为2，以此类推。</p>
<p><span class="name">后向引用</span>用于重复搜索前面某个分组匹配的文本。例如，<span class="part">\1</span>代表<span class="desc">分组1匹配的文本</span>。难以理解？请看示例：</p>
<p><span class="regex">\b(\w+)\b\s+\1\b</span>可以用来匹配<span class="desc">重复的单词</span>，像<span class="string">go go</span>, 或者<span class="string">kitty kitty</span>。这个表达式首先是<span class="desc">一个单词</span>，也就是<span class="desc">单词开始处和结束处之间的多于一个的字母或数字</span>(<span class="part">\b(\w+)\b</span>)，这个单词会被捕获到编号为1的分组中，然后是<span class="desc">1个或几个空白符</span>(<span class="part">\s+</span>)，最后是<span class="desc">分组1中捕获的内容（也就是前面匹配的那个单词）</span>(<span class="part">\1</span>)。</p>
<p>你也可以自己指定子表达式的<span class="name">组名</span>。要指定一个子表达式的组名，请使用这样的语法：<span class="code">(?&lt;Word&gt;\w+)</span>(或者把尖括号换成<span class="code">'</span>也行：<span class="code">(?'Word'\w+)</span>),这样就把<span class="part">\w+</span>的组名指定为<span class="part">Word</span>了。要反向引用这个分组<span class="name">捕获</span>的内容，你可以使用<span class="code">\k&lt;Word&gt;</span>,所以上一个例子也可以写成这样：<span class="regex">\b(?&lt;Word&gt;\w+)\b\s+\k&lt;Word&gt;\b</span>。</p>
<p>使用小括号的时候，还有很多特定用途的语法。下面列出了最常用的一些：</p>
<table cellspacing="0">
    <caption>表4.常用分组语法</caption>
    <tbody>
        <tr>
            <th scope="col">分类</th>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
        <tr>
            <th rowspan="3">捕获</th>
            <td><span class="code">(exp)</span></td>
            <td><span class="desc">匹配exp,并捕获文本到自动命名的组里</span></td>
        </tr>
        <tr>
            <td><span class="code">(?&lt;name&gt;exp)</span></td>
            <td><span class="desc">匹配exp,并捕获文本到名称为name的组里，也可以写成(?'name'exp)</span></td>
        </tr>
        <tr>
            <td><span class="code">(?:exp)</span></td>
            <td><span class="desc">匹配exp,不捕获匹配的文本，也不给此分组分配组号</span></td>
        </tr>
        <tr>
            <th rowspan="4">零宽断言</th>
            <td><span class="code">(?=exp)</span></td>
            <td><span class="desc">匹配exp前面的位置</span></td>
        </tr>
        <tr>
            <td><span class="code">(?&lt;=exp)</span></td>
            <td><span class="desc">匹配exp后面的位置</span></td>
        </tr>
        <tr>
            <td><span class="code">(?!exp)</span></td>
            <td><span class="desc">匹配后面跟的不是exp的位置</span></td>
        </tr>
        <tr>
            <td><span class="code">(?&lt;!exp)</span></td>
            <td><span class="desc">匹配前面不是exp的位置</span></td>
        </tr>
        <tr>
            <th>注释</th>
            <td><span class="code">(?#comment)</span></td>
            <td><span class="desc">这种类型的分组不对正则表达式的处理产生任何影响，用于提供注释让人阅读</span></td>
        </tr>
    </tbody>
</table>
<p>我们已经讨论了前两种语法。第三个<span class="code">(?:exp)</span>不会改变正则表达式的处理方式，只是这样的组匹配的内容<span class="desc">不会像前两种那样被捕获到某个组里面，也不会拥有组号</span>。</p>
<h2 id="lookaround">零宽断言</h2>
<p class="note">地球人，是不是觉得这些术语名称太复杂，太难记了？我也和你一样。知道有这么一种东西就行了，它叫什么，随它去吧！&#8220;无名，万物之始...&#8221;</p>
<p>接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西，也就是说它们像<span class="code">\b</span>,<span class="code">^</span>,<span class="code">$</span>那样用于指定一个位置，这个位置应该满足一定的条件(即断言)，因此它们也被称为<span class="name">零宽断言</span>。最好还是拿例子来说明吧：</p>
<p class="note">断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。</p>
<p><span class="code">(?=exp)</span>也叫<span class="name">零宽度正预测先行断言</span>，它<span class="desc">断言自身出现的位置的后面能匹配表达式exp</span>。比如<span class="regex">\b\w+(?=ing\b)</span>，匹配<span class="desc">以ing结尾的单词的前面部分(除了ing以外的部分)</span>，如查找<span class="string">I'm singing while you're dancing.</span>时，它会匹配<span class="desc">sing</span>和<span class="desc">danc</span>。</p>
<p><span class="code">(?&lt;=exp)</span>也叫<span class="name">零宽度正回顾后发断言</span>，它<span class="desc">断言自身出现的位置的前面能匹配表达式exp</span>。比如<span class="regex">(?&lt;=\bre)\w+\b</span>会匹配<span class="desc">以re开头的单词的后半部分(除了re以外的部分)</span>，例如在查找<span class="string">reading a book</span>时，它匹配<span class="desc">ading</span>。</p>
<p>假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了)，你可以这样查找需要在前面和里面添加逗号的部分：<span class="regex">((?&lt;=\d)\d{3})*\b</span>，用它对<span class="string">1234567890</span>进行查找时结果是<span class="desc">234567890</span>。</p>
<p>下面这个例子同时使用了这两种断言：<span class="regex">(?&lt;=\s)\d+(?=\s)</span>匹配<span class="desc">以空白符间隔的数字(再次强调，不包括这些空白符)</span>。</p>
<h2 id="negativelookaround">负向零宽断言</h2>
<p>前面我们提到过怎么查找<strong>不是某个字符或不在某个字符类里</strong>的字符的方法(反义)。但是如果我们只是想要<strong>确保某个字符没有出现，但并不想去匹配它</strong>时怎么办？例如，如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样：</p>
<p><span class="regex">\b\w*q[^u]\w*\b</span>匹配<span class="desc">包含<strong>后面不是字母u的字母q</strong>的单词</span>。但是如果多做测试(或者你思维足够敏锐，直接就观察出来了)，你会发现，如果q出现在单词的结尾的话，像<strong>Iraq</strong>,<strong>Benq</strong>，这个表达式就会出错。这是因为<span class="part">[^u]</span>总要匹配一个字符，所以如果q是单词的最后一个字符的话，后面的<span class="part">[^u]</span>将会匹配q后面的单词分隔符(可能是空格，或者是句号或其它的什么)，后面的<span class="part">\w*\b</span>将会匹配下一个单词，于是<span class="regex">\b\w*q[^u]\w*\b</span>就能匹配整个<span class="string">Iraq fighting</span>。<span class="name">负向零宽断言</span>能解决这样的问题，因为它只匹配一个位置，并不<strong>消费</strong>任何字符。现在，我们可以这样来解决这个问题：<span class="regex">\b\w*q(?!u)\w*\b</span>。</p>
<p><span class="name">零宽度负预测先行断言</span><span class="code">(?!exp)</span>，<span class="desc">断言此位置的后面不能匹配表达式exp</span>。例如：<span class="regex">\d{3}(?!\d)</span>匹配<span class="desc">三位数字，而且这三位数字的后面不能是数字</span>；<span class="regex">\b((?!abc)\w)+\b</span>匹配<span class="desc">不包含连续字符串abc的单词</span>。</p>
<p>同理，我们可以用<span class="code">(?&lt;!exp)</span>,<span class="name">零宽度正回顾后发断言</span>来<span class="desc">断言此位置的前面不能匹配表达式exp</span>：<span class="regex">(?&lt;![a-z])\d{7}</span>匹配<span class="desc">前面不是小写字母的七位数字</span>。</p>
<p class="note">请详细分析表达式<span class="regex">(?&lt;=&lt;(\w+)&gt;).*(?=&lt;\/\1&gt;)</span>，这个表达式最能表现零宽断言的真正用途。</p>
<p>一个更复杂的例子：<span class="regex">(?&lt;=&lt;(\w+)&gt;).*(?=&lt;\/\1&gt;)</span>匹配<span class="desc">不包含属性的简单HTML标签内里的内容</span>。<span class="code">(&lt;?(\w+)&gt;)</span>指定了这样的<span class="name">前缀</span>：<span class="desc">被尖括号括起来的单词</span>(比如可能是&lt;b&gt;)，然后是<span class="part">.*</span>(任意的字符串),最后是一个<span class="name">后缀</span><span class="part">(?=&lt;\/\1&gt;)</span>。注意后缀里的<span class="part">\/</span>，它用到了前面提过的字符转义；<span class="part">\1</span>则是一个反向引用，引用的正是<span class="desc">捕获的第一组</span>，前面的<span class="part">(\w+)</span>匹配的内容，这样如果前缀实际上是&lt;b&gt;的话，后缀就是&lt;/b&gt;了。整个表达式匹配的是&lt;b&gt;和&lt;/b&gt;之间的内容(再次提醒，不包括前缀和后缀本身)。</p>
<h2 id="commenting">注释</h2>
<p>小括号的另一种用途是通过语法<span class="code">(?#comment)</span>来包含注释。例如：<span class="regex">2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)</span>。</p>
<p>要包含注释的话，最好是启用&#8220;忽略模式里的空白符&#8221;选项，这样在编写表达式时能任意的添加空格，Tab，换行，而实际使用时这些都将被忽略。启用这个选项后，在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如，我们可以前面的一个表达式写成这样：</p>
<pre class="regex">      (?&lt;=    # 断言要匹配的文本的前缀<br>      &lt;(\w+)&gt; # 查找尖括号括起来的字母或数字(即HTML/XML标签)<br>      )       # 前缀结束<br>      .*      # 匹配任意文本<br>      (?=     # 断言要匹配的文本的后缀<br>      &lt;\/\1&gt;  # 查找尖括号括起来的内容：前面是一个"/"，后面是先前捕获的标签<br>      )       # 后缀结束</pre>
<h2 id="greedyandlazy">贪婪与懒惰</h2>
<p>当正则表达式中包含能接受重复的限定符时，通常的行为是（在使整个表达式能得到匹配的前提下）匹配<strong>尽可能多</strong>的字符。考虑这个表达式：<span class="regex">a.*b</span>，它将会匹配<span class="desc">最长的以a开始，以b结束的字符串</span>。如果用它来搜索<span class="string">aabab</span>的话，它会匹配整个字符串<span class="desc">aabab</span>。这被称为<span class="name">贪婪</span>匹配。</p>
<p>有时，我们更需要<span class="name">懒惰</span>匹配，也就是匹配<strong>尽可能少</strong>的字符。前面给出的限定符都可以被转化为懒惰匹配模式，只要在它后面加上一个问号<span class="code">?</span>。这样<span class="regex">.*?</span>就意味着<span class="desc">匹配任意数量的重复，但是在能使整个匹配成功的前提下使用最少的重复</span>。现在看看懒惰版的例子吧：</p>
<p><span class="regex">a.*?b</span>匹配<span class="desc">最短的，以a开始，以b结束的字符串</span>。如果把它应用于<span class="string">aabab</span>的话，它会匹配<span class="desc">aab（第一到第三个字符）</span>和<span class="desc">ab（第四到第五个字符）</span>。</p>
<p class="note">为什么第一个匹配是aab（第一到第三个字符）而不是ab（第二到第三个字符）？简单地说，因为正则表达式有另一条规则，比懒惰／贪婪规则的优先级更高：最先开始的匹配拥有最高的优先权——The match that begins earliest wins。</p>
<table cellspacing="0">
    <caption>表5.懒惰限定符</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code">*?</span></td>
            <td><span class="desc">重复任意次，但尽可能少重复</span></td>
        </tr>
        <tr>
            <td><span class="code">+?</span></td>
            <td><span class="desc">重复1次或更多次，但尽可能少重复</span></td>
        </tr>
        <tr>
            <td><span class="code">??</span></td>
            <td><span class="desc">重复0次或1次，但尽可能少重复</span></td>
        </tr>
        <tr>
            <td><span class="code">{n,m}?</span></td>
            <td><span class="desc">重复n到m次，但尽可能少重复</span></td>
        </tr>
        <tr>
            <td><span class="code">{n,}?</span></td>
            <td><span class="desc">重复n次以上，但尽可能少重复</span></td>
        </tr>
    </tbody>
</table>
<h2 id="regexoptions">处理选项</h2>
<p class="note">在C#中，你可以使用<a  href="http://msdn2.microsoft.com/zh-cn/library/h5845fdz.aspx" title="MSDN 相关文档"><u><font color="#0000ff">Regex(String, RegexOptions)构造函数</font></u></a>来设置正则表达式的处理选项。如：Regex regex = new Regex("\ba\w{6}\b", RegexOptions.IgnoreCase);</p>
<p>上面介绍了几个选项如忽略大小写，处理多行等，这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项：</p>
<table cellspacing="0">
    <caption>表6.常用的处理选项</caption>
    <thead>
        <tr>
            <th scope="col">名称</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>IgnoreCase(忽略大小写)</td>
            <td>匹配时不区分大小写。</td>
        </tr>
        <tr>
            <td>Multiline(多行模式)</td>
            <td>更改<span class="code">^</span>和<span class="code">$</span>的含义，使它们分别在任意一行的行首和行尾匹配，而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,<span class="code">$</span>的精确含意是:匹配\n之前的位置以及字符串结束前的位置.) </td>
        </tr>
        <tr>
            <td>Singleline(单行模式)</td>
            <td>更改<span class="code">.</span>的含义，使它与每一个字符匹配（包括换行符\n）。 </td>
        </tr>
        <tr>
            <td>IgnorePatternWhitespace(忽略空白)</td>
            <td>忽略表达式中的非转义空白并启用由<span class="code">#</span>标记的注释。</td>
        </tr>
        <tr>
            <td>RightToLeft(从右向左查找)</td>
            <td>匹配从右向左而不是从左向右进行。</td>
        </tr>
        <tr>
            <td>ExplicitCapture(显式捕获)</td>
            <td>仅捕获已被显式命名的组。</td>
        </tr>
        <tr>
            <td>ECMAScript(JavaScript兼容模式)</td>
            <td>使表达式的行为与它在JavaScript里的行为一致。</td>
        </tr>
    </tbody>
</table>
<p>一个经常被问到的问题是：是不是只能同时使用多行模式和单行模式中的一种？答案是：不是。这两个选项之间没有任何关系，除了它们的名字比较相似（以至于让人感到疑惑）以外。</p>
<h2 id="balancedgroup">平衡组/递归匹配</h2>
<p class="important note">这里介绍的平衡组语法是由.Net Framework支持的；其它语言／库不一定支持这种功能，或者支持此功能但需要使用不同的语法。</p>
<p>有时我们需要匹配像<span class="desc">( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构</span>，这时简单地使用<span class="code">\(.+\)</span>则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式，懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等，比如<span class="string">( 5 / ( 3 + 2 ) ) )</span>，那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的，配对的括号之间的内容呢？</p>
<p>为了避免<span class="code">(</span>和<span class="code">\(</span>把你的大脑彻底搞糊涂，我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把<span class="string">xx &lt;aa &lt;bbb&gt; &lt;bbb&gt; aa&gt; yy</span>这样的字符串里，最长的配对的尖括号内的内容捕获出来？</p>
<p>这里需要用到以下的语法构造：</p>
<ul>
    <li><span class="code">(?'group')</span> 把捕获的内容命名为group,并压入<span class="name">堆栈(Stack)</span>
    </li>
    <li><span class="code">(?'-group')</span> 从堆栈上弹出最后压入堆栈的名为group的捕获内容，如果堆栈本来为空，则本分组的匹配失败
    </li>
    <li><span class="code">(?(group)yes|no)</span> 如果堆栈上存在以名为group的捕获内容的话，继续匹配yes部分的表达式，否则继续匹配no部分
    </li>
    <li><span class="code">(?!)</span> 零宽负向先行断言，由于没有后缀表达式，试图匹配总是失败</li>
</ul>
<p class="note">如果你不是一个程序员（或者你自称程序员但是不知道堆栈是什么东西），你就这样理解上面的三种语法吧：第一个就是在黑板
上写一个"group"，第二个就是从黑板上擦掉一个"group"，第三个就是看黑板上写的还有没有"group"，如果有就继续匹配yes部分，否则
就匹配no部分。</p>
<p>我们需要做的是每碰到了左括号，就在压入一个"Open",每碰到一个右括号，就弹出一个，到了最后就看看堆栈是否为空－－如果不为空那就证明左括号比右括号多，那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符)，尽量使整个表达式得到匹配。</p>
<pre class="regex">&lt;                         #最外层的左括号<br>    [^&lt;&gt;]*                #最外层的左括号后面的不是括号的内容<br>    (<br>        (<br>            (?'Open'&lt;)    #碰到了左括号，在黑板上写一个"Open"<br>            [^&lt;&gt;]*       #匹配左括号后面的不是括号的内容<br>        )+<br>        (<br>            (?'-Open'&gt;)   #碰到了右括号，擦掉一个"Open"<br>            [^&lt;&gt;]*        #匹配右括号后面不是括号的内容<br>        )+<br>    )*<br>    (?(Open)(?!))         #在遇到最外层的右括号前面，判断黑板上还有没有没擦掉的"Open"；如果还有，则匹配失败<br>&gt;                         #最外层的右括号</pre>
<p>平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配<span class="desc">嵌套的&lt;div&gt;标签</span>：<span class="regex">&lt;div[^&gt;]*&gt;[^&lt;&gt;]*(((?'Open'&lt;div[^&gt;]*&gt;)[^&lt;&gt;]*)+((?'-Open'&lt;/div&gt;)[^&lt;&gt;]*)+)*(?(Open)(?!))&lt;/div&gt;</span>.</p>
<h2 id="more">还有些什么东西没提到</h2>
<p>我已经描述了构造正则表达式的大量元素，还有一些我没有提到的东西。下面是未提到的元素的列表，包含语法和简单的说明。你可以在网上找到更详细的参
考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到关于.net下正则表达式详细的文档。</p>
<table cellspacing="0">
    <caption>表7.尚未详细讨论的语法</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code">\a</span></td>
            <td><span class="desc">报警字符(打印它的效果是电脑嘀一声)</span></td>
        </tr>
        <tr>
            <td><span class="code">\b</span></td>
            <td><span class="desc">通常是单词分界位置，但如果在字符类里使用代表退格</span></td>
        </tr>
        <tr>
            <td><span class="code">\t</span></td>
            <td><span class="desc">制表符，Tab</span></td>
        </tr>
        <tr>
            <td><span class="code">\r</span></td>
            <td><span class="desc">回车</span></td>
        </tr>
        <tr>
            <td><span class="code">\v</span></td>
            <td><span class="desc">竖向制表符</span></td>
        </tr>
        <tr>
            <td><span class="code">\f</span></td>
            <td><span class="desc">换页符</span></td>
        </tr>
        <tr>
            <td><span class="code">\n</span></td>
            <td><span class="desc">换行符</span></td>
        </tr>
        <tr>
            <td><span class="code">\e</span></td>
            <td><span class="desc">Escape</span></td>
        </tr>
        <tr>
            <td><span class="code">\0nn</span></td>
            <td><span class="desc">ASCII代码中八进制代码为nn的字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\xnn</span></td>
            <td><span class="desc">ASCII代码中十六进制代码为nn的字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\unnnn</span></td>
            <td><span class="desc">Unicode代码中十六进制代码为nnnn的字符</span></td>
        </tr>
        <tr>
            <td><span class="code">\cN</span></td>
            <td><span class="desc">ASCII控制字符。比如\cC代表Ctrl+C</span></td>
        </tr>
        <tr>
            <td><span class="code">\A</span></td>
            <td><span class="desc">字符串开头(类似^，但不受处理多行选项的影响)</span></td>
        </tr>
        <tr>
            <td><span class="code">\Z</span></td>
            <td><span class="desc">字符串结尾或行尾(不受处理多行选项的影响)</span></td>
        </tr>
        <tr>
            <td><span class="code">\z</span></td>
            <td><span class="desc">字符串结尾(类似$，但不受处理多行选项的影响)</span></td>
        </tr>
        <tr>
            <td><span class="code">\G</span></td>
            <td><span class="desc">当前搜索的开头</span></td>
        </tr>
        <tr>
            <td><span class="code">\p{name}</span></td>
            <td><span class="desc">Unicode中命名为name的字符类，例如\p{IsGreek}</span></td>
        </tr>
        <tr>
            <td><span class="code">(?&gt;exp)</span></td>
            <td><span class="desc">贪婪子表达式</span></td>
        </tr>
        <tr>
            <td><span class="code">(?&lt;x&gt;-&lt;y&gt;exp)</span></td>
            <td><span class="desc">平衡组</span></td>
        </tr>
        <tr>
            <td><span class="code">(?im-nsx:exp)</span></td>
            <td><span class="desc">在子表达式exp中改变处理选项</span></td>
        </tr>
        <tr>
            <td><span class="code">(?im-nsx)</span></td>
            <td><span class="desc">为表达式后面的部分改变处理选项</span></td>
        </tr>
        <tr>
            <td><span class="code">(?(exp)yes|no)</span></td>
            <td><span class="desc">把exp当作零宽正向先行断言，如果在这个位置能匹配，使用yes作为此组的表达式；否则使用no</span></td>
        </tr>
        <tr>
            <td><span class="code">(?(exp)yes)</span></td>
            <td><span class="desc">同上，只是使用空表达式作为no</span></td>
        </tr>
        <tr>
            <td><span class="code">(?(name)yes|no)</span></td>
            <td><span class="desc">如果命名为name的组捕获到了内容，使用yes作为表达式；否则使用no</span></td>
        </tr>
        <tr>
            <td><span class="code">(?(name)yes)</span></td>
            <td><span class="desc">同上，只是使用空表达式作为no</span></td>
        </tr>
    </tbody>
</table>
<h2 id="contact">联系作者</h2>
<p>好吧,我承认,我骗了你,读到这里你肯定花了不止30分钟.相信我,这是我的错,而不是因为你太笨.我之所以说"30分钟",是为了让你有信心,有耐心继续下去.既然你看到了这里,那证明我的阴谋成功了.被忽悠的感觉很爽吧？</p>
<p>要投诉我,或者觉得我其实可以做得更好,或者有任何其它问题,欢迎来<a  href="http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html"><u><font color="#0000ff">我的博客</font></u></a>让我知道.</p>
</div>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/72109.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2009-01-15 17:36 <a href="http://www.cppblog.com/richardhe/articles/72109.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>.net中的 delegate的标准C++模拟(转)</title><link>http://www.cppblog.com/richardhe/articles/66190.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Fri, 07 Nov 2008 02:05:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/66190.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/66190.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/66190.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/66190.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/66190.html</trackback:ping><description><![CDATA[<span style="font-family: 宋体; font-size: 14px; line-height: 25px;">
<p>用模板的偏特化和成员模板，重载函数调用运算符成功的实现了delegate,既可以绑定普通函数，也可以绑定对象及其成员函数<br>在cygnuwin下编译通过,&nbsp;<br>还不支持一个delegate包含多个函数的用法,不过相信很简单，从std::list派生一个类&nbsp;<br>就可以了&nbsp;<br>我用的cygun有些毛病，&nbsp;<br>my_delegate d2=my_delegate(t,&amp;Test::f);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^如果写成&amp;t，就会导致编译器内部错误，没办法了&nbsp;<br>&nbsp;&nbsp;<br>我本来写程序是加空行的，贴到BBS上就没了，忍受一下吧&nbsp;<br>Win32下的各种调用约定很讨厌，没有考虑，不过实现起来不费什么脑筋，就是麻烦，&nbsp;<br>不管了&nbsp;<br>&nbsp;&nbsp;<br>// Test.cpp : Defines the entry point for the console application.&nbsp;<br>//&nbsp;<br>#include &lt;stddef.h&gt;&nbsp;<br>template&lt;class T&gt;&nbsp;<br></p>
<p>//函数traits,用来提取函数的返回类型</p>
<p>struct function_traits&nbsp;<br>{&nbsp;<br>};&nbsp;<br>template&lt;class RT&gt;&nbsp;<br>struct function_traits&lt; RT(*)() &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT result_type;&nbsp;<br>};&nbsp;<br>template&lt;class RT,class AT&gt;&nbsp;<br>struct function_traits&lt; RT(*)(AT) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT result_type;&nbsp;<br>&nbsp;typedef AT argument_type;&nbsp;<br>};&nbsp;<br>template&lt;class RT,class AT1,class AT2&gt;&nbsp;<br>struct function_traits&lt; RT(*)(AT1,AT2) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT result_type;&nbsp;<br>&nbsp;typedef AT1 first_argument_type;&nbsp;<br>&nbsp;typedef AT2 second_argument_type;&nbsp;<br>};</p>
<p>// 函数traits,用来提取类成员函数的返回类型</p>
<p><br>template&lt;class RT, class OT&gt;&nbsp;<br>struct function_traits&lt; RT (OT::*)() &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef OT object_type;&nbsp;<br>&nbsp;typedef RT result_type;&nbsp;<br>};&nbsp;<br>template&lt;class RT, class OT, class AT&gt;&nbsp;<br>struct function_traits&lt; RT (OT::*)(AT) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef OT object_type;&nbsp;<br>&nbsp;typedef RT result_type;&nbsp;<br>&nbsp;typedef AT argument_type;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;typedef AT first_argument_type;&nbsp;<br>};&nbsp;<br>template&lt;class RT,class OT,class AT1,class AT2&gt;&nbsp;<br>struct function_traits&lt; RT (OT::*)(AT1,AT2) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef OT object_type;&nbsp;<br>&nbsp;typedef RT result_type;&nbsp;<br>&nbsp;typedef AT1 first_argument_type;&nbsp;<br>&nbsp;typedef AT2 second_argument_type;&nbsp;<br>};</p>
<p>// 把一个普通函数类向转化为类型兼容的指定类的成员函数类型&nbsp;<br>template &lt;typename OT, typename PFT&gt;&nbsp;<br>struct to_member_function_pointer&nbsp;<br>{&nbsp;<br>};&nbsp;<br>template &lt;typename OT,typename RT&gt;&nbsp;<br>struct to_member_function_pointer&lt; OT, RT(*)() &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)();&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT, typename AT&gt;&nbsp;<br>struct to_member_function_pointer&lt; OT, RT(*)(AT) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)(AT);&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT, typename AT1, typename AT2&gt;&nbsp;<br>struct to_member_function_pointer&lt; OT, RT(*)(AT1,AT2) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)(AT1,AT2);&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT, typename AT1, typename AT2, typename AT3&gt;&nbsp;<br>struct to_member_function_pointer&lt; OT, RT(*)(AT1,AT2,AT3) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)(AT1,AT2,AT3);&nbsp;<br>};&nbsp;<br></p>
<p>// 转化为const 成员函数</p>
<p>template &lt;typename OT, typename PFT&gt;&nbsp;<br>struct to_const_member_function_pointer&nbsp;<br>{&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT&gt;&nbsp;<br>struct to_const_member_function_pointer&lt; OT, RT(*)() &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)() const;&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT, typename AT&gt;&nbsp;<br>struct to_const_member_function_pointer&lt; OT, RT(*)(AT) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)(AT) const;&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT, typename AT1, typename AT2&gt;&nbsp;<br>struct to_const_member_function_pointer&lt; OT, RT(*)(AT1,AT2) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)(AT1,AT2) const;&nbsp;<br>};&nbsp;<br>template &lt;typename OT, typename RT, typename AT1, typename AT2, typename AT3&gt;&nbsp;<br>struct to_const_member_function_pointer&lt; OT, RT(*)(AT1,AT2,AT3) &gt;&nbsp;<br>{&nbsp;<br>&nbsp;typedef RT (OT::*type)(AT1,AT2,AT3) const;&nbsp;<br>};&nbsp;<br></p>
<p>// delegate的实现</p>
<p>template &lt;typename PFT&gt;&nbsp;<br>class delegate&nbsp;<br>{&nbsp;<br>&nbsp;class object&nbsp;<br>&nbsp;{&nbsp;<br>&nbsp;}*m_pObject; // 对象指针，是一个代理对象<br>&nbsp;typedef typename to_member_function_pointer&lt;object, PFT&gt;::type object_member_fuunction_pointer;&nbsp;<br>&nbsp;union&nbsp;<br>&nbsp;{&nbsp;<br>&nbsp; PFT m_pf;&nbsp;<br>&nbsp; object_member_function_pointer m_pmf;&nbsp;<br>&nbsp;}; // 函数指针和成员函数指针的联合体<br>&nbsp;public:&nbsp;<br>&nbsp; typedef typename function_traits&lt;PFT&gt;::result_type result_type;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; delegate()&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; m_pObject=NULL;&nbsp;<br>&nbsp;&nbsp; m_pf=NULL;&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; delegate(PFT pf)&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; operator=(pf);&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; template&lt;typename OT&gt;&nbsp;<br>&nbsp;&nbsp; delegate(&nbsp;<br>&nbsp;&nbsp; OT *pObject,&nbsp;<br>&nbsp;&nbsp; typename to_member_function_pointer&lt;OT, PFT&gt;::type pmf&nbsp;<br>&nbsp;&nbsp; )&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; m_pObject=reinterpret_cast&lt;object*&gt;(pObject);&nbsp;<br>&nbsp;&nbsp; m_pmf=*(reinterpret_cast&lt;object_member_function_pointer*&gt;(&amp;pmf));&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; template&lt;typename OT&gt;&nbsp;<br>&nbsp;&nbsp; delegate(&nbsp;<br>&nbsp;&nbsp; OT &amp;pObject,&nbsp;<br>&nbsp;&nbsp; typename to_member_function_pointer&lt;OT, PFT&gt;::type pmf&nbsp;<br>&nbsp;&nbsp; )&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; m_pObject=reinterpret_cast&lt;object*&gt;(&amp;pObject);&nbsp;<br>&nbsp;&nbsp; m_pmf=*(reinterpret_cast&lt;object_member_function_pointer*&gt;(&amp;pmf));&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; template&lt;typename OT&gt;&nbsp;<br>&nbsp;&nbsp; delegate(&nbsp;<br>&nbsp;&nbsp; const OT *pObject,&nbsp;<br>&nbsp;&nbsp; typename to_const_member_function_pointer&lt;OT, PFT&gt;::type pmf&nbsp;<br>&nbsp;&nbsp; )&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; m_pObject=const_cast&lt;object*&gt;(reinterpret_cast&lt;object*&gt;(pObject));&nbsp;<br>&nbsp;&nbsp; m_pmf=*(reinterpret_cast&lt;object_member_function_pointer*&gt;(&amp;pmf));&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; template&lt;typename OT&gt;&nbsp;<br>&nbsp;&nbsp; delegate(&nbsp;<br>&nbsp;&nbsp; const OT &amp;pObject,&nbsp;<br>&nbsp;&nbsp; typename to_const_member_function_pointer&lt;OT, PFT&gt;::type pmf&nbsp;<br>&nbsp;&nbsp; )&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; m_pObject=const_cast&lt;object*&gt;(reinterpret_cast&lt;object*&gt;(&amp;pObject));&nbsp;<br>&nbsp;&nbsp; m_pmf=*(reinterpret_cast&lt;object_member_function_pointer*&gt;(&amp;pmf));&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp;&nbsp;<br>&nbsp; delegate &amp; operator=(PFT pf)&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; m_pf=pf;&nbsp;<br>&nbsp;&nbsp; m_pObject=0;&nbsp;<br>&nbsp;&nbsp; return *this;&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp; template&lt;int&gt;&nbsp;<br>:gcc的函数模板不许无参数，加了个占位的"int"才能通过&nbsp;<br>&nbsp;&nbsp; result_type operator()()&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; if(m_pObject)&nbsp;<br>&nbsp;&nbsp;&nbsp; return (m_pObject-&gt;*m_pmf)();&nbsp;<br>&nbsp;&nbsp; else&nbsp;<br>&nbsp;&nbsp;&nbsp; return m_pf();&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp; template&lt;typename AT&gt;&nbsp;<br>&nbsp;&nbsp; result_type operator()(&nbsp;<br>&nbsp;&nbsp; AT a1&nbsp;<br>&nbsp;&nbsp; )&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; if(m_pObject)&nbsp;<br>&nbsp;&nbsp;&nbsp; return (m_pObject-&gt;*m_pmf)(a1);&nbsp;<br>&nbsp;&nbsp; else&nbsp;<br>&nbsp;&nbsp;&nbsp; return m_pf(a1);&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp; template&lt;typename AT1, typename AT2&gt;&nbsp;<br>&nbsp;&nbsp; result_type operator()(&nbsp;<br>&nbsp;&nbsp; AT1 a1,&nbsp;<br>&nbsp;&nbsp; AT2 a2&nbsp;<br>&nbsp;&nbsp; )&nbsp;</p>
<p>{&nbsp;<br>&nbsp;&nbsp; if(m_pObject)&nbsp;<br>&nbsp;&nbsp;&nbsp; return (m_pObject-&gt;*m_pmf)(a1,a2);&nbsp;<br>&nbsp;&nbsp; else&nbsp;<br>&nbsp;&nbsp;&nbsp; return m_pf(a1,a2);&nbsp;<br>&nbsp; }&nbsp;<br>&nbsp; template&lt;typename AT1, typename AT2, typename AT3&gt;&nbsp;<br>&nbsp;&nbsp; result_type operator()(&nbsp;<br>&nbsp;&nbsp; AT1 a1,&nbsp;<br>&nbsp;&nbsp; AT2 a2,&nbsp;<br>&nbsp;&nbsp; AT3 a3&nbsp;<br>&nbsp;&nbsp; )&nbsp;<br>&nbsp; {&nbsp;<br>&nbsp;&nbsp; if(m_pObject)&nbsp;<br>&nbsp;&nbsp;&nbsp; return (m_pObject-&gt;*m_pmf)(a1,a2,a3);&nbsp;<br>&nbsp;&nbsp; else&nbsp;<br>&nbsp;&nbsp;&nbsp; return m_pf(a1,a2,a3);&nbsp;<br>&nbsp; }&nbsp;<br>};&nbsp;<br>int gf(int)&nbsp;<br>{&nbsp;<br>&nbsp;return 0;&nbsp;<br>}&nbsp;<br>class Test&nbsp;<br>{&nbsp;<br>public:&nbsp;<br>&nbsp;int f(int){return 0;}&nbsp;<br>};&nbsp;<br>typedef delegate &lt; int (*)(int) &gt; my_delegate;&nbsp;<br>int main()&nbsp;<br>{&nbsp;<br>&nbsp;Test t;</p>
<p>&nbsp;</p>
<p>&nbsp;my_delegate d1=&amp;gf; // 普通函数<br>&nbsp;my_delegate d2=my_delegate(t,&amp;Test::f); //对象和类成员函数<br>&nbsp;d1(0); //调用<br>&nbsp;d2(2);&nbsp;<br>} <br></p>
</span><img src ="http://www.cppblog.com/richardhe/aggbug/66190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-11-07 10:05 <a href="http://www.cppblog.com/richardhe/articles/66190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏中的资源管理――资源高速缓存</title><link>http://www.cppblog.com/richardhe/articles/65198.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 27 Oct 2008 05:32:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/65198.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/65198.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/65198.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/65198.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/65198.html</trackback:ping><description><![CDATA[<p>《游戏中的资源管理――资源高速缓存》<br>转载请注明出处：<a  href="http://groups.google.com/group/jianguhan" target="_blank" rel="nofollow"><u><font color="#800080">http://groups.google.com/group/jianguhan</font></u></a> <br><br><br>1.什么是资源高速缓存 <br>&nbsp;&nbsp;&nbsp;
资源高速缓存的原理与其它内存高速缓存的工作原理是相似的。在游戏的状态转换过程中，有些数据是刚才使用过的，那么直接从资源高速缓存中载入即可。例
如，RPG&#173;游戏中主角从大地图进入一个房间，探索一番后主角退出房间，此时只要直接从缓存中载入大地图数据即可，节省了从硬盘载入数据的时间，要知道从
硬盘载入数据是非常&#173;慢的。当然，如果你的游戏所使用的数据文件很少，那么你可以在游戏运行过程中把这些数据完全储存在内存中，而不使用资源高速缓存。
</p>
<p><br>2.一个简单的资源高速缓存管理器 <br>&nbsp;&nbsp;&nbsp; 下面我将向你展示一个比较简单的资源高速缓存管理器，源代码来自我上一个游戏，如果你需要知道更多关于资源高速缓存方面的知识，请参考&lt;&lt;Game Coding Complete&gt;&gt;的第八章。 <br>首先，需要一个机制来唯一标识一个资源，我们用下面这个结构来做资源句柄： <br>struct ResHandle <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp; ResHandle(std::string &amp;resName, void *buffer, int size) <br>&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_resName = resName; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_size&nbsp;&nbsp; = size; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_buffer = buffer; <br>&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp; ~ResHandle() <br>&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (m_buffer != 0) delete[] m_buffer; <br>&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp; std::string&nbsp;&nbsp; m_resName;&nbsp;&nbsp;&nbsp; //资源名 <br>&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *m_buffer;&nbsp;&nbsp;&nbsp; //资源句柄所标识的资源 <br>&nbsp;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_size;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //资源所占内存大小 </p>
<p><br>}; </p>
<p><br>好了，现在我们可以从资源名来找出这个资源了，接下来实现这个资源高速缓存管理器： <br>class CacheManager <br>{ <br>public: <br>&nbsp;&nbsp;&nbsp;&nbsp; CacheManager(); <br>&nbsp;&nbsp;&nbsp;&nbsp; ~CacheManager(); </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //载入资源，resName为资源名，若载入成功size被设为该资源的大小 <br>&nbsp;&nbsp;&nbsp; //注意，管理中的资源不能在管理器外用delete显示的删除它 <br>&nbsp;&nbsp;&nbsp; void*&nbsp;&nbsp;&nbsp; Load(std::string resName, DWORD *size = 0); <br>&nbsp;&nbsp;&nbsp; //设置缓存大小，单位MB <br>&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetCacheSize(int sizeMB)&nbsp;&nbsp;&nbsp; { m_cacheSize = sizeMB * 1024 * 1024; } <br>&nbsp;&nbsp;&nbsp;&nbsp; //得到缓存大小，单位MB <br>&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetCacheSize()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { return m_cacheSize / 1024 /1024; } </p>
<p><br>private: <br>&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp; Free();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //释放lru链表中最后一个资源 <br>&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp; *Update(ResHandle *res);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //更新lru链表 <br>&nbsp;&nbsp;&nbsp;&nbsp; ResHandle *Find(std::string &amp;resName);&nbsp;&nbsp;&nbsp;&nbsp; //找出该资源名的资源句柄 </p>
<p><br>private: <br>&nbsp;&nbsp;&nbsp;&nbsp; DWORD m_cacheSize;&nbsp;&nbsp;&nbsp;&nbsp; //缓存大小 <br>&nbsp;&nbsp;&nbsp;&nbsp; DWORD m_allocated;&nbsp;&nbsp;&nbsp;&nbsp; //已使用的缓存大小 </p>
<p><br>//lru链表，记录最近被使用过的资源 <br>&nbsp;&nbsp;&nbsp;&nbsp; std::list&lt;ResHandle*&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lru;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; //资源标识映射 <br>&nbsp;&nbsp;&nbsp;&nbsp; std::map&lt;std::string, ResHandle*&gt;&nbsp;&nbsp;&nbsp; m_resources; </p>
<p>&nbsp;</p>
<p>}; </p>
<p><br>CacheManager:: CacheManager () <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp; m_cacheSize = 0; <br>&nbsp;&nbsp;&nbsp;&nbsp; m_allocated = 0; </p>
<p><br>} </p>
<p><br>CacheManager::~ CacheManager () <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!m_lru.empty()) Free();&nbsp;&nbsp; //释放所有管理中的资源 </p>
<p><br>} </p>
<p><br>void * CacheManager::Load(std::string resName, DWORD *size) <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp; ResHandle *handle = Find(resName);&nbsp;&nbsp; //查找该资源是否在缓存中 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; if (handle != 0) //如果找到该资源句柄，则返回该资源并更新lru链表 <br>&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (size != 0) *size = handle-&gt;m_size; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Update(handle); <br>&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp;&nbsp; else <br>&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //先检测资源大小 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD _size = 资源大小; </p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //是否有足够空间? <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (_size &gt; (m_cacheSize - m_allocated)) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (m_lru.empty()) break; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Free(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_allocated += _size; </p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer = new char[_size]; <br>//在这里用任何你能想到的办法载入资源文件到buffer <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230; </p>
<p><br>//记录当前资源 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResHandle *handle = new ResHandle(resName, buffer, _size); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lru.push_front(handle); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_resources[resName] = handle; </p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (size != 0) *size = _size; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return buffer; <br>&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp; return 0; </p>
<p>&nbsp;</p>
<p>} </p>
<p><br>void CacheManager::Free() <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp; std::list&lt;ResHandle*&gt;::iterator gonner = m_lru.end(); <br>&nbsp;&nbsp;&nbsp;&nbsp; gonner--; <br>&nbsp;&nbsp;&nbsp;&nbsp; ResHandle *handle = *gonner; <br>&nbsp;&nbsp;&nbsp;&nbsp; m_lru.pop_back(); <br>&nbsp;&nbsp;&nbsp;&nbsp; m_resources.erase(handle-&gt;m_resName); <br>&nbsp;&nbsp;&nbsp;&nbsp; m_allocated -= handle-&gt;m_size; <br>&nbsp;&nbsp;&nbsp;&nbsp; delete handle; </p>
<p><br>} </p>
<p><br>void * CacheManager::Update(ResHandle *res) <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp; m_lru.remove(res); <br>&nbsp;&nbsp;&nbsp;&nbsp; m_lru.push_front(res); <br>&nbsp;&nbsp;&nbsp;&nbsp; m_size = res-&gt;m_size; <br>&nbsp;&nbsp;&nbsp;&nbsp; return res-&gt;m_buffer; </p>
<p><br>} <br><br>ResHandle * CacheManager::Find(std::string &amp;resName) <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp; std::map&lt;std::string, ResHandle*&gt;::iterator it = m_resources.find(resName); <br>&nbsp;&nbsp;&nbsp;&nbsp; if (it == m_resources.end()) return 0; <br>&nbsp;&nbsp;&nbsp;&nbsp; return (*it).second; </p>
<p><br>} <br><br>至此，你已经可以在游戏中缓存任何你想缓存的资源了^_^ </p>
<p>3. 资源管理进阶 <br>&nbsp;&nbsp;&nbsp; 至此你已经可以在游戏中缓存任何你想缓存的资源了，但是你的任务还没完成，当你请求的资源存在于缓存之外时，那个闪耀的硬盘灯可能就是玩家最感兴趣的东西了。 <br>因此你必须根据不同的游戏类型使用不同的载入方式：&nbsp;<br>&nbsp;&nbsp;&nbsp; 一次载入所有东西：适用于任何以界面或关卡切换的游戏&nbsp;<br>&nbsp;&nbsp;&nbsp; 只在关键点载入资源：很多射击游戏都使用这样的设计，如&#8220;半条命&#8221;&nbsp;<br>&nbsp;&nbsp;&nbsp; 持续载入：适用于开放型地图的游戏，如&#8220;侠盗猎车手&#8221; <br>&nbsp;&nbsp;&nbsp; 如果有可能的话，你还可以使用缓存预测机制，当CPU有额外时间的时候可以把未来可能用到的资源载入到资源高速缓存。 <br>&nbsp;&nbsp;&nbsp; 最后，尽管在游戏的资源管理中资源打包不是必须的，但仍然建议大家把资源文件按类型分别打包到单一的文件中，这将为你节省磁盘空间，并加快游戏的载入速度。 </p><img src ="http://www.cppblog.com/richardhe/aggbug/65198.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-10-27 13:32 <a href="http://www.cppblog.com/richardhe/articles/65198.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FMOD音频引擎简单使用</title><link>http://www.cppblog.com/richardhe/articles/64473.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 20 Oct 2008 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/64473.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/64473.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/64473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/64473.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/64473.html</trackback:ping><description><![CDATA[<h2>
<a  href="http://www.cppblog.com/rise-worlds/archive/2008/10/19/64397.html" id="viewpost1_TitleUrl">FMOD音频引擎简单使用</a>
</h2>
<p>现代游戏已经不能没有声音，所以音频引擎成为游戏引擎中不可缺少的一部分．这是一篇介绍现代音频引擎的文章(<a  href="http://hard.zol.com.cn/labs/2003/0520/60986.shtml">http://hard.zol.com.cn/labs/2003/0520/60986.shtml</a>)．FMOD音频引擎(<a  href="http://www.fmod.org/">http://www.fmod.org</a>)是一个非常不错的音频引擎，其使用也比较简单，下面做一些简单介绍：<br>一．基本准备<br>它是免费的，你可以从它们的主站上下载API等文件．之后，你需要添加头文件和库文件，如下（C/C++）：  </p>
<div class="post">
<li>fmodvc.lib 用于 Microsoft Visual C++ 和 Codewarrior  </li>
<li>fmodbc.lib 用于 Borland  </li>
<li>fmodwc.lib 用于 Watcom  </li>
<li>fmodcc.lib 用于 LCC-Win32  </li>
<li>libfmod.a 用于 MingW and CygWin  </li>
<li>fmod-3-7.lib 用于 GCC<br>（参考：<a  href="http://www.gamedev.net/reference/articles/article2098.asp">http://www.gamedev.net/reference/articles/article2098.asp</a>）<br>之后，只要添加fmod.h头文件后就可以使用了．<br>二．开始使用<br>１．初始化<br>开始播放声音前，需要进行初始化，很简单：<br>FSOUND_Init (44100, 32, 0);<br>第一个参数是输出HZ，第二是最大软件信道数可以不管也不会增加ＣＰＵ负担，第三个参数可以设置一些标志可以不设置则赋值为０．<br>２．基本常识<br>ＦＭＯＤ将音频分为声音(sound)和音乐(music)两种．前者如：.MOD, .S3M, .XM, .IT, .MID, .RMI, .SGT or .FSB<br>等，后者如： .WAV, .MP2, .MP3, .OGG or .RAW等．二者使用不同的函数处理．都可以通过采样后流的方式来处理．不过小文件一般通过采样方式，它可以多次播放但占用内存．大文件通过流方式，减少内存消耗．<br>３．播放音乐<br>首先定义一个FMUSIC_MODULE类型变量来作为文件句柄．然后就可以通过FMUSIC API来实现，如：<br>装入文件：<br>handle=FMUSIC_LoadSong("YourFileName");<br>FMUSIC_PlaySong(handle);<br>音量控制：FMUSIC_SetMasterVolume (handle, 255);后面的参数在0~255之间，值越大声音越大．<br>暂停播放：FMUSIC_SetPaused (handle, true);<br>重开始：FMUSIC_SetPaused (handle, false);<br>循环播放：FMUSIC_SetLooping (handle, true);<br>停止播放：FMUSIC_StopSong (handle);<br>释放音频内存：FMUSIC_FreeSong (handle);<br>下面是一个命令模式下的例子：<br>#include &lt;conio.h&gt;<br>#include "inc/fmod.h"<br>FMUSIC_MODULE* handle;<br>int main ()<br>{<br>&nbsp;&nbsp; // 初始化<br>&nbsp;&nbsp; FSOUND_Init (44100, 32, 0);<br>&nbsp;&nbsp; // 装如<br>&nbsp;&nbsp; handle=FMUSIC_LoadSong ("canyon.mid");<br>&nbsp;&nbsp; // 只播放一次<br>&nbsp;&nbsp; // 播放midi文件时请关闭循环播放<br>&nbsp;&nbsp;&nbsp; FMUSIC_SetLooping (handle, false);<br>&nbsp;&nbsp; //播放<br>&nbsp;&nbsp; FMUSIC_PlaySong (handle);<br>&nbsp; // 按任一键结束<br>&nbsp;&nbsp; while (!_kbhit())<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp; }<br>&nbsp;&nbsp; //释放<br>&nbsp;&nbsp; FMUSIC_FreeSong (handle);<br>&nbsp;&nbsp; FSOUND_Close();<br>}<br>４．播放声音<br>4.1 采样(Sample)方式<br>先定义FSOUND_SAMPLE类型变量，然后就可以使用FSOUND系列函数来实现，如：<br>装如文件：<br>handle=FSOUND_Sample_Load (0,"YourFileName",0,0,0);　　//除文件名外的参数用于多采样或其它等<br>FSOUND_PlaySound (0,handle);<br>设置音量：FSOUND_SetVolume (handle, 255);<br>暂听：FSOUND_SetPaused (handle, true);<br>重新开始：FSOUND_SetPaused (handle, false);<br>停止：FSOUND_StopSound (handle);<br>释放：FSOUND_Sample_Free (handle);<br>下面是一个简单的例子：<br>#include &lt;conio.h&gt;<br>#include "inc/fmod.h"<br>FSOUND_SAMPLE* handle;<br>int main ()<br>{<br>&nbsp;&nbsp; // 初始化<br>&nbsp;&nbsp; FSOUND_Init (44100, 32, 0);<br>&nbsp;&nbsp; // 装载和播放<br>&nbsp;&nbsp; handle=FSOUND_Sample_Load (0,"sample.mp3",0, 0, 0);<br>&nbsp;&nbsp; FSOUND_PlaySound (0,handle);<br>&nbsp;&nbsp; // 按任一键结束<br>&nbsp;&nbsp; while (!_kbhit())<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp; }<br>&nbsp;&nbsp; // 释放<br>&nbsp;&nbsp; FSOUND_Sample_Free (handle);<br>&nbsp;&nbsp; FSOUND_Close();<br>}<br>4.2 流(stream)方式<br>先定义一个FSOUND_STREAM 类型变量，然后：<br>装入文件：<br>handle=FSOUND_Stream_Open("YourFileName",0, 0, 0);<br>FSOUND_Stream_Play (0,handle);<br>　　　提示：3.7版本之前的方式是不一样的．<br>停止：FSOUND_Stream_Stop (handle);<br>释放：FSOUND_Stream_Close(handle);<br>其它和前面是一样的．下面是一个简单的例子：<br>#include &lt;conio.h&gt;<br>#include "inc/fmod.h"<br>FSOUND_STREAM* handle;<br>void main ()<br>{<br>&nbsp;&nbsp; //init FMOD sound system<br>&nbsp;&nbsp; FSOUND_Init (44100, 32, 0);<br>&nbsp;&nbsp; //load and play sample<br>&nbsp;&nbsp; handle=FSOUND_Stream_Open("sample.mp3",0, 0, 0);<br>&nbsp;&nbsp; FSOUND_Stream_Play (0,handle);<br>&nbsp;&nbsp; //wait until the users hits a key to end the app<br>&nbsp;&nbsp; while (!_kbhit())<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp; }<br>&nbsp;&nbsp; //clean up<br>&nbsp;&nbsp; FSOUND_Stream_Close(handle);<br>&nbsp;&nbsp; FSOUND_Close();<br>}<br>５．关闭<br>FSOUND_Close ();<br>参考：<br>A Quick Guide to FMOD by <a  href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#119;&#101;&#98;&#109;&#97;&#115;&#116;&#101;&#114;&#64;&#106;&#111;&#97;&#99;&#104;&#105;&#109;&#114;&#111;&#104;&#100;&#101;&#46;&#100;&#101;">Joachim Rohde</a>（<a  href="http://www.gamedev.net/reference/articles/article2098.asp">http://www.gamedev.net/reference/articles/article2098.asp</a>）<br>ＦＭＯＤ wiki（<a  href="http://www.devmaster.net/wiki/FMod">http://www.devmaster.net/wiki/FMod</a>）</li>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/64473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-10-20 10:37 <a href="http://www.cppblog.com/richardhe/articles/64473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程程序设计的相关问题</title><link>http://www.cppblog.com/richardhe/articles/64465.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 20 Oct 2008 02:09:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/64465.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/64465.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/64465.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/64465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/64465.html</trackback:ping><description><![CDATA[<span><font size="4">一、&nbsp;&nbsp;&nbsp;&nbsp;什么是进程？什么是线程？<br>　　　进程是一大堆系统对象拥有权的集合。如进程拥有内存上下
文，文件句柄，可以派生出很多线程，也可以拥有很多DLL模块。在windows系统中，进程并不完成实质的工作，只是提供一个相对独立的运行环境，线程
才是完成实际工作的载体。线程从属于进程，共享进程所拥有的系统对象。线程是操作系统调度的单位。实质上，线程就是一段可执行代码。<br></font><font size="4"><font color="#0000ff">采用多进程的优点和缺点：<br></font>优点：运行环境相对独立，某一进程的崩溃一般不会影响到其它进程的执行。<br>缺点：<br>耗时耗资源：启动一个进程需要申请大量的系统资源，其中包括虚拟内存、文件句柄以及加载各种必要的动态链接库；线程则不需要以上动作，因为它共享进程中的所有资源。<br>&#8220;系统准备一个进程环境可能需要好几M的空间&#8221;<br>通
信复杂：进程的地址空间独立，进程A的地址X，在进程B中可能是无意义的，这样，当进程间需要共享数据时，就需要特殊的机制来完成这些工作。线程则在同一
地址空间，数据共享方便快捷。&#8220;线程是一个物美价廉的选择，在一个Windows上拥有500个线程是一件很轻易的事情，但是500个进程将是难以想象的
&#8221;。<br><br>二、&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">为什么需要多线程</font>（解释何时考虑使用线程）<br>从用户的角度考虑，就是为了得到更好的系统服务；从程序自身的角度考虑，就是使目标任务能够尽可能快的完成，更有效的利用系统资源。综合考虑，一般以下场合需要使用多线程：<br>1、&nbsp;&nbsp;&nbsp;&nbsp;程序包含复杂的计算任务时<br>主要是利用多线程获取更多的CPU时间（资源）。<br>2、&nbsp;&nbsp;&nbsp;&nbsp;处理速度较慢的外围设备<br>比如：打印时。再比如网络程序，涉及数据包的收发，时间因素不定。使用独立的线程处理这些任务，可使程序无需专门等待结果。<br>3、&nbsp;&nbsp;&nbsp;&nbsp;程序设计自身的需要<br>WINDOWS系统是基于消息循环的抢占式多任务系统，为使消息循环系统不至于阻塞，程序需要多个线程的来共同完成某些任务。<br>三、&nbsp;&nbsp;&nbsp;&nbsp;使用多线程可能出现的问题（列举问题）<br>事
实上，单纯的使用线程不会产生任何问题，其启动、运行和结束都是非常简单的事情。在Win32环境下，启动：CreateThread，运行就是函数执行
的过程，中止就是函数返回的过程或者调用ExitThread。但是由于下列原因可能会使在使用线程的过程中带来一系列问题：<br>1、&nbsp;&nbsp;&nbsp;&nbsp;版本问题<br>多
任务的概念是随着实际需求的提出而产生，最初的程序设计者并没有考虑到代码需要在多线程环境下运行，在多线程环境下使用这些代码无疑将产生访问冲突。最典
型的例子就是C runtime library。最早的C runtime
library产生于20世纪70年代，当时连多任务都是一个新奇的概念，更别说什么多线程了，该版本的库中使用了大量全局变量和静态变量（产生竞争条件
的根源，对局部变量无此要求，因为局部变量都使用栈，每个线程都有自己的栈空间，另外在启动线程时，给线程函数的参数应该是尽量使用值，而非指针或引用，
这样可以避免因此带来的冲突问题），如在该库中统一使用一个errno变量来表明程序的错误码，如果在多线程中使用该库，并且都需要设置错误码时，此时即
产生了一个冲突。<br>VC为防止以上问题，提供了另外一个线程安全的C runtime
library，因此在写多线程程序时，需要注意所连接库的版本是否正确（该过程一般由应用程序向导完成，因此平时编程并无此问题）。与此有关的还有一些
其它版本：单线程版、多线程版调试版和多线程发行版。<br>2、&nbsp;&nbsp;&nbsp;&nbsp;线程间共享资源时形成竞争条件（race condition）<br>一般而
言，线程并不是单独行动，通常是多个线程分工协作，完成一个大任务中的不同小任务，此时，这些线程之间就需要共同操作一些资源，比较典型的例子是多个线程
进行文件操作或屏幕打印的情况：线程A在写文件进行了一半时，发生了context
switch，另外一个线程B继续进行写文件操作，此时文件的内容将会凌乱不堪。甚至造成异常错误。典型的例子是，三个线程，线程A在堆中申请了一块内存
并填入了一个值，线程B读取了该值后将该内存释放，如果线程C还要对该内存操作时，将导致异常。<br>3、&nbsp;&nbsp;&nbsp;&nbsp;线程间的通信问题<br>线程协作完
成某一任务时，有时还需要通信以控制任务的执行步骤，典型的例子就是读写者线程：写线程在对某内存区域写完数据后，需要通知读线程来取，读完之后又需要通
知写线程可以继续往里写入数据。更为广泛的例子是：某线程需要等待某一事件发生，以决定是否继续工作。此时，如果没有正确控制线程的执行过程，将导致不可
预料的错误发生。<br>4、&nbsp;&nbsp;&nbsp;&nbsp;由于不规范的使用线程导致系统效率下降<br>进程中包含了一个以上的线程，这些线程可能会动态的申请某些资源，如
某些数据库线程可能会动态加载数据库方面的动态链接库，但是在该线程结束时，并没有及时释放该动态链接库即被其他线程强行终止，于是该进程中的该动态链接
库引用计数不为0，从而导致该动态链接库在该进程中存有一个副本。当这种情况频繁时，将对系统效率产生很大的影响。<br>四、&nbsp;&nbsp;&nbsp;&nbsp;线程的类型（解释UI线程和WORKER线程的区别和联系）<br>严格说来，线程并没有什么本质区别，但是Win32编程文档中却反复强调UI线程和Worker线程的区别。并给出了它们的定义：<br>UI线程就是：拥有消息队列和窗口的线程，并且它的主要职责是处理窗口消息。Worker线程则没有消息队列，但是当Worker线程产生一个用户界面（消息框和模式对话框除外）时，则该线程则摇身一变，成为UI线程。<br>问题：<br>1、&nbsp;&nbsp;&nbsp;&nbsp;线程的消息队列和窗口的消息队列<br>在Win32中，每个线程都有它自己专属的消息队列，而窗口并不总是有消息队列，因为一个UI线程可以创建很多个窗口。<br>2、&nbsp;&nbsp;&nbsp;&nbsp;UI线程到底跟Worker线程存在什么差别？<br>职
责不一样：UI线程负责处理与用户界面有关的消息，一般而言，用户界面消息来自用户输入（如鼠标键盘消息）、系统消息（如WM_PAINT）以及程序产生
的用户自定义消息。因此，在该线程下一般不能存在等待(wait&#8230;)函数，这样该线程就会挂起，从而影响消息队列的处理。Worker线程不用处理用户界
面消息，而是完成一般性的计算任务，该线程等待计算过程中必要的资源时，不会影响到界面的刷新动作。<br>操作系统的管理不一样：对UI线程来说，产生一个UI线程实际上产生了两个线程，一个是其自身，另一个是操作系统为响应其GDI调用而产生的影子线程。<br>3、&nbsp;&nbsp;&nbsp;&nbsp;Worker线程变成UI线程有什么不好？<br>Worker线程一般用于计算，此时如果它转换为UI线程的话，将无暇顾及用户界面的消息响应。<br>4、&nbsp;&nbsp;&nbsp;&nbsp;Worker线程可否拥有自己的消息队列？<br>Worker线程同样可以拥有自己的消息队列，该队列一般通过PeekMessage()调用建立，通过GetMessage调用来解析。（具体实现看源码）<br>5、&nbsp;&nbsp;&nbsp;&nbsp;用以下规则来管理win32中线程、消息和窗口的互动<br>所有传送给某一窗口的消息，将由产生该窗口的线程负责处理。<br>五、&nbsp;&nbsp;&nbsp;&nbsp;线程的启动和中止（解释启动线程的不同方式及其它们的区别和实用场合）<br>随C Runtime Library库的更新和编程环境的不同，线程的启动方式也有所不同，以下介绍几种典型的线程启动方式。<br>1、_beginthread和_endthread<br>该
函数是C Runtime Library中的函数，它负责初始化函数库；其原型如下unsigned long _beginthread(
void( __cdecl *start_address )( void * ), unsigned stack_size, void
*arglist
);&#8220;该函数被认为是头脑简单的函数&#8221;，使用该函数导致无法有效的控制被创建线程，如不能在启动时将该线程挂起，无法为该线程设置优先权等。另外，该函数
为隐藏Win32的实现细节，启动线程的第一件事情即将自己的Handle关闭，因此也就无法利用这个Handle来等待该线程结束等操作。该函数是早期
的C Runtime Library的产物，不提倡使用，后期的改良版本为_beginthreadex。<br>通过_beginthread启动的线程在应当通过调用_endthread结束，以保证清除与线程相关的资源。<br>2、_beginthreadex和_endthreadex<br>该
函数是C Runtime
Library中的一个函数，用标准C实现，相比_beginthread，_beginthreadex对线程控制更为有力（比前者多三个参数）,是
_beginthread的加强版。其原型为unsigned long _beginthreadex( void *security,
unsigned stack_size, unsigned ( __stdcall *start_address )( void * ),
void *arglist, unsigned initflag, unsigned *thrdaddr
);该函数返回新线程的句柄，通过该句柄可实现对线程的控制。虽然，该函数是用标准C写的（即可不加修改就可以移植到其他系统执行），但是由于它与
Windows系统有着紧密的联系（需要手动关闭该线程产生的Handle），因此实现时，往往需要包含windows.h。<br>通过_beginthreadex启动的线程通过调用_endthreadex做相关清理。<br>3、CreateThread和ExitThread<br>CreateThread
是Win32 API函数集中的一个函数，其原型为HANDLE CreateThread(LPSECURITY_ATTRIBUTES
lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE
lpStartAddress,LPVOID lpParameter,DWORD wCreationFlags,LPDWORD
lpThreadId);该函数使用Win32编程环境中的类型约定，只适用于Windows系统。参数形式与_beginthreadex一致，对线程
控制能力也与之一致，只是该函数与C Runtime
Library没有任何关系，它不负责初始化该库，因此在多线程环境中，如果使用该函数启动线程，则不应使用C Runtime
Library中的多线程版本的函数。取而代之的应该是功能相对应的 Win32 API函数；另外，应当自己手工提供线程同步的代码。<br>通过CreateThread创建的线程则通过ExitThread做清理工作。<br>4、AfxBeginThread和AfxEndThread<br>AfxBeginThread
是MFC提供的线程启动方式，它是个重载函数，有两种调用形式：Worker线程版和UI线程版。MFC对Win32线程做了小心的很好的封装
（CWinThread），虽然其总是调用了_beginthreadex来启动一个线程，但是其额外做的工作使得在MFC环境下，操作线程变得简单明
了，并且不需要太多的关注细节问题。MFC在线程的封装方面主要做了下列事情：<br>1、&nbsp;&nbsp;&nbsp;&nbsp;自动清除CWinThread对象<br>2、&nbsp;&nbsp;&nbsp;&nbsp;关闭线程handle，线程对象自动释放<br>3、&nbsp;&nbsp;&nbsp;&nbsp;存储了线程相关的重要参数，即线程handle和线程ID<br>4、&nbsp;&nbsp;&nbsp;&nbsp;辅之以其它MFC同步对象，方便的实现线程同步<br>5、&nbsp;&nbsp;&nbsp;&nbsp;使用了严格的断言调试语句，使线程调试变得相对简单<br><br>&#8220;（C
Runtime
Library是用标准C开发的实用函数集）如果多线程程序中使用了标准C库函数，并用CreateThread()和ExitThread()，则会导
致内存泄漏。解决这个问题的方法是用C运行库（run-time library）函数来启动和终止线程，而不用WIN32
API定义的CreateThread()和ExitThread()。在C运行库函数中，它们的替代函数分别是_beginthreadex()和
_exitthreadex()，需要的头文件是_process.h。在VC6.0下，还需在
Project-&gt;Settings-&gt;C/C++-&gt;Code Generation中选择Multithreaded
Runtime
Library。当然，也可以通过避免使用C标准库函数的方法来解决上述问题，WIN32提供了一些C标准库函数的替代函数，例如，可用
wsprintf()和lstrlen()来代替sprintf()和strlen()。这样，使用CreateThread()和
ExitThread()不会出现问题。&#8221;<br>六、&nbsp;&nbsp;&nbsp;&nbsp;线程的同步问题（介绍Windows的同步机制）<br>1、&nbsp;&nbsp;&nbsp;&nbsp;怎样等待一个线程结束（忙等（busy loop）和高效的等（WaitForSingleObject））<br>1）&nbsp;&nbsp;&nbsp;&nbsp;忙等（busy loop）<br>hThrd = CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&amp;threadId );<br>for (;;)<br>{<br>GetExitCodeThread(hThrd, &amp;exitCode);<br>if ( exitCode != STILL_ACTIVE )<br>break;<br>}<br>CloseHandle(hThrd);<br>缺点：耗费CPU资源，且如果在UI线程中这样等待将导致窗口无法刷新。不推荐使用。<br>2）&nbsp;&nbsp;&nbsp;&nbsp;高效的等待<br>（1）WaitForSingleObject;<br>关于WaitForSingleObject的参数，前者为等待的对象，后者为等待的时间，对某些执行时间较长的线程，可以设置一个合适的值，等待完这个时间后，更新界面，然后继续等待，或者强行终止线程。<br>将以上的等待部分的代码改为：<br>WaitForSingleObject（hThrd,INFINITE）;<br>该函数相当于Sleep函数，当需要等待的对象（句柄）没有被触发时，等待的线程将被自动挂起。该方法解决了耗费CPU时间的问题，但是在UI线程中，仍不能使用该方法来等待某一线程结束。<br>解决方法之一：创建一个Worker管理者线程，在该线程中等待，工作者线程完成，然后由管理者线程发消息通知UI线程更新窗口。<br>（2）WaitForMultipleObject<br>该函数允许在同一时间等待多个对象，函数的原型如下：<br>DWORD WaitForMultipleObject(DWORD nCount，CONST HANDE *lpHandles,BOOL bWaitAll,dwMilliseconds)；<br>第一个参数表示句柄数组的大小；等待的对象不能超过64<br>第二个参数为句柄数组；<br>第三个参数表明是否等待所有对象激发。True表示是。<br>第四个参数为等待时间。<br>关于WaitForMultipleObject的返回值：<br>当bWaitAll为True时，返回值为WAIT_OBJECT_0；<br>当bWaitAll为false时，返回值减去WAIT_OBJECT_0，就是激发对象所在的下标。<br>应用：<br>A）&nbsp;&nbsp;&nbsp;&nbsp;解决多个工人n完成多个任务m（n&lt;m）的问题（bWaitAll设置为false）<br>解决的思路如下：先从m个任务中取出n个任务，对应地用n个工人去完成，然后利用该函数等待其中任意一个工人结束任务，一旦结束则让其做另外一个任务<br>B）&nbsp;&nbsp;&nbsp;&nbsp;解决等待多个资源的问题（bWaitAll设置为true）<br>哲学家就餐问题：5个哲学家在圆桌旁，每个哲学家左手边放着1只筷子，哲学家做两件事情，吃饭和思考，吃饭时同时需要其左右的两只筷子。<br>解决思路：将哲学家模拟为线程，筷子为资源，只有哲学家线程同时获得两个资源时，方可进一步动作（吃饭）。即：<br>WaitForMultipleObjects(2, myChopsticks, TRUE, INFINITE);<br>MyChopsticks是一个大小为5的核心对象数组。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（3）MsgWaitForMultipleObjects<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;原型：<br>DWORD MsgWaitForMultipleObjects( DWORD nCount,CONST HANDLE pHandles,BOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask);<br>&nbsp;&nbsp;&nbsp;&nbsp;前
几个参数含义同WaitForMultipleObject，最后一个是消息屏蔽标识，指示接收消息的类型。此外返回值也有额外的意义：当消息到达时，该
函数返回WAIT_OBJECT_0+nCount。以下是常见的使用MsgWaitForMultipleObjects的架构：<br>&nbsp;&nbsp;while (!quit)<br>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; // Wait for next message or object being signaled<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp; dwWake;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwWake = MsgWaitForMultipleObjects(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gNumPrinting,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gPrintJobs,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FALSE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INFINITE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QS_ALLEVENTS);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dwWake &gt;= WAIT_OBJECT_0 &amp;&amp; dwWake &lt; WAIT_OBJECT_0 + gNumPrinting)<br>&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;} // end if<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (dwWake == WAIT_OBJECT_0 + gNumPrinting)<br>&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;while (PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; // Get Next message in queue<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (msg.message == WM_QUIT)<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;&nbsp;&nbsp;&nbsp;&nbsp; quit = TRUE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exitCode = msg.wParam;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } // end if<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TranslateMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DispatchMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } // end while<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;} // end while<br>2、&nbsp;&nbsp;&nbsp;&nbsp;怎样有效的控制一个线程<br>在任何情况下，切记线程的核心属性为：线程的句柄，线程的ID号。因此控制一个线程也需从这两方面着手。<br>1）&nbsp;&nbsp;&nbsp;&nbsp;使用能返回线程Handle的启动函数来启动线程（除_beginthread外）<br>2）&nbsp;&nbsp;&nbsp;&nbsp;尽量不要使一个工作量较大的线程成为&#8220;闷葫芦&#8221;，从而使该线程能够接收外界通知消息；如下列代码：<br><br><br>MSG msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;while(1)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PeekMessage(&amp;msg,NULL,0,0,PM_REMOVE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(msg.message==WM_MY)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(100);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>注：GetMessage也是用来得到消息队列中一条消息的函数，它们的区别在于GetMessage是同步的，即如果消息队列中没有消息的话，该线程将自动挂起。使用GetMessage可以使Worker线程成为一个一步一动的线程！<br>&nbsp;&nbsp;&nbsp;&nbsp;MSG msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;while(GetMessage(&amp;msg,NULL,0,0))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(msg.message==WM_MY)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Do something here<br>}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>以上的过程也可以通过事件对象予以实现。<br>悬而未决的问题：怎么控制一个正在等待其他事件的线程。如：一个TCP监听线程，在某一Socket上listen，此时该线程处于挂起状态！但是现在主线程又需要关闭该线程，应该怎么操作！<br><br>3、&nbsp;&nbsp;&nbsp;&nbsp;怎样互斥访问一个资源（CMutex和Critical Section）<br>何时需要一个互斥对象？<br>常
见的情形：多个线程需要不定时的操作同一链表（锁链表的头指针）；多个线程需要不定时的进行写文件或是进行屏幕输出（锁文件句柄或屏幕句柄）；多个线程需
要不定时对某个计数器进行操作（锁这个变量）；在多线程环境吓，凡是涉及到对全局变量、静态变量、堆中的内存进行访问时，都应该考虑，是否可能出现一个
race condition（竞争条件）。<br>1）&nbsp;&nbsp;&nbsp;&nbsp;互斥器<br>Win32提供了对互斥资源访问的一整套机制，其中之一就是互斥器，MFC将这些API函数加以封装，形成了CMutex互斥类，使用这两种方法都能够实现对资源的互斥访问。<br>Win32中的API：<br>CreateMutex：<br>原型：<br>HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,&nbsp;&nbsp; BOOL bInitialOwner,&nbsp;&nbsp;LPCTSTR lpName );<br>第一个参数为安全属性；<br>第二个参数用来指示互斥器的拥有者是否为当前线程；<br>第三个参数为互斥器的名称；<br>当不再需要互斥器时，应当调用CloseHandle关闭。<br>约
定：互斥器产生之后，由某一线程完成锁定工作（即调用Wait&#8230;函数），此时系统将该mutex的拥有权交于该线程，然后短暂地将该对象设置为激发态，于
是Wait&#8230;函数返回，做完相应的工作之后（如：修改链表指针、修改计数器、写文件等），调用ReleaseMutex释放拥有权。周而复始。<br>MFC中的互斥器CMutex对象：<br>A、&nbsp;&nbsp;&nbsp;&nbsp;利用其构造函数产生一个互斥器对象<br>HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner, LPCTSTR lpName);<br>B、&nbsp;&nbsp;&nbsp;&nbsp;配合CSingleLock或者CmutipleLock产生一个临时对象，对产生的互斥器进行加锁和释放的动作；<br>2）&nbsp;&nbsp;&nbsp;&nbsp;临界区<br>另一个提供互斥访问的机制是Critical Section，该机制较前一种方法廉价，因为它不属于不是系统的核心对象；临界区可以反复进入，这一点与Mutex有所区别，这需要我们在使用临界区时，保证进入的次数要等于离开的次数。<br>相关函数为InitializeCriticalSection、DeleteCriticalSection、EnterCriticalSection、LeaveCriticalSection。<br>4、&nbsp;&nbsp;&nbsp;&nbsp;怎样等待多个不同（或者相同）资源（WaitForMultiObject）<br>等待多个不同资源在多线程程序设计中时常遇到，如：等待某一线程结束和某一个资源被释放，等待缓冲区和设备准备好两个资源；这种现实情况，可以分别为不同的资源设置系统对象，然后利用WaitForMultiObject进行等待。<br>5、&nbsp;&nbsp;&nbsp;&nbsp;怎样等待多个资源中的一个（使用CSemaphore）<br>现实中还可能出现如下情形：客人租相机的问题：有若干客人需要，租相机，总相机数为n，相机租完后，客人必须等待，只要有一个相机，则某客人就可以等到租借。还有许多问题可以用这种Producer/consumer模型加以概括。<br>这种情形即是等待多个资源中的一个的情况，在Win32程序设计中则经常使用信号量（Semaphore）来解决此问题。<br>Win32系统中，信号量具有以下特性：<br>一
个信号量可以被锁定N次，N一般代表可用资源的个数，上例中即可代表相机的个数，信号量初始化后，在Win32环境下调用一次Wait&#8230;操作即表示对其的
一次锁定，信号量的值相应加1，操作完后，调用ReleaseSemaphore操作，即代表资源释放（上述例子中就是归还相机）。MFC对Win32信
号量的相关API函数进行了封装（CSemaphore），配合CMultiLock 或者 CSingleLock即可实现锁定和资源释放的动作。<br>七、&nbsp;&nbsp;&nbsp;&nbsp;线程间的通信<br>线程间的通信有许多方法可以实现，视场合不同也有不同的应用，大致可以分为两类：进程内的线程通信和进程间的通信。关于进程内线程的通信，前面所述的各种同步互斥等待机制也可归属线程间通信的范畴，<br>1、&nbsp;&nbsp;&nbsp;&nbsp;使用线程消息实现线程通信<br>2、&nbsp;&nbsp;&nbsp;&nbsp;使用事件对象实现线程通信<br>Win32还提供了一种比较灵活的核心对象，该对象完全受控于程序（只是清除的时候由系统回收），这就是Event（事件）对象。事件对象一般用于线程间的通知。下面先看事件对象的一些属性：<br>创建一个事件对象可以调用Win32 API函数完成，也可以使用MFC封装的事件对象。其API原型为：<br>HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState, LPCTSTR lpName );<br>第二个参数指示事件对象是否为手动修改状态（手动修改需要显式调用ResEvent函数）；第三个参数设置事件对象的初态，true为激发态，false为非激发态。第四个参数为事件的名字。<br>事件对象自从创建后即在程序的控制下处于激发态和非激发态之间翻转。<br>八、&nbsp;&nbsp;&nbsp;&nbsp;线程代码的调试<br>九、&nbsp;&nbsp;&nbsp;&nbsp;什么是线程安全的代码<br>十、&nbsp;&nbsp;&nbsp;&nbsp;多线程程序设计的几个原则</font></span><img src ="http://www.cppblog.com/richardhe/aggbug/64465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-10-20 10:09 <a href="http://www.cppblog.com/richardhe/articles/64465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网易笔试</title><link>http://www.cppblog.com/richardhe/articles/63305.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 06 Oct 2008 03:41:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/63305.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/63305.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/63305.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/63305.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/63305.html</trackback:ping><description><![CDATA[第一部分，计算机基础：<br>
（1）模块划分的原则：选择题，高/低内聚 高/低耦合<br>
（2）下面排序算法最坏情况下时间复杂度不是n(n-1)/2的是：堆排序，冒泡，直接插入排序，快速排序<br>
（3）Hash技术中的open addressing 和 chianning。<br>
（4）设计一个新的链表结构以改进定位第n个结点的时间复杂度并给出复杂度。<br>
（5）什么是NP问题，举例常见的NP问题。你如何判定一个问题是否是NP问题（ICPCer多多少少都想得到点吧，，嘿嘿）。<br>
（6）给了一棵树和一个简单的遍历函数（这种遍历方式在数据结构书中没出现过），输出遍历序列。（很简单。。是个选择题）<br>
忘了1题了好像。<br>
<br>
第二部分，C/C++：<br>
（1）输出std::list&lt;int&gt; &amp;l中的元素，每个一行。<br>
（2）关于重载，虚函数，覆盖，类静态成员，sizeof(class) 等。（我都不会，平时没用过）<br>
（3）有什么办法可以让new操作符只调用构造函数而不分配空间。这样做有什么作用。（完全不会做）<br>
（4）C++ Traits 是什么？（我不知道，拼错没？）<br>
<br>
第三部分，JAVA：<br>
（1）多线程的实现的方式以及什么情况下那种情况下那种比较合适。ThreadLocal相关。<br>
（2）给了一个JAVA程序让你找错。<br>
（3）JAVA Class Loader的层次以及各个Loader 的作用。<br>
（4）虚构造函数的覆盖等。<br>
（5）interface 和 抽象类，什么情况下用哪个。<br>
（6）Map的几种实现。<br>
（7）<br>
public static void main(String argvs[]){<br>
&nbsp;&nbsp;&nbsp;         Integer var1 = new Integer(1);<br>
Integer var2 = var1;<br>
&nbsp;&nbsp;&nbsp;         doSomeThing(var2);<br>
&nbsp;&nbsp;&nbsp;         System.out.println(var1+var1==var2);<br>
}<br>
<br>
doSomeThing(Integer var){<br>
&nbsp;&nbsp;&nbsp;         var = new Integer(1);<br>
}<br>
求此程序的输出。<br>
<br>
第四部分，数据库：<br>
（1）哈希索引和树索引的区别。<br>
（2）基本的跨表SQL查询。<br>
（3）连接池技术，如何提高一个中心数据库服务器的（连接池）性能。<br>
我没做这部分，记得的不多，好像一共四题吧。<br>
<br>
第五部分，linux 开发：<br>
（1）基本的文件查找替换命令。用一个命令建立 aa bb cc 三个目录。<br>
（2）pthread。<br>
（3）gdb<br>
（4）什么位置的bash..和 bash_profile 的区别。<br>
这些东西我都是久仰他们的大名，但从来就没用过。（建议各位尽早开始使用linux）<br>
<br>
第六部分，windows程序开发：<br>
（1）碰撞检测，怎么判断点在多变形内部，两个多变形的重合面积等。<br>
（2）一个程序非MFC，CRT进程什么的。<br>
<br>
第七部分，Flash和JAVAscript：<br>
（1）下面错误的是<br>
object var={ };<br>
object var=[ ];<br>
object var=( );<br>
object var=/ /;<br>
（2）flash如何与javascript交互。<br>
<br>
第八部分，web开发：<br>
（1）给出了一个html代码，求其中一张图片距离什么div的距离，按照css计算。<br>
（2）HTTP头相关，keep-alive的问题。<br>
（3）说你常用的web服务器的什么的。<br>
<br>
第九部分，测试：<br>
（1）说说你知道的测试过程，工具，流程等。<br>
（2）如果你某天早上上班，发现不能上网了，你怎么办。<br>
（3）描述了一个多人聊天系统，让你设计测试用例。<br>
（4）和（3）差不多的一题吧。<img src ="http://www.cppblog.com/richardhe/aggbug/63305.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-10-06 11:41 <a href="http://www.cppblog.com/richardhe/articles/63305.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>buffer和cache的区别</title><link>http://www.cppblog.com/richardhe/articles/62736.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Thu, 25 Sep 2008 01:45:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/62736.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/62736.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/62736.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/62736.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/62736.html</trackback:ping><description><![CDATA[A buffer is something that has
yet to be "written" to disk. A cache is something that has been "read"
from the disk and stored for later use.&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 缓存（cached）是把读取过的数据保存起来，重新读取时若命中（找到需要的数据）就不要去读硬盘了，若没有命中就读硬盘。其中的数据会根据读取频率进行组织，把最频繁读取的内容放在最容易找到的位置，把不再读的内容不断往后排，直至从中删除。 <br>缓冲（buffers）是根据磁盘的读写设计的，把分散的写操作集中进行，减少磁盘碎片和硬盘的反复寻道，从而提高系统性能。<br>两者都是RAM中的数据。简单来说，buffer是即将要被写入磁盘的，而cache是被从磁盘中读出来的。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer是由各种进程分配的，被用在如输入队列等方面，一个简单的例子如某个进程要求有多个字段读入，在所有字段被读入完整之前，进程把先前读入的字段放在buffer中保存。 <br>cache经常被用在磁盘的I/O请求上，如果有多个进程都要访问某个文件，于是该文件便被做成cache以方便下次被访问，这样可提供系统性能。
<p style="font-size: 12pt;" align="left">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cache 和 buffer的区别:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cache：
高速缓存,是位于CPU与主内存间的一种容量较小但速度很高的存储器。由于CPU的速度远高于主内存，CPU直接从内存中存取数据要等待一定时间周期，
Cache中保存着CPU刚用过或循环使用的一部分数据，当CPU再次使用该部分数据时可从Cache中直接调用,这样就减少了CPU的等待时间,提高了
系统的效率。Cache又分为一级Cache(L1 Cache)和二级Cache(L2 Cache)，L1 Cache集成在CPU内部，L2
Cache早期一般是焊在主板上,现在也都集成在CPU内部，常见的容量有256KB或512KB L2 Cache。<br>&nbsp;　Buffer：缓冲区，一个用于存储速度不同步的设备或优先级不同的设备之间传输数据的区域。通过缓冲区，可以使进程之间的相互等待变少，从而使从速度慢的设备读入数据时，速度快的设备的操作进程不发生间断。</p><img src ="http://www.cppblog.com/richardhe/aggbug/62736.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-09-25 09:45 <a href="http://www.cppblog.com/richardhe/articles/62736.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++位运算</title><link>http://www.cppblog.com/richardhe/articles/62198.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Thu, 18 Sep 2008 09:39:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/62198.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/62198.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/62198.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/62198.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/62198.html</trackback:ping><description><![CDATA[<font face="Verdana">前言&nbsp;&nbsp; <br>
&nbsp; 看到有些人对位运算还存在问题，于是决定写这篇文章作个简要说明。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 什么是位(bit)？&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;很简单，位(bit)就是单个的0或1，位是我们在计算机上所作一切的基础。计算机上的所有数据都是用位来存储的。一个字节(BYTE)由八个位组成，一个字(WORD)是二个字节或十六位，一个双字(DWORD)是二个字(WORDS)或三十二位。如下所示：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 1&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp;
0&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 0&nbsp;&nbsp; 1&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; <br>
&nbsp; |&nbsp;&nbsp; +-&nbsp;&nbsp; bit&nbsp;&nbsp; 31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit&nbsp;&nbsp; 0&nbsp;&nbsp; -+&nbsp;&nbsp; |&nbsp;&nbsp; <br>
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; <br>
&nbsp; +--&nbsp;&nbsp; BYTE&nbsp;&nbsp; 3&nbsp;&nbsp; ----&nbsp;&nbsp; -+----&nbsp;&nbsp; BYTE&nbsp;&nbsp; 2&nbsp;&nbsp; ---+----&nbsp;&nbsp; BYTE&nbsp;&nbsp; 1&nbsp;&nbsp; ---+---&nbsp;&nbsp; BYTE&nbsp;&nbsp; 0&nbsp;&nbsp; -----+&nbsp;&nbsp; <br>
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; <br>
&nbsp; +------------&nbsp;&nbsp; WORD&nbsp;&nbsp; 1&nbsp;&nbsp; ------------+-----------&nbsp;&nbsp; WORD&nbsp;&nbsp; 0&nbsp;&nbsp; -------------+&nbsp;&nbsp; <br>
&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp; <br>
&nbsp; +-----------------------------&nbsp;&nbsp; DWORD&nbsp;&nbsp; -----------------------------+&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;使用位运算的好处是可以将BYTE,&nbsp;&nbsp; WORD&nbsp;&nbsp; 或&nbsp;&nbsp; DWORD&nbsp;&nbsp; 作为小数组或结构使用。通过位运算可以检查位的值或赋值，也可以对整组的位进行运算。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 16进制数及其与位的关系&nbsp;&nbsp; <br>
&nbsp; 用0或1表示的数值就是二进制数，很难理解。因此用到16进制数。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 16进制数用4个位表示0&nbsp;&nbsp; -&nbsp;&nbsp; 15的值，4个位组成一个16进制数。也把4位成为半字节(nibble)。一个BYTE有二个nibble，因此可以用二个16进制数表示一个BYTE。如下所示：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; NIBBLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HEX&nbsp;&nbsp; VALUE&nbsp;&nbsp; <br>
&nbsp; ======&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =========&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0001&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 0111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1001&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; 1111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 如果用一个字节存放字母"r"(ASCII码114)，结果是：&nbsp;&nbsp; <br>
&nbsp; 0111&nbsp;&nbsp; 0010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二进制&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16进制&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可以表达为：'0x72'&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 有6种位运算：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 与运算&nbsp;&nbsp; <br>
&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; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 非运算(求补)&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 右移运算&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 左移运算&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 与运算(&amp;)&nbsp;&nbsp; <br>
&nbsp; 双目运算。二个位都置位(等于1)时，结果等于1，其它的结果都等于0。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 与运算的一个用途是检查指定位是否置位(等于1)。例如一个BYTE里有标识位，要检查第4位是否置位，代码如下：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; 50;&nbsp;&nbsp; <br>
&nbsp; if&nbsp;&nbsp; (&nbsp;&nbsp; b&nbsp;&nbsp; &amp;&nbsp;&nbsp; 0x10&nbsp;&nbsp; )&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "Bit&nbsp;&nbsp; four&nbsp;&nbsp; is&nbsp;&nbsp; set"&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; else&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "Bit&nbsp;&nbsp; four&nbsp;&nbsp; is&nbsp;&nbsp; clear"&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 上述代码可表示为：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp; 00010000&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; &amp;&nbsp;&nbsp; 0x10&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; ----------------------------&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00010000&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; result&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可以看到第4位是置位了。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 或运算(&nbsp;&nbsp; |&nbsp;&nbsp; )&nbsp;&nbsp; <br>
&nbsp; 双目运算。二个位只要有一个位置位，结果就等于1。二个位都为0时，结果为0。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 与运算也可以用来检查置位。例如要检查某个值的第3位是否置位：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; 50;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; c&nbsp;&nbsp; =&nbsp;&nbsp; b&nbsp;&nbsp; |&nbsp;&nbsp; 0x04;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "c&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; c&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可表达为：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 00000100&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; |&nbsp;&nbsp; 0x04&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ----------&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110110&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; result&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 异或运算(^)&nbsp;&nbsp; <br>
&nbsp; 双目运算。二个位不相等时，结果为1，否则为0。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 异或运算可用于位值翻转。例如将第3位与第4位的值翻转：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; 50;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "b&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; b&nbsp;&nbsp; ^&nbsp;&nbsp; 0x18;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "b&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; b&nbsp;&nbsp; ^&nbsp;&nbsp; 0x18;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "b&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可表达为：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^&nbsp;&nbsp; 00011000&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; ^0x18&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ----------&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00101010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; result&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00101010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^&nbsp;&nbsp; 00011000&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; ^0x18&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ----------&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; result&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 非运算(~)&nbsp;&nbsp; <br>
&nbsp; 单目运算。位值取反，置0为1，或置1为0。非运算的用途是将指定位清0，其余位置1。非运算与数值大小无关。例如将第1位和第2位清0，其余位置1：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; ~0x03;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "b&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; WORD&nbsp;&nbsp; w&nbsp;&nbsp; =&nbsp;&nbsp; ~0x03;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "w&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; w&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可表达为：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000011&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; 0x03&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11111100&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; ~0x03&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0000000000000011&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; 0x03&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1111111111111100&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; ~0x03&nbsp;&nbsp;&nbsp;&nbsp; w&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 非运算和与运算结合，可以确保将指定为清0。如将第4位清0：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; 50;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "b&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; c&nbsp;&nbsp; =&nbsp;&nbsp; b&nbsp;&nbsp; &amp;&nbsp;&nbsp; ~0x10;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "c&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; c&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可表达为：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&nbsp;&nbsp; 11101111&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; ~0x10&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ----------&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00100010&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; result&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 移位运算(&gt;&gt;&nbsp;&nbsp; 与&nbsp;&nbsp; &lt;&lt;)&nbsp;&nbsp; <br>
&nbsp; 将位值向一个方向移动指定的位数。右移&nbsp;&nbsp; &gt;&gt;&nbsp;&nbsp; 算子从高位向低位移动，左移&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; 算子从低位向高位移动。往往用位移来对齐位的排列(如MAKEWPARAM,&nbsp;&nbsp; HIWORD,&nbsp;&nbsp; LOWORD&nbsp;&nbsp; 宏的功能)。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; b&nbsp;&nbsp; =&nbsp;&nbsp; 12;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "b&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; BYTE&nbsp;&nbsp; c&nbsp;&nbsp; =&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; 2;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "c&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; c&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp; c&nbsp;&nbsp; =&nbsp;&nbsp; b&nbsp;&nbsp; &gt;&gt;&nbsp;&nbsp; 2;&nbsp;&nbsp; <br>
&nbsp; cout&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; "c&nbsp;&nbsp; =&nbsp;&nbsp; "&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; c&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; endl;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 可表达为：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00001100&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00110000&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; &lt;&lt;&nbsp;&nbsp; 2&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000011&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp; b&nbsp;&nbsp; &gt;&gt;&nbsp;&nbsp; 2&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 译注：以上示例都对，但举例用法未必恰当。请阅文末链接的文章，解释得较为清楚。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 位域(Bit&nbsp;&nbsp; Field)&nbsp;&nbsp; <br>
&nbsp;位操作中的一件有意义的事是位域。利用位域可以用BYTE,&nbsp;&nbsp; WORD或DWORD来创建最小化的数据结构。例如要保存日期数据，并尽可能减少内存占用，就可以声明这样的结构：&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; struct&nbsp;&nbsp; date_struct&nbsp;&nbsp; {&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BYTE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp;&nbsp; 5,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; 1&nbsp;&nbsp; to&nbsp;&nbsp; 31&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; month&nbsp;&nbsp; :&nbsp;&nbsp; 4,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; 1&nbsp;&nbsp; to&nbsp;&nbsp; 12&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; year&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp;&nbsp; 14;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; 0&nbsp;&nbsp; to&nbsp;&nbsp; 9999&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }date;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
&nbsp; 在结构中，日期数据占用最低5位，月份占用4位，年占用14位。这样整个日期数据只需占用23位，即3个字节。忽略第24位。如果用整数来表达各个域，整个结构要占用12个字节。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; |&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; |&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; |&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; |&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; year&nbsp;&nbsp; --------------+&nbsp;&nbsp; month+--&nbsp;&nbsp; day&nbsp;&nbsp; --+&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 现在分别看看在这个结构声明中发生了什么&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;
首先看一下位域结构使用的数据类型。这里用的是BYTE。1个BYTE有8个位，编译器将分配1个BYTE的内存。如果结构内的数据超过8位，编译器就再
分配1个BYTE，直到满足数据要求。如果用WORD或DWORD作结构的数据类型，编译器就分配一个完整的32位内存给结构。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 其次看一下域声明。变量(day,&nbsp;&nbsp; month,&nbsp;&nbsp; year)名跟随一个冒号，冒号后是变量占用的位数。位域之间用逗号分隔，用分号结束。&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 使用了位域结构，就可以方便地象处理普通结构数据那样处理成员数据。尽管我们无法得到位域的地址，却可以使用结构地址。例如：&nbsp;&nbsp; <br>
&nbsp; date.day&nbsp;&nbsp; =&nbsp;&nbsp; 12;&nbsp;&nbsp; <br>
&nbsp; dateptr&nbsp;&nbsp; =&nbsp;&nbsp; &amp;date;&nbsp;&nbsp; <br>
&nbsp; dateptr-&gt;year&nbsp;&nbsp; =&nbsp;&nbsp; 1852;</font><img src ="http://www.cppblog.com/richardhe/aggbug/62198.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-09-18 17:39 <a href="http://www.cppblog.com/richardhe/articles/62198.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论百万人同时在线棋牌类网络游戏服务器设计</title><link>http://www.cppblog.com/richardhe/articles/61615.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Thu, 11 Sep 2008 11:10:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/61615.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/61615.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/61615.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/61615.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/61615.html</trackback:ping><description><![CDATA[<span  style="font-family: Verdana; font-size: 13px; "><div class="post" style="line-height: 150%; font-size: 13px; ">本文主要探讨如何设计一款百万人同时在线的棋牌类网络游戏服务器系统，如果您发现本文的设计上存在漏洞或不对的地方欢迎提出共同探讨。<br><h1 style="margin-top: 17pt; margin-right: 0cm; margin-bottom: 16.5pt; margin-left: 0cm; "><font size="6"><font color="#000000"><span lang="EN-US"><font face="Calibri">1.</font></span><span style="font-family: 宋体; ">总体架构图<br><br></span></font></font></h1><img height="507" alt="" src="http://www.cppblog.com/images/cppblog_com/beifangying/1.JPG" width="487" border="0"><br>&#160;<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span>注</span><span>: CMS(control and manage server) :&#160;</span><span>控制管理服务器</span><span>. GateServer :&#160;</span><span>门服务器<br></span></p><h1 style="margin-top: 17pt; margin-right: 0cm; margin-bottom: 16.5pt; margin-left: 0cm; "><font size="6"><font color="#000000"><span lang="EN-US"><font face="Calibri">2.</font></span><span style="font-family: 宋体; ">相关服务器介绍<br></span></font></font></h1><span style="font-size: 10.5pt; font-family: 宋体; ">注：除</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Calibri, sans-serif; ">CMS</span><span style="font-size: 10.5pt; font-family: 宋体; ">外每台服务器都由两个程序实例构成，服务器管理客户端和服务器程序。<br><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.1&#160;</font></span><span style="font-family: 宋体; ">控制管理服务器（</span><span lang="EN-US"><font face="Cambria">CMS</font></span><span style="font-family: 宋体; ">）</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">的作用是管理和配置所有的服务器。主备账号服务器、主备</span><span lang="EN-US"><font face="Calibri">GATE</font></span><span style="font-family: 宋体; ">服务器的切换也是由</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">决定的，服务器管理员通过</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">来管理所有的服务器。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.2&#160;</font></span><span style="font-family: 宋体; ">账号服务器</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">账号服务器的主要用于处理用户注册和登录游戏系统。用户是否重复登录游戏也将在账号服务器上处理。账号服务器由主备构成，任何时候只有主账号服务器负责和客户端及</span><span lang="EN-US"><font face="Calibri">GATE</font></span><span style="font-family: 宋体; ">服务器交互；备用账号服务器主要处理</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">发来的控制消息及主账号服务器发来的实时数据备份消息，及其他服务器发来的心跳消息。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.3&#160;</font></span><span style="font-family: 宋体; ">门服务器（</span><span lang="EN-US"><font face="Cambria">GateServer</font></span><span style="font-family: 宋体; ">）</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">门服务器的作用是负责各服务器之间的消息转发，确定用户的资料在哪台数据库服务器上。门服务器也分为主用和备用两台，除</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">外的其他服务器只和主用的门服务器交互。当</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">发现主用门服务器故障时将通知其他服务器进行主备切换。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.4&#160;</font></span><span style="font-family: 宋体; ">大厅服务器</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">当用户登录成功后将和大厅服务器保持长连接以实时获取游戏系统的信息。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.5&#160;</font></span><span style="font-family: 宋体; ">游戏服务器</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">当用户在大厅中点击进入某个游戏时，用户将登录相应的游戏服务器进行游戏。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.6&#160;</font></span><span style="font-family: 宋体; ">数据库服务器</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">数据库服务器主要保存用户的资料和用户的游戏数据。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">2.7&#160;</font></span><span style="font-family: 宋体; ">消息服务器</span></font></font></h2><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">主要负责用户聊天消息的处理。</span></p><h1 style="margin-top: 17pt; margin-right: 0cm; margin-bottom: 16.5pt; margin-left: 0cm; "><font size="6"><font color="#000000"><span lang="EN-US"><font face="Calibri">3.</font></span><span style="font-family: 宋体; ">流程介绍<br></span></font></font></h1></span><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">3.1&#160;</font></span><span style="font-family: 宋体; ">系统启动流程</span></font></font></h2><img height="88" alt="" src="http://www.cppblog.com/images/cppblog_com/beifangying/2.JPG" width="563" border="0"><br><p class="MsoNormal" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; "><span style="font-family: 宋体; ">如图所示，系统最先启动的是</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">，当</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">启动之后将从本地数据库读取相关服务器配置信息，只有本地配置中存在的服务器才可以连接本系统正常工作；这样就可以保证只有合法的服务器才能连接到本系统以防止非法服务器的接入。当门服务器启动并连接</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">后</span><span lang="EN-US"><font face="Calibri">CMS</font></span><span style="font-family: 宋体; ">将选择其中一个作为主用门服务器。接下来依次启动的是数据库服务器，大厅服务器，游戏服务器，消息服务器。最后启动的是账号服务器。</span></p><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">3.2&#160;</font></span><span style="font-family: 宋体; ">添加一台新服务器流程</span></font></font></h2><img height="549" alt="" src="http://www.cppblog.com/images/cppblog_com/beifangying/3.JPG" width="498" border="0"><br><br><h2 style="margin-right: 0cm; margin-bottom: 13pt; margin-left: 0cm; margin-top: 10px; font-size: 13px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(102, 102, 102); "><font size="5"><font color="#000000"><span lang="EN-US"><font face="Cambria">3.3&#160;</font></span><span style="font-family: 宋体; ">用户登录流程</span></font></font></h2><img height="700" alt="" src="http://www.cppblog.com/images/cppblog_com/beifangying/4.JPG" width="533" border="0"><br><br><br><p class="postfoot" style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 11px; ">posted on 2008-09-11 17:15&#160;<a href="http://www.cppblog.com/beifangying/" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">司强</a>&#160;阅读(78)&#160;<a href="http://www.cppblog.com/beifangying/archive/2008/09/11/61600.html#Post" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">评论(2)</a>&#160;&#160;<a href="http://www.cppblog.com/beifangying/admin/EditPosts.aspx?postid=61600" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">编辑</a>&#160;<a href="http://www.cppblog.com/beifangying/AddToFavorite.aspx?id=61600" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">收藏</a>&#160;<a href="http://www.cppblog.com/beifangying/services/trackbacks/61600.aspx" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">引用</a></p></div><img src="http://www.cppblog.com/beifangying/aggbug/61600.html?webview=1" width="1" height="1"><div id="AjaxHolder_UpdatePanel1"><a name="pagedcomment" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a><a name="评论" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a><div id="comments"><a name="评论" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "><h3 style="font-size: 15px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(170, 170, 170); ">评论</h3></a><h4 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-size: 13px; "><a name="评论" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a><a title="permalink: re: 论百万人同时在线棋牌类网络游戏服务器设计" href="http://www.cppblog.com/beifangying/archive/2008/09/11/61600.html#61608" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">#</a>&#160;<a name="61608" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a>re: 论百万人同时在线棋牌类网络游戏服务器设计&#160;<span style="color: rgb(153, 153, 153); ">2008-09-11 18:14&#160;</span><a id="AjaxHolder_Comments_CommentList_ctl00_NameLink" href="http://www.cppblog.com/aurain/" target="_blank" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">水</a></h4><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; ">帐号服务器的用户数据如何与数据库服务器同步？定期吗？当用户登录游戏服务器后，应该同大厅服务器断开连接吧？所有用户均向一台帐号服务器登录吗？&#160;&#160;<a onclick="return SetReplyAuhor(&quot;水&quot;)" href="http://www.cppblog.com/beifangying/archive/2008/09/11/61600.html#post" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">回复</a>&#160;&#160;<a title="查看该作者发表过的评论" href="http://www.cppblog.com/comment?author=%e6%b0%b4" target="_blank" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">更多评论</a>&#160;<a id="AjaxHolder_Comments_CommentList_ctl00_DeleteLink" href="javascript:__doPostBack('AjaxHolder$Comments$CommentList$ctl00$DeleteLink','')" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a>&#160;&#160;<a id="AjaxHolder_Comments_CommentList_ctl00_EditLink" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a></p><h4 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-size: 13px; "><a title="permalink: re: 论百万人同时在线棋牌类网络游戏服务器设计" href="http://www.cppblog.com/beifangying/archive/2008/09/11/61600.html#61611" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">#</a>&#160;<a name="61611" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a>re: 论百万人同时在线棋牌类网络游戏服务器设计<a name="Post" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a>&#160;<span style="color: rgb(153, 153, 153); ">2008-09-11 18:28&#160;</span><a id="AjaxHolder_Comments_CommentList_ctl01_NameLink" href="http://www.cppblog.com/hideto/" target="_blank" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">Hideto</a></h4><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 150%; font-size: 13px; ">用户流程简化来看：<br>前端LoadBalance -> 用户认证服务器组 -> LoadBalance -> 大厅服务器组 -> LoadBalance -> 游戏服务器组<br><br>1，访问前端LoadBalance，负载均衡，建立到一个用户认证服务器的新连接<br>2，访问用户认证服务器，用户输入登录id和密码进行认证，通过后断开连接，负载均衡，建立到一个大厅服务器的新连接<br>3，访问大厅服务器，用户选择一款游戏，断开连接，LoadBalance，建立到一个游戏服务器的新连接<br>4，开始游戏&#160;&#160;<a onclick="return SetReplyAuhor(&quot;Hideto&quot;)" href="http://www.cppblog.com/beifangying/archive/2008/09/11/61600.html#post" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">回复</a>&#160;&#160;<a title="查看该作者发表过的评论" href="http://www.cppblog.com/comment?author=Hideto" target="_blank" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; ">更多评论</a>&#160;<a id="AjaxHolder_Comments_CommentList_ctl01_DeleteLink" href="javascript:__doPostBack('AjaxHolder$Comments$CommentList$ctl01$DeleteLink','')" style="text-decoration: none; color: rgb(102, 102, 102); background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a>&#160;&#160;<a id="AjaxHolder_Comments_CommentList_ctl01_EditLink" style="color: rgb(102, 102, 102); text-decoration: none; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; "></a></p><div><span  style="line-height: 19px;"><br></span></div></div></div></span><img src ="http://www.cppblog.com/richardhe/aggbug/61615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-09-11 19:10 <a href="http://www.cppblog.com/richardhe/articles/61615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ansi、Unicode、UTF8字符串之间的转换和写入文本文件</title><link>http://www.cppblog.com/richardhe/articles/60564.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 01 Sep 2008 01:37:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/60564.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/60564.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/60564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/60564.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/60564.html</trackback:ping><description><![CDATA[<p>转载请注明出处<a  href="http://www.cppblog.com/greatws/archive/2008/08/31/60546.html">http://www.cppblog.com/greatws/archive/2008/08/31/60546.html</a><br><br>最近有人问我关于这个的问题，就此写一篇blog<br><br>Ansi字符串我们最熟悉，英文占一个字节，汉字2个字节，以一个\0结尾，常用于txt文本文件<br>Unicode
字符串，每个字符(汉字、英文字母)都占2个字节，以2个连续的\0结尾，NT操作系统内核用的是这种字符串，常被定义为typedef
unsigned short wchar_t;所以我们有时常会见到什么char*无法转换为unsigned
short*之类的错误，其实就是unicode<br>UTF8是Unicode一种压缩形式，英文A在unicode中表示为0x0041，老外觉得
这种存储方式太浪费，因为浪费了50%的空间，于是就把英文压缩成1个字节，成了utf8编码，但是汉字在utf8中占3个字节，显然用做中文不如
ansi合算，这就是中国的网页用作ansi编码而老外的网页常用utf8的原因。<br>UTF8在还游戏里运用的很广泛，比如WOW的lua脚本等<br><br>下面来说一下转换，主要用代码来说明吧<br>写文件我用了CFile类，其实用FILE*之类的也是一样，写文件和字符串什么类别没有关系，硬件只关心数据和长度<br><br>Ansi转Unicode<br>介绍2种方法<br></p>
<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;CConvertDlg::OnBnClickedButtonAnsiToUnicode()<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_51_1122_Open_Image" onclick="this.style.display='none'; codehighlighter1_51_1122_open_text.style.display="'none';" codehighlighter1_51_1122_closed_image.style.display="'inline';" codehighlighter1_51_1122_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_51_1122_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_51_1122_closed_text.style.display="'none';" codehighlighter1_51_1122_open_image.style.display="'inline';" codehighlighter1_51_1122_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_51_1122_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_51_1122_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;ansi&nbsp;to&nbsp;unicode</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;szAnsi&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">abcd1234你我他</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">预转换，得到所需空间的大小</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;wcsLen&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::MultiByteToWideChar(CP_ACP,&nbsp;NULL,&nbsp;szAnsi,&nbsp;strlen(szAnsi),&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">分配空间要给'\0'留个空间，MultiByteToWideChar不会给'\0'空间</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;wszString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;wchar_t[wcsLen&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">];<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">转换</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::MultiByteToWideChar(CP_ACP,&nbsp;NULL,&nbsp;szAnsi,&nbsp;strlen(szAnsi),&nbsp;wszString,&nbsp;wcsLen);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">最后加上'\0'</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;wszString[wcsLen]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">'</span><span style="color: #000000;">\0</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">unicode版的MessageBox&nbsp;API</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::MessageBoxW(GetSafeHwnd(),&nbsp;wszString,&nbsp;wszString,&nbsp;MB_OK);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">接下来写入文本<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写文本文件，头2个字节0xfeff，低位0xff写在前</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CFile&nbsp;cFile;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Open(_T(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.txt</span><span style="color: #000000;">")</span><span style="color: #000000;">,&nbsp;CFile::modeWrite&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;CFile::modeCreate);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">文件开头</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.SeekToBegin();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">\xff\xfe</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写入内容</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Write(wszString,&nbsp;wcsLen&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(wchar_t));<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Flush();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Close();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;delete[]&nbsp;wszString;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;wszString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">NULL;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">方法2<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">设置当前地域信息，不设置的话，使用这种方法，中文不会正确显示<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">需要#include&lt;locale.h&gt;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;setlocale(LC_CTYPE,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">chs</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;wchar_t&nbsp;wcsStr[</span><span style="color: #000000;">100</span><span style="color: #000000;">];<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">注意下面是大写S，在unicode中，代表后面是ansi字符串<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">swprintf是sprintf的unicode版本<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">格式的前面要加大写L，代表是unicode</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;swprintf(wcsStr,&nbsp;L</span><span style="color: #000000;">"</span><span style="color: #000000;">%S</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;szAnsi);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;::MessageBoxW(GetSafeHwnd(),&nbsp;wcsStr,&nbsp;wcsStr,&nbsp;MB_OK);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span></div>
<br><br>Unicode转Ansi<br>也是2种方法<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;CConvertDlg::OnBnClickedButtonUnicodeToAnsi()<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_51_1013_Open_Image" onclick="this.style.display='none'; codehighlighter1_51_1013_open_text.style.display="'none';" codehighlighter1_51_1013_closed_image.style.display="'inline';" codehighlighter1_51_1013_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_51_1013_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_51_1013_closed_text.style.display="'none';" codehighlighter1_51_1013_open_image.style.display="'inline';" codehighlighter1_51_1013_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_51_1013_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_51_1013_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;unicode&nbsp;to&nbsp;ansi</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;wszString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;L</span><span style="color: #000000;">"</span><span style="color: #000000;">abcd1234你我他</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">预转换，得到所需空间的大小，这次用的函数和上面名字相反</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;ansiLen&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::WideCharToMultiByte(CP_ACP,&nbsp;NULL,&nbsp;wszString,&nbsp;wcslen(wszString),&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;NULL,&nbsp;NULL);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">同上，分配空间要给'\0'留个空间</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;szAnsi&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">[ansiLen&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">];<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">转换<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">unicode版对应的strlen是wcslen</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::WideCharToMultiByte(CP_ACP,&nbsp;NULL,&nbsp;wszString,&nbsp;wcslen(wszString),&nbsp;szAnsi,&nbsp;ansiLen,&nbsp;NULL,&nbsp;NULL);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">最后加上'\0'</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;szAnsi[ansiLen]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">'</span><span style="color: #000000;">\0</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">Ansi版的MessageBox&nbsp;API</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::MessageBoxA(GetSafeHwnd(),&nbsp;szAnsi,&nbsp;szAnsi,&nbsp;MB_OK);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">接下来写入文本<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写文本文件，ANSI文件没有BOM</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CFile&nbsp;cFile;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Open(_T(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.txt</span><span style="color: #000000;">")</span><span style="color: #000000;">,&nbsp;CFile::modeWrite&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;CFile::modeCreate);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">文件开头</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.SeekToBegin();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写入内容</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Write(szAnsi,&nbsp;ansiLen&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(</span><span style="color: #0000ff;">char</span><span style="color: #000000;">));<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Flush();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Close();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;delete[]&nbsp;szAnsi;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;szAnsi&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">NULL;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">方法2<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">和上面一样有另一种方法</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;setlocale(LC_CTYPE,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">chs</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;szStr[</span><span style="color: #000000;">100</span><span style="color: #000000;">];<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">注意下面是大写，在ansi中，代表后面是unicode字符串<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">sprintf</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;sprintf(szStr,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">%S</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;wszString);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;::MessageBoxA(GetSafeHwnd(),&nbsp;szStr,&nbsp;szStr,&nbsp;MB_OK);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span></div>
<br><br>Unicode转UTF8<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;CConvertDlg::OnBnClickedButtonUnicodeToU8()<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_49_850_Open_Image" onclick="this.style.display='none'; codehighlighter1_49_850_open_text.style.display="'none';" codehighlighter1_49_850_closed_image.style.display="'inline';" codehighlighter1_49_850_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_49_850_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_49_850_closed_text.style.display="'none';" codehighlighter1_49_850_open_image.style.display="'inline';" codehighlighter1_49_850_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_49_850_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_49_850_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;unicode&nbsp;to&nbsp;UTF8</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;wszString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;L</span><span style="color: #000000;">"</span><span style="color: #000000;">abcd1234你我他</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">预转换，得到所需空间的大小，这次用的函数和上面名字相反</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;u8Len&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::WideCharToMultiByte(CP_UTF8,&nbsp;NULL,&nbsp;wszString,&nbsp;wcslen(wszString),&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;NULL,&nbsp;NULL);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">同上，分配空间要给'\0'留个空间<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">UTF8虽然是Unicode的压缩形式，但也是多字节字符串，所以可以以char的形式保存</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;szU8&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">[u8Len&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">];<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">转换<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">unicode版对应的strlen是wcslen</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::WideCharToMultiByte(CP_UTF8,&nbsp;NULL,&nbsp;wszString,&nbsp;wcslen(wszString),&nbsp;szU8,&nbsp;u8Len,&nbsp;NULL,&nbsp;NULL);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">最后加上'\0'</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;szU8[u8Len]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">'</span><span style="color: #000000;">\0</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">MessageBox不支持UTF8,所以只能写文件<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">接下来写入文本<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写文本文件，UTF8的BOM是0xbfbbef</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CFile&nbsp;cFile;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Open(_T(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.txt</span><span style="color: #000000;">"</span><span style="color: #000000;">),&nbsp;CFile::modeWrite&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;CFile::modeCreate);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">文件开头</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.SeekToBegin();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写BOM，同样低位写在前</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">\xef\xbb\xbf</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写入内容</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Write(szU8,&nbsp;u8Len&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(</span><span style="color: #0000ff;">char</span><span style="color: #000000;">));<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Flush();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;cFile.Close();<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;delete[]&nbsp;szU8;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;szU8&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">NULL;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span></div>
<br>UTF8转UNICODE<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;CConvertDlg::OnBnClickedButtonU8ToUnicode()<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_49_613_Open_Image" onclick="this.style.display='none'; codehighlighter1_49_613_open_text.style.display="'none';" codehighlighter1_49_613_closed_image.style.display="'inline';" codehighlighter1_49_613_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_49_613_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_49_613_closed_text.style.display="'none';" codehighlighter1_49_613_open_image.style.display="'inline';" codehighlighter1_49_613_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_49_613_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_49_613_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">UTF8&nbsp;to&nbsp;Unicode<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">由于中文直接复制过来会成乱码，编译器有时会报错，故采用16进制形式</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;szU8&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">abcd1234\xe4\xbd\xa0\xe6\x88\x91\xe4\xbb\x96\x00</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">预转换，得到所需空间的大小</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;wcsLen&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::MultiByteToWideChar(CP_UTF8,&nbsp;NULL,&nbsp;szU8,&nbsp;strlen(szU8),&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">分配空间要给'\0'留个空间，MultiByteToWideChar不会给'\0'空间</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;wszString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;wchar_t[wcsLen&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">];<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">转换</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::MultiByteToWideChar(CP_UTF8,&nbsp;NULL,&nbsp;szU8,&nbsp;strlen(szU8),&nbsp;wszString,&nbsp;wcsLen);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">最后加上'\0'</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;wszString[wcsLen]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">'</span><span style="color: #000000;">\0</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">unicode版的MessageBox&nbsp;API</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;::MessageBoxW(GetSafeHwnd(),&nbsp;wszString,&nbsp;wszString,&nbsp;MB_OK);<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">写文本同ansi&nbsp;to&nbsp;unicode</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"></span><span style="color: #000000;">}</span></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div>
<br><br>Ansi转换utf8和utf8转换Ansi就是上面2个的结合，把unicode作为中间量，进行2次转换即可<br><br>by greatws<img src ="http://www.cppblog.com/richardhe/aggbug/60564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-09-01 09:37 <a href="http://www.cppblog.com/richardhe/articles/60564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)vc中socket编程步骤 </title><link>http://www.cppblog.com/richardhe/articles/60456.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Sat, 30 Aug 2008 12:16:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/60456.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/60456.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/60456.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/60456.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/60456.html</trackback:ping><description><![CDATA[sockets（套接字）编程有三种，流式套接字（SOCK_STREAM），数据报套接字（SOCK_DGRAM），原始套接字（SOCK_RAW）；
基于TCP的socket编程是采用的流式套接字。在这个程序中，将两个工程添加到一个工作区。要链接一个ws2_32.lib的库文件。<br><br>服务器端编程的步骤：<br><br>1：加载套接字库，创建套接字(WSAStartup()/socket())；<br><br>2：绑定套接字到一个IP地址和一个端口上(bind())；<br><br>3：将套接字设置为监听模式等待连接请求(listen())；<br><br>4：请求到来后，接受连接请求，返回一个新的对应于此次连接的套接字(accept())；<br><br>5：用返回的套接字和客户端进行通信(send()/recv())；<br><br>6：返回，等待另一连接请求；<br><br>7：关闭套接字，关闭加载的套接字库(closesocket()/WSACleanup())。<br><br>服务器端代码如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><img  src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top"><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Winsock2.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main()<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_53_981_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_53_981_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_53_981_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_53_981_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_53_981_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_53_981_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_53_981_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_53_981_open_text').style.display="'inline';"" alt="" align="top"></span><span id="Codehighlighter1_53_981_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_53_981_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;WORD&nbsp;wVersionRequested;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;WSADATA&nbsp;wsaData;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;err;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;wVersionRequested&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;MAKEWORD(&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">&nbsp;);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;err&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;WSAStartup(&nbsp;wVersionRequested,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">wsaData&nbsp;);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" id="Codehighlighter1_218_232_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_218_232_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_218_232_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_218_232_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" id="Codehighlighter1_218_232_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_218_232_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_218_232_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_218_232_open_text').style.display="'inline';"" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;err&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">0</span><span style="color: #000000;">&nbsp;)&nbsp;</span><span id="Codehighlighter1_218_232_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_218_232_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top">&nbsp;}</span></span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;LOBYTE(&nbsp;wsaData.wVersion&nbsp;)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" id="Codehighlighter1_318_349_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_318_349_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_318_349_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_318_349_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" id="Codehighlighter1_318_349_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_318_349_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_318_349_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_318_349_open_text').style.display="'inline';"" alt="" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HIBYTE(&nbsp;wsaData.wVersion&nbsp;)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">&nbsp;)&nbsp;</span><span id="Codehighlighter1_318_349_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_318_349_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;WSACleanup(&nbsp;);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top">&nbsp;}</span></span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;SOCKET&nbsp;sockSrv</span><span style="color: #000000;">=</span><span style="color: #000000;">socket(AF_INET,SOCK_STREAM,</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;SOCKADDR_IN&nbsp;addrSrv;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;addrSrv.sin_addr.S_un.S_addr</span><span style="color: #000000;">=</span><span style="color: #000000;">htonl(INADDR_ANY);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;addrSrv.sin_family</span><span style="color: #000000;">=</span><span style="color: #000000;">AF_INET;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;addrSrv.sin_port</span><span style="color: #000000;">=</span><span style="color: #000000;">htons(</span><span style="color: #800080;">6000</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;bind(sockSrv,(SOCKADDR</span><span style="color: #000000;">*</span><span style="color: #000000;">)</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">addrSrv,</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(SOCKADDR));<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;listen(sockSrv,</span><span style="color: #800080;">5</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;SOCKADDR_IN&nbsp;addrClient;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;len</span><span style="color: #000000;">=</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(SOCKADDR);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(</span><span style="color: #800080;">1</span><span style="color: #000000;">)<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" id="Codehighlighter1_669_978_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_669_978_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_669_978_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_669_978_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" id="Codehighlighter1_669_978_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_669_978_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_669_978_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_669_978_open_text').style.display="'inline';"" alt="" align="top">&nbsp;</span><span id="Codehighlighter1_669_978_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_669_978_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;SOCKET&nbsp;sockConn</span><span style="color: #000000;">=</span><span style="color: #000000;">accept(sockSrv,(SOCKADDR</span><span style="color: #000000;">*</span><span style="color: #000000;">)</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">addrClient,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">len);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;sendBuf[</span><span style="color: #800080;">50</span><span style="color: #000000;">];<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;sprintf(sendBuf,</span><span style="color: #800000;">"</span><span style="color: #800000;">Welcome&nbsp;%s&nbsp;to&nbsp;here!</span><span style="color: #800000;">"</span><span style="color: #000000;">,inet_ntoa(addrClient.sin_addr));<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;send(sockConn,sendBuf,strlen(sendBuf)</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">,</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;recvBuf[</span><span style="color: #800080;">50</span><span style="color: #000000;">];<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;recv(sockConn,recvBuf,</span><span style="color: #800080;">50</span><span style="color: #000000;">,</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">%s\n</span><span style="color: #800000;">"</span><span style="color: #000000;">,recvBuf);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;closesocket(sockConn);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top">&nbsp;}</span></span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top">}</span></span></div>
客户端编程的步骤：<br><br>1：加载套接字库，创建套接字(WSAStartup()/socket())；<br><br>2：向服务器发出连接请求(connect())；<br><br>3：和服务器端进行通信(send()/recv())；<br><br>4：关闭套接字，关闭加载的套接字库(closesocket()/WSACleanup())。<br><br>客户端的代码如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><img  src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top"><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Winsock2.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main()<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_53_765_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_53_765_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_53_765_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_53_765_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_53_765_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_53_765_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_53_765_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_53_765_open_text').style.display="'inline';"" alt="" align="top"></span><span id="Codehighlighter1_53_765_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_53_765_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;WORD&nbsp;wVersionRequested;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;WSADATA&nbsp;wsaData;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;err;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;wVersionRequested&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;MAKEWORD(&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">&nbsp;);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;err&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;WSAStartup(&nbsp;wVersionRequested,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">wsaData&nbsp;);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" id="Codehighlighter1_218_232_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_218_232_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_218_232_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_218_232_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" id="Codehighlighter1_218_232_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_218_232_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_218_232_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_218_232_open_text').style.display="'inline';"" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;err&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">0</span><span style="color: #000000;">&nbsp;)&nbsp;</span><span id="Codehighlighter1_218_232_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_218_232_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top">&nbsp;}</span></span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;LOBYTE(&nbsp;wsaData.wVersion&nbsp;)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" id="Codehighlighter1_318_349_Open_Image" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_318_349_open_text').style.display="'none';" document.getelementbyid('codehighlighter1_318_349_closed_image').style.display="'inline';" document.getelementbyid('codehighlighter1_318_349_closed_text').style.display="'inline';"" alt="" align="top"><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" id="Codehighlighter1_318_349_Closed_Image" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('codehighlighter1_318_349_closed_text').style.display="'none';" document.getelementbyid('codehighlighter1_318_349_open_image').style.display="'inline';" document.getelementbyid('codehighlighter1_318_349_open_text').style.display="'inline';"" alt="" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HIBYTE(&nbsp;wsaData.wVersion&nbsp;)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">&nbsp;)&nbsp;</span><span id="Codehighlighter1_318_349_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cnblogs.com/Images/dot.gif" alt=""></span><span id="Codehighlighter1_318_349_Open_Text"><span style="color: #000000;">{<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;WSACleanup(&nbsp;);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top">&nbsp;}</span></span><span style="color: #000000;"><br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;SOCKET&nbsp;sockClient</span><span style="color: #000000;">=</span><span style="color: #000000;">socket(AF_INET,SOCK_STREAM,</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;SOCKADDR_IN&nbsp;addrSrv;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;addrSrv.sin_addr.S_un.S_addr</span><span style="color: #000000;">=</span><span style="color: #000000;">inet_addr(</span><span style="color: #800000;">"</span><span style="color: #800000;">127.0.0.1</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;addrSrv.sin_family</span><span style="color: #000000;">=</span><span style="color: #000000;">AF_INET;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;addrSrv.sin_port</span><span style="color: #000000;">=</span><span style="color: #000000;">htons(</span><span style="color: #800080;">6000</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;connect(sockClient,(SOCKADDR</span><span style="color: #000000;">*</span><span style="color: #000000;">)</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">addrSrv,</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(SOCKADDR));<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;send(sockClient,</span><span style="color: #800000;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;">,strlen(</span><span style="color: #800000;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">,</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;recvBuf[</span><span style="color: #800080;">50</span><span style="color: #000000;">];<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;recv(sockClient,recvBuf,</span><span style="color: #800080;">50</span><span style="color: #000000;">,</span><span style="color: #800080;">0</span><span style="color: #000000;">);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">%s\n</span><span style="color: #800000;">"</span><span style="color: #000000;">,recvBuf);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;closesocket(sockClient);<br><img  src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top">&nbsp;WSACleanup();<br><br></span></span></div><img src ="http://www.cppblog.com/richardhe/aggbug/60456.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-08-30 20:16 <a href="http://www.cppblog.com/richardhe/articles/60456.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>插件系统-选择GetProcAddress还是Interfaces（译）</title><link>http://www.cppblog.com/richardhe/articles/59429.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Wed, 20 Aug 2008 05:34:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/59429.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/59429.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/59429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/59429.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/59429.html</trackback:ping><description><![CDATA[转自http://www.imyaker.com/blog/article.asp?id=34<br>插件系统-选择GetProcAddress还是Interfaces（译）<br>原文：<br><a  href="http://www.imyaker.com/blog/article.asp?id=35" target="_blank" rel="external">Plugin System &#8211; an alternative to GetProcAddress and interfaces</a><br><img  src="http://www.imyaker.com/blog/images/download.gif" alt="下载文件" style="margin: 0px 2px -4px 0px;"> <a  href="http://www.imyaker.com/blog/attachments/month_0707/PluginSystem_src.zip" target="_blank">代码下载</a><br><strong><span style="color: blue;">[介绍]</span></strong><br>有很多文章描述如何实现一个简单的插件框架，比如后面的链接[1]和[2]。通常有两种方法<br>(1)
插件实现一组标准的（并且通常是小的）函数（方法）。宿主（host)知道这些函数的名字，并且可以通过使用GetProcAddress函数获得这些函
数的地址。这并不合适，随着函数数量的增长，维护变得越来越困难。你必须手动通过函数名绑定函数，这样你就不得不做很多工作。<br>(2)GetProcAddress所返回的函数被用来传递接口指针（Interface Pointer）给插件或者从插件里获取接口指针。剩下的宿主和插件的通信通过接口完成。下面是一个例子<br><br>我
们将使用一个简单的例子。宿主程序是一个图片查看器。它实现了一个插件框架来增加对不同图片格式的支持（在这个例子中就是24-bit的BMP图象和24
-bit的TGA(Targa)图象）。插件将被实现为DLLs并且将有.imp的扩展名以便和普通dll文件区分开来了.注意，尽管如此，可是这篇文章
是关于插件的，而不是关于图象解解析器的。这里所提供的解析器非常基础并且只是用来说明的。<br><br><strong><span style="color: blue;">[使用接口的方法]</span></strong><br>接口是所有函数都是公共的并且纯虚的基类，并且没有没有数据成员。比如<br>
<div class="UBBPanel">
<div class="UBBTitle"><img  src="http://www.imyaker.com/blog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent">// IImageParser is the interface that all image parsers<br>// must implement<br>class IImageParser<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;public:<br>&nbsp;&nbsp;&nbsp;&nbsp;// parses the image file and reads it into a HBITMAP<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual HBITMAP ParseFile( const char *fname )=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;// returns true if the file type is supported<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual bool SupportsType( const char *type ) const=0;<br>};</div>
</div>
<br>实际的图象解析器必须继承自接口类并且实现纯虚函数。BMP文件解析器可能是这个样子。<br>
<div class="UBBPanel">
<div class="UBBTitle"><img  src="http://www.imyaker.com/blog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent">// CBMPParser implements the IImageParser interface<br>class CBMPParser: public IImageParser<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;public:<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual HBITMAP ParseFile( const char *fname );<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual bool SupportsType( const char *type ) const;<br><br>private:<br>&nbsp;&nbsp;&nbsp;&nbsp;HBITMAP CreateBitmap( int width, int height, void **data );<br>};<br><br>static CBMPParser g_BMPParser;<br><br>// The host calls this function to get access to the<br>// image parser<br>extern "C" __declspec(dllexport) IImageParser *GetParser( void )<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;return &amp;g_BMPParser;<br>}</div>
</div>
<br>宿主将使用LoadLibrary函数来载入BmpParser.imp，然后使用GetProcAddress("GetParser")来得到GetParser函数的地址，然后调用它得到IImageParser类的指针。<br>宿主将保存了注册了的解析器的邻接表(list)，它把GetParser函数返回的指针附加到那个邻接表上去。<br>当宿主需要解析一个bmp文件的时候，它将调用每个解析器的SupportType(".BMP")。如果返回类型是true,宿主将调用那个解析器并且使用完整文件名调用待解析文件，并将绘制HBITMAP句柄指向的位图。<br><br>基类并不真的必须是纯接口。在技术上这里的限制是所有的成员必须可以通过对象指针访问。所以你可以有：<br>- 纯虚成员函数（它们能通过虚表被间接访问）<br>- 数据成员（它们可以通过对象的指针直接访问）<br>- 内联成员函数（技术上它们不能通过指针访问，但是它们的代码又一次在插件里实例化。<br>这样就剩下了非内联和静态成员函数。插件无法从宿主访问这样的函数，宿主也不能对插件进行这样的操作。不幸的是在一个大型系统之中，这样的函数要占据代码的大部分。<br><br>例如所有的图象解析器需要CreateFunction函数。有必要在基类里声明它并且在宿主端实现。否则每个插件都将有一份这个函数的拷贝。<br>这个方法的另一个限制是你不能由宿主端暴露任何全局成员或者全局函数给插件端。<br>我们怎么改进呢?<br><br><strong><span style="color: blue;">[把宿主分成Dll和Exe]</span></strong><br>让
我们看一下USER32模块，它有两个部分 - user32.dll 和
user32.lib。真正的代码和数据在dll中，lib仅仅提供调用dll函数的占位函数。最好的事情在于它是自动发生的。当你链接到
user32.lib你就自动地获得访问user32.dll函数的权利。（这里翻译的不好）<br>MFC 实现得更进一步 - 它暴露你能直接使用和继承的整个类。它们没有我们在上面讨论的纯虚接口类的限制。<br>我
们也能做同样的事情。任何你想提供给插件的函数（我私下觉得原文functionality这个词用得不好）都能放在一个单独的Dll里。使用
/IMPLIB 链接器选项来创建相应的 LIB
文件。插件能与那个静态库链接，并且所有导出函数都能提供给它们。你能按你喜欢的方式把代码分成Dll 和
Exe。极限情况下，像在代码里演示的那样，Exe 工程里仅仅含有一行WinMain函数，它仅仅用来启动Dll。<br>任何你想要导出的全局数据，函数，类，或者成员函数必须被标记为 __declspec(dllexport) 在编译插件时。一个常用的技巧是使用宏<br>
<div class="UBBPanel">
<div class="UBBTitle"><img  src="http://www.imyaker.com/blog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent"><br>#ifdef COMPILE_HOST<br>// when the host is compiling<br>#define HOSTAPI __declspec(dllexport)<br>#else<br>// when the plugins are compiling<br>#define HOSTAPI __declspec(dllimport)<br>#endif<br></div>
</div>
<br>添加宏COMPILE_HOST的定义到Dll工程里，但是不加到插件工程里。<br><br>在宿主Dll端：<br>
<div class="UBBPanel">
<div class="UBBTitle"><img  src="http://www.imyaker.com/blog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent"><br>// CImageParser is the base class that all image parsers<br>// must inherit<br>class CImageParser<br>{<br>public:<br>&nbsp;&nbsp;&nbsp;&nbsp;// adds the parser to the parsers list<br>&nbsp;&nbsp;&nbsp;&nbsp;HOSTAPI CImageParser( void );<br>&nbsp;&nbsp;&nbsp;&nbsp;// parses the image file and reads it into a HBITMAP<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual HBITMAP ParseFile( const char *fname )=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;// returns true if the file type is supported<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual bool SupportsType( const char *type ) const=0;<br><br>protected:<br>&nbsp;&nbsp;&nbsp;&nbsp;HOSTAPI HBITMAP CreateBitmap( int width, int height,<br>&nbsp;&nbsp;&nbsp;&nbsp;void **data );<br>};</div>
</div>
<br>现在基类并不仅仅限于一个接口。我们能增加更多基本功能。CreateBitmap函数将被所有解析器共享。<br>这次不再是宿主调用一个函数来获取解析器并且将它添加到邻接表中，这个功能被CImageParser的构造函数取代。当解析器对象被创建，它的构造函数将自动更新邻接表。宿主不必再使用GetProcAddress函数来看看什么解析器在Dll里。<br><br>在插件端：<br>
<div class="UBBPanel">
<div class="UBBTitle"><img  src="http://www.imyaker.com/blog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent">// CBMPParser inherits from CImageParser<br>class CBMPParser: public CImageParser<br>{<br>public:<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual HBITMAP ParseFile( const char *fname );<br>&nbsp;&nbsp;&nbsp;&nbsp;virtual bool SupportsType( const char *type ) const;<br>};<br><br>static CBMPParser g_BMPParser;</div>
</div>
<br>当g_BMPParser被创建是它的构造函数 CBMPParser() 将被调用。那个构造函数（在插件端实现）将调用基类的构造函数CImageParser() （在宿主端实现）。那是可能的因为构造函数被标记为HOSTAPI。<br>等等，还可以变得更好<br><br>[把宿主Dll和Exe连接起来]<br>（这一部分暂时没翻译）<br><br><strong><span style="color: blue;">[链接]</span></strong><br>[1] <a  href="http://www.codeproject.com/dll/plugin.asp" target="_blank" rel="external">Plug-In framework using DLLs</a> by Mohit Khanna<br>[2] <a  href="http://www.codeproject.com/com/AddinProjectFramework.asp" target="_blank" rel="external">ATL COM Based Addin / Plugin Framework With Dynamic Toolbars and Menus</a> by thomas_tom99<br><br>PS.我想，Interface方法，是在第一种方法之上加入了一个间接层。<br>我现在到没有太强的感觉非内联函数和静态函数会成为这样一个大型系统的主要部分，Interface的派生类中的非内联函数应该只被纯虚接口函数调用，不然就是接口设计有问题了。<img src ="http://www.cppblog.com/richardhe/aggbug/59429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-08-20 13:34 <a href="http://www.cppblog.com/richardhe/articles/59429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++按位操作符</title><link>http://www.cppblog.com/richardhe/articles/58071.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 05 Aug 2008 09:51:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/58071.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/58071.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/58071.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/58071.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/58071.html</trackback:ping><description><![CDATA[<div class="postBody">
<p>顾名思义，按位运算符允许按照位来操作整型变量。可以把按位运算符应用于任意signed和unsigned整型，包括char类型。但是，它们通常应用于不带符号的整型。</p>
<p>这些运算符的一个常见应用是在整型变量中使用单个的位存储信息。例如标记，它用于描述二进制状态指示符。可以使用一个位来描述有两个状态的值：开或关、男或女，真或假。</p>
<p>也可以使用按位运算符处理存储在一个变量中的几个信息项。例如，颜色值常常记录为三个八位值，分别存储颜色中红、绿和蓝的强度。这些常常保存到四字
节变量中的三个字节。第四个字节也不会浪费，包含表示颜色透明度的值。显然，要处理各个颜色成分，需要从变量中分离出各个字节，按位运算符就可以做到这一
点。</p>
<p>再看另外一个例子，假定需要记录字体的信息，那么，只要存储每种字体的样式和字号，以及字体是黑体还是斜体，就可以把这些信息都存储在一个二字节的整型变量中，如图3-1所示。</p>
<p><img  src="http://book.csdn.net/bookfiles/31/3/image001.gif" alt="" width="277" height="167"></p>
<p>图3-1 把字体数据存储在2个字节中</p>
<p>可以使用一位来记录字体是否为斜体——
1表示斜体，0表示一般。同样，用另一位来指定字体是否为黑体。使用一个字节可以从多达256种不同的样式中选择一个，再用另外5位记录最多32磅的字
号。因此，在一个16位的字中，可以记录四个不同的数据项。按位运算符提供了访问和修改整数中单个位和一组位的便利方式，能方便地组合和分解一个16位的
字。</p>
<h3>3.3.1 移位运算符</h3>
<p>移位运算符可以把整型变量中的内容向左或向右移动指定的位数。移位运算符和其他按位运算符一起使用，可以获得前面描述的结果。&gt;&gt;运算符把位向右移动，&lt;&lt;运算符把位向左移动，移出变量两端的位被舍弃。</p>
<p>所有的按位操作都可以处理任何类型的整数，但本章的例子使用16位的变量，使例子较为简单。用下面的语句声明并初始化一个变量number：</p>
<p>unsigned short number=16387U;</p>
<p>如第2章所述，不带符号的字面量应在数字的最后添加字母U或u。</p>
<p>在下面的语句中，对这个变量的内容进行移位，并存储结果：</p>
<p>unsigned short result = number &lt;&lt;2; //Shift left two bit positions</p>
<p>移位运算符的左操作数是要移位的值，右操作数指定要移动的位数。图3-2列出了该操作的过程。</p>
<p><img  src="http://book.csdn.net/bookfiles/31/3/image002.gif" alt="" width="433" height="214"></p>
<p>图3-2 移位运算</p>
<p>从图3-2可以看出，把数值16387向左移动两位，得到数值12。数值的这种剧烈变化是舍弃高位数字的结果。</p>
<p>把数值向右移动，可以使用下面的语句：</p>
<p>result = number &gt;&gt;2; //Shift right two bit positions</p>
<p>把数值16387向右移动两位，得到数值4096。向右移动两位相当于使该数值除以4。</p>
<p>只要没有舍弃位，向左移动n位就相当于把该数值乘以2的n次方。换言之，就等于把该数值乘以2<sup>n</sup>。同样，向右移动n位就相当
于把该数值除以2的n次方。但要注意，变量number向左移位时，如果舍弃了重要的位，结果就不是我们希望的那样了。可是，这与乘法运算并没有不同。如
果把2字节的数值乘以4，就会得到相同的结果，所以向左移位和相乘仍是等价的。出现问题的原因是相乘的结果超出了2字节整数的取值范围。</p>
<p>如果需要修改原来的值，可以使用op= 赋值运算符。在这种情况下，可以使用&gt;&gt;=或&lt;&lt;=运算符。例如：</p>
<p>number &gt;&gt;= 2; // Shift contents of number two positions to the right</p>
<p>这等价于：</p>
<p>number =number &gt;&gt; 2; // Shift contents of number two positions to the right</p>
<p>这些移位运算符跟前面用于输入输出的插入和提取运算符有可能搞混。从编译器的角度来看，其含义一般可以从上下文中判断出来。否则，编译器就会生成一个消息，但用户需要非常小心。例如，如果输出变量number向左移动两位的结果，就应编写下面的代码：</p>
<p>cout &lt;&lt; (number &lt;&lt; 2);</p>
<p>其中，括号是必不可少的。没有括号，编译器就会把移位运算符解释为流插入运算符，从而得不到想要的结果。</p>
<h4>按位移动带符号的整数</h4>
<p>可以把移位运算符应用于带符号和不带符号的整型数。但是，向右移位运算符在带符号整数类型的操作随系统的不同而不同，这取决于编译器的实现。在一些情况下，向右移位运算符会在左边空出来的位上填充0。在其他情况下，符号位向右移动，在左边空出来的位上填充1。</p>
<p>移动符号位的原因是为了保持向右移位和除法运算的一致性。可以用char类型的变量来说明这一点，解释其工作原理。假定把value定义为char类型，其初始值为&#8211;104(十进制)：</p>
<p>signed char value=&#8211;104;</p>
<p>其二进制表示为10011000。使用下面的操作把它向右移动两位：</p>
<p>value &gt;&gt;= 2; //Result 11100110</p>
<p>注释中显示了其二进制结果。右边溢出了两个0，因为符号位是1，就在左边空出来的位上填充1。该结果的十进制表示是&#8211;26，这正好是value的值除以4的结果。当然，对于不带符号的整数类型的操作，符号位不移动，在左边空出来的位上填充0。</p>
<p>前面说过，在向右移位负整数时，其操作是已定义好的，所以实现该操作时不一定要依赖它。因为在大多数情况下，使用这些运算符是为了进行按位操作，此时维护位模式的完整性是非常重要的。所以，应总是使用不带符号的整数，以确保避免高阶位的移位。</p>
<h3>3.3.2 位模式下的逻辑运算</h3>
<p>修改整数值中的位时，可以使用4个按位运算符，如表3-1所示。</p>
<p>表3-1 按位运算符</p>
<div align="center">
<table style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 60.45pt;" valign="top" width="81">
            <p>运 算 符</p>
            </td>
            <td style="border-style: solid none; border-color: windowtext -moz-use-text-color; border-width: 1pt medium; padding: 0cm 5.4pt; width: 366.3pt;" valign="top" width="488">
            <p>说 明</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 60.45pt;" valign="top" width="81">
            <p>~</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 366.3pt;" valign="top" width="488">
            <p>这是按位求反运算符。它是一个一元运算符，可以反转操作数中的位，即1变成0，0变成1</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 60.45pt;" valign="top" width="81">
            <p>&amp;</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 366.3pt;" valign="top" width="488">
            <p>这是按位与运算符，它对操作数中相应的位进行与运算。如果相应的位都是1，结果位就是1，否则就是0</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 60.45pt;" valign="top" width="81">
            <p>^</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 366.3pt;" valign="top" width="488">
            <p>这是按位异或运算符，它对操作数中相应的位进行异或运算。如果相应的位各不相同，例如一个位是1，另一个位是0，结果位就是1。如果相应的位相同，结果位就是0</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 60.45pt;" valign="top" width="81">
            <p>|</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 366.3pt;" valign="top" width="488">
            <p>这是按位或运算符，它对操作数中相应的位进行或运算。如果两个对应的位中有一个是1，结果位就是1。如果两个位都是0，结果就是0</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>&nbsp;</p>
<p>表3-1中的运算符按照其优先级排列，在这个集合中，按位求反运算符的优先级最高，按位或运算符的优先级最低。在附录D的运算符优先级表中，按位移动运算符&lt;&lt;和&gt;&gt;具有相同的优先级，它们位于～运算符的下面，&amp;运算符的上面。</p>
<p>如果以前没有见过这些运算符，就会问&#8220;这非常有趣，但这是为什么？&#8221;。下面就将它们用于实践。</p>
<h4>1. 使用按位与运算符</h4>
<p>按位与运算符一般用于选择整数值中特定的一个位或一组位。为了说明这句话的含义，下面再次使用本节开头的例子，利用一个16位整数存储字体的特性。</p>
<p>假定声明并初始化一个变量，指定一种12磅字号、斜体、样式为6的字体。实际上，就是图3-1中的字体。样式的二进制值是00000110，斜体位
是1，黑体位是0，字号是01100。还有一个没有使用的位，需要把font变量的值初始化为二进制数0000 0110 0100 1100。</p>
<p>由于4位二进制数对应于一个16进制数，因此最简单的方法是以十六进制方式指定初 始值：</p>
<p>unsigned short font=0x064C; // Style 6, italic, 12 point</p>
<p>注释：</p>
<p>在建立像这样的位模式时，十六进制表示法要比十进制表示法更合适。</p>
<p>要使用字号，需要从font变量中提取它，这可以使用按位与运算符来实现。只有当两个位都是1时，按位与运算符才会产生1，所以可以定义一个值，在
将定义字号的位和font执行按位与操作时选择该位。为此，只需定义一个值，该值在我们感兴趣的位上包含1，在其他位上包含0。这种值称为掩码，用下面的
语句定义它：</p>
<p>unsigned short size_mask=0x1F; //Mask is 0000 0000 0001 1111 </p>
<p>//to select size</p>
<p>font变量的5个低位表示其字号，把这些位设置为1，剩余的位设置为0，这样它们就会被舍弃(二进制数0000 0000 0001 1111可转换为十六进制数1F)。</p>
<p>现在可以用下面的语句提取font中的字号了：</p>
<p>unsigned short size=font &amp; size_mask;</p>
<p>在&amp;操作中，当两个对应的位是1时，结果位就是1。任何其他组合起来的结果就是0。因此组合起来的值如下：</p>
<p>font 0000 0110 0100 1100</p>
<p>size_mask 0000 0000 0001 1111</p>
<p>font &amp; size_mask 0000 0000 0000 1100</p>
<p>把二进制值分解为4位一组的形式并不是很重要，这只是易于表示对应的十六进制数，看出其中有多少位。掩码的作用是把最右边的5位分隔出来，这5位表示点数(即字号)。</p>
<p>可以使用同样的方法选择字体的样式，只是还需要使用按位移动运算符把样式值向右移动。可以用下面的语句定义一个掩码，选择左边的8位，如下所示：</p>
<p>unsigned short style_mask=0xFF00; //Mask is 1111 1111 0000 0000 </p>
<p>//for style</p>
<p>用下面的语句获取样式值：</p>
<p>unsigned short style＝(font &amp; style_mask) &gt;&gt; 8; //Extract the style</p>
<p>该语句的结果如下：</p>
<p>font 0000 0110 0100 1100</p>
<p>style_mask 1111 1111 0000 0000</p>
<p>font &amp; style_mask 0000 0110 0000 0000</p>
<p>(font &amp; style_mask) &gt;&gt; 8 0000 0000 0000 0110</p>
<p>为表示斜体和黑体的位定义掩码，并把相应的位设置为1，就很容易把它们分隔出来。当然，还需要一种方式来测试得到的位，这部分内容详见第4章。</p>
<p>按位与运算符的另一个用途是关闭位。前面介绍的是掩码中为0的位在结果中也将输出0。例如，为了关闭表示斜体的位，其他的位不变，只需定义一个掩
码，使该掩码中的斜体位为0，其他位为1，再对font变量和该掩码进行按位与操作即可。实现此操作的代码将在按位或运算符一节中介绍。</p>
<h4>2. 使用按位或运算符</h4>
<p>可以使用按位或运算符设置一个或多个位。继续操作前面的font变量，现在需要设置斜体和黑体位。用下面的语句可以定义掩码，选择这些位：</p>
<p>unsigned short italic=0x40U; //Seventh bit from the right</p>
<p>unsigned short bold=0x20U; //Sixth bit from the right</p>
<p>用下面的语句设置黑体位：</p>
<p>font |= bold; // Set bold</p>
<p>位的组合如下：</p>
<p>font 0000 0110 0100 1100</p>
<p>bold 0000 0000 0010 0000</p>
<p>font | bold 0000 0110 0110 1100</p>
<p>现在，font变量指定它表示的字体是黑体和斜体。注意这个操作会设置位，而不考虑以前的状态。如果以前位的状态是开，则现在仍保持开的状态。</p>
<p>也可以对掩码执行按位或操作，设置多个位。下面的语句就同时设置了黑体和斜体：</p>
<p>font |= bold | italic; //Set bold and italic</p>
<p>该语言很容易让人选择错误的运算符。&#8220;设置斜体和黑体&#8221;很容易让人觉得应使用&amp;运算符，而这是错误的。对两个掩码执行按位与操作会得到一个所有位都是0的值，这不会改变字体的任何属性。</p>
<p>如上一节最后所述，可以使用&amp;运算符关闭位。也就是定义一个掩码，把其中要关闭的位设置为0，其他位设置为1。但如何指定这样的掩码？如果
要显式指定它，就需要知道变量中有多少个字节，如果希望程序可以任何方式移植，这就不很方便。可是，在通常用于打开位的掩码上使用按位求反运算符，就可以
得到这样的掩码。在bold掩码上关闭黑体位，就可以得到该掩码：</p>
<p>bold 0000 0000 0010 0000</p>
<p>~bold 1111 1111 1101 1111</p>
<p>按位求反运算符的作用是反转原数值中的每一位，使0变成1，1变成0。无论bold变量占用2个字节、4个字节还是8个字节，这都会生成我们期望的结果。</p>
<p>提示：</p>
<p>按位求反运算符有时称为NOT运算符，因为对于它操作的每个位，都会得到跟开始不同的值。</p>
<p>因此，在关闭黑体位时，只需对掩码bold的反码和font变量执行按位与操作，可用的语句如下所示：</p>
<p>font &amp;= ~bold; //Turn bold off</p>
<p>还可以使用&amp;运算符把几个掩码组合起来，再对结果跟要修改的变量执行按位与操作，将多个位设置为0。例如：</p>
<p>font &amp;= ~bold &amp; ~italic; //Turn bold and italic off</p>
<p>这个语句把font变量中的斜体和黑体位设置为0。注意这里不需要括号，因为~运算符的优先级高于&amp;运算符。但是，如果不清楚运算符的优先级，就应加上括号，表示希望执行的操作。这肯定是无害的，在需要括号时还可以正常发挥作用。</p>
<h4>3. 使用按位异或运算符</h4>
<p>按位异或运算符的使用频率远远低于&amp;和 |
运算符，有关它的使用例子也比较少。但它的一个重要应用是图形编程。在屏幕中创建动画的一种方式是绘制一个对象，删除它，再在一个新位置重新绘制。如果要
求动画很平滑，这个过程就需要重复得很快，其中删除是一个重要的部分。我们并不想删除和重新绘制整个屏幕，因为这非常费时，屏幕也会出现闪烁。最理想的
是，只删除屏幕上要移动的对象。使用所谓的异或模式就可以做到这一点，得到非常平滑的 动画。</p>
<p>异或模式的理念是，在屏幕上用给定的颜色绘制对象，如果接着用背景色重新绘制它，它就会消失。如图3-3所示。</p>
<p><img  src="http://book.csdn.net/bookfiles/31/3/image003.gif" alt="" width="345" height="226"></p>
<p>图3-3 用异或模式绘图</p>
<p>以异或模式在屏幕上绘制对象时，每次绘制对象的颜色会自动在为对象所选的颜色和背景色之间来回变化。得到这一效果的关键是使用按位异或运算符快速而
自动地改变颜色。它使用异或运算符的一个特性，即如果对两个值进行异或操作，再对所得的结果和一个原始值执行异或操作，就会得到另一个值。这听起来很复
杂，下面就用一个例子来说明。</p>
<p>假定要在前景色(这里使用红色)和背景色(白色)之间来回切换。颜色通常用3个8位值来表示，分别对应于红、蓝、绿的亮度，存储在一个4字节的整数
中。通过改变颜色中的红、蓝和绿的比例，就可以获得大约1600万种不同的颜色，包括从白色到黑色之间的所有颜色。纯红色是0xFF0000，这时红色成
分设置为其最大值，其他两种颜色即蓝色和绿色的成分设置为0。在相同颜色模式下，绿色就是0xFF00，蓝色是0xFF。在白色中，红、蓝、绿的成分具有
相同的最大值，即0xFFFFFF。</p>
<p>可以用下面的语句定义表示红色和白色的变量：</p>
<p>unsigned long red=0XFF0000UL; //Color red</p>
<p>unsigned long white=0XFFFFFFUL; //Color white-RGB all maximum</p>
<p>接着创建一个掩码，用于在红色和白色之间来回切换，并把包含绘图颜色的变量初始化为红色：</p>
<p>unsigned long mask=red ^ white; //Mask for switching colors</p>
<p>unsigned long draw_color=red; //Drawing color</p>
<p>变量mask初始化为要切换的两种颜色的按位异或操作结果，因此：</p>
<p>red 1111 1111 0000 0000 0000 0000</p>
<p>white 1111 1111 1111 1111 1111 1111</p>
<p>mask(即red ^ white) 0000 0000 1111 1111 1111 1111</p>
<p>如果对mask和red执行异或操作，就会得到white，如果对mask和white执行异或操作，就会得到red。因此，使用draw_color中的颜色绘制对象，就可以通过下面的语句切换颜色：</p>
<p>draw_color ^= mask; //Switch the drawing color</p>
<p>当draw_color包含red时，其执行过程如下：</p>
<p>draw_color 1111 1111 0000 0000 0000 0000</p>
<p>mask 0000 0000 1111 1111 1111 1111</p>
<p>draw_color ^ mask 1111 1111 1111 1111 1111 1111</p>
<p>显然，draw_color的值从红色变为白色。再次执行这个语句，就会把颜色改回为红色：</p>
<p>draw_color^=mask; //Switch the drawing color</p>
<p>其执行过程如下：</p>
<p>draw_color 1111 1111 1111 1111 1111 1111</p>
<p>mask 0000 0000 1111 1111 1111 1111</p>
<p>draw_color ^ mask 1111 1111 0000 0000 0000 0000</p>
<p>draw_color又变成了红色。这个技术适用于任意两种颜色，当然它实际上与特定颜色没有一点关系，可以把它用于切换任意一对整型数值。</p>
<p>程序示例3.4—— 使用按位运算符</p>
<p>下面用一个例子来试验按位运算符，看看它们如何一起工作。本例还演示了如何使用异或运算符在两个值之间切换，以及如何使用掩码来选择和设置各个位。代码如下：</p>
<p>//Program 3.4 Using the bitwise operators</p>
<p>#include &lt;iostream&gt;</p>
<p>#include &lt;iomanip&gt;</p>
<p>using std::cout;</p>
<p>using std::endl;</p>
<p>using std::setfill;</p>
<p>using std::setw;</p>
<p>&nbsp;</p>
<p>int main() {</p>
<p>unsigned long red=0xFF0000UL; //Color red</p>
<p>unsigned long white=0xFFFFFFUL; //Color white - RGB all maximum</p>
<p>&nbsp;</p>
<p>cout &lt;&lt; std::hex; //Set hexadecimal output format</p>
<p>cout &lt;&lt; setfill('0'); //Set fill character for output</p>
<p>&nbsp;</p>
<p>cout &lt;&lt; "\nTry out bitwise AND and OR operators.";</p>
<p>cout &lt;&lt; "\nInitial value red = "&lt;&lt; setw(8) &lt;&lt; red;</p>
<p>cout &lt;&lt; "\nComplement ~red = "&lt;&lt; setw(8) &lt;&lt;~ red;</p>
<p>&nbsp;</p>
<p>cout &lt;&lt; "\nInitial value white = "&lt;&lt; setw(8) &lt;&lt; white;</p>
<p>cout &lt;&lt; "\nComplement ~ white = "&lt;&lt; setw(8) &lt;&lt;~ white;</p>
<p>&nbsp;</p>
<p>cout &lt;&lt; "\n Bitwise AND red &amp; white = " &lt;&lt; setw(8) &lt;&lt; (red &amp; white); </p>
<p>cout &lt;&lt; "\n Bitwise OR red | white = " &lt;&lt; setw(8) &lt;&lt; (red | white); </p>
<p>&nbsp;</p>
<p>cout &lt;&lt; "\n\nNow we can try out successive exclusive OR operations.";</p>
<p>&nbsp;</p>
<p>unsigned long mask=red ^ white;</p>
<p>&nbsp;</p>
<p>cout &lt;&lt; "\n mask= red ^ white = " &lt;&lt; setw(8) &lt;&lt; mask; </p>
<p>cout &lt;&lt; "\n mask ^ red = " &lt;&lt; setw(8) &lt;&lt; (mask ^ red); </p>
<p>cout &lt;&lt; "\n mask ^ white = " &lt;&lt; setw(8) &lt;&lt; (mask ^ white); </p>
<p>&nbsp;</p>
<p>unsigned long flags=0xFF; //Flags variable</p>
<p>unsigned long bit1mask=0x1; //Selects bit 1</p>
<p>unsigned long bit6mask=0x20; //Selects bit 6</p>
<p>unsigned long bit20mask=0x80000; //Selects bit 20</p>
<p>&nbsp;</p>
<p>cout &lt;&lt; "\n\nNow use masks to select or set a particular flag bit.";</p>
<p>cout &lt;&lt; "\nSelect bit 1 from flags : " &lt;&lt; setw(8) &lt;&lt; (flags &amp; bit1mask); </p>
<p>cout &lt;&lt; "\nSelect bit 6 from flags : " &lt;&lt; setw(8) &lt;&lt; (flags &amp; bit6mask); </p>
<p>cout &lt;&lt; "\nSwitch off bit 6 in flags : " &lt;&lt; setw(8) &lt;&lt; (flags &amp;= ~bit6mask); </p>
<p>cout &lt;&lt; "\nSwitch on bit 20 in flags : " &lt;&lt; setw(8) &lt;&lt; (flags |= bit20mask); </p>
<p>cout &lt;&lt;endl;</p>
<p>return 0;</p>
<p>}</p>
<p>该例子的输出如下：</p>
<p>Try out bitwise AND and OR operators.</p>
<p>Initial value red = 00ff0000</p>
<p>Complement ~red = ff00ffff</p>
<p>Initial value white = 00ffffff</p>
<p>Complement ~ white = ff000000</p>
<p>Bitwise AND red &amp; white = 00ff0000</p>
<p>Bitwise OR red | white = 00ffffff</p>
<p>&nbsp;</p>
<p>Now we can try out successive exclusive OR operations.</p>
<p>mask= red ^ white =0000ffff</p>
<p>mask ^ red = 00ffffff</p>
<p>mask ^ white =00ff0000</p>
<p>&nbsp;</p>
<p>Now use masks to select or set a particular flag bit.</p>
<p>Select bit 1 from flags : 00000001</p>
<p>Select bit 6 from flags : 00000020</p>
<p>Switch off bit 6 in flags : 000000df</p>
<p>Switch on bit 20 in flags : 000800df</p>
<p>例子的说明</p>
<p>本例中添加了对标准头文件&lt;iomanip&gt;的#include指令，这个头文件在第2章介绍过，因为代码将使用操纵程序控制输出的格式。首先，定义两个整数变量，它们包含的值表示要用于后续按位运算的颜色：</p>
<p>unsigned long red=0xFF0000UL; //Color red</p>
<p>unsigned long white=0xFFFFFFUL; //Color white - RGB all maximum</p>
<p>为了把数据显示为十六进制值，可用下面的语句指定：</p>
<p>cout &lt;&lt; std::hex; //Set hexadecimal output format</p>
<p>其中hex是一个操纵程序，它把整数值的输出表示为十六进制。注意，这是模式化的，该程序以后在标准输出流中的所有整数输出都采用十六进制格式。不需要把hex发送给输出流cout。如果需要，可以用下面的语句把输出格式改回为十进制：</p>
<p>cout &lt;&lt; std::dec; //Set decimal output format</p>
<p>这个语句使用dec操纵程序，把整数输出重新设置为默认的十进制表示。注意，把输出格式设置为十六进制，仅影响整数值。浮点数值会继续显示为一般的十进制。</p>
<p>如果在输出整数时加上前导0，就会使结果更清晰易懂。用下面的语句设置这种模式：</p>
<p>cout &lt;&lt; setfill('0'); //Set fill character for output</p>
<p>其中setfill()是一个操纵程序，它把填充字符设置为括号中的字符。这也是模式化的，这样，以后的所有整数输出都会在需要时使用这个填充字符。它对十进制和十六进制输出都起作用。如果要用星号代替该填充字符，则可以使用下面的语句：</p>
<p>cout &lt;&lt; setfill('*'); //Set fill character for output</p>
<p>要把填充字符设置回原来的默认值，只需在括号中使用空格：</p>
<p>cout &lt;&lt; setfill(' '); //Set fill character for output</p>
<p>下面的语句显示red的值及其反码：</p>
<p>cout &lt;&lt; "\nInitial value red = "&lt;&lt; setw(8) &lt;&lt; red;</p>
<p>cout &lt;&lt; "\nComplement ~red = "&lt;&lt; setw(8) &lt;&lt;~ red;</p>
<p>这里使用第2章介绍的setw()操纵程序，把输出字段宽度设置为8。如果所有的输出值都采用相同的字段宽度，就很容易比较它们。设置宽度不是模式化的，它只应用于跟在字段宽度设置点后面的下一条语句的输出。在red和white的输出中，～运算符反转了其操作数的位。</p>
<p>下面的语句使用按位与以及按位或运算符来合并red和white：</p>
<p>cout &lt;&lt; "\n Bitwise AND red &amp; white = " &lt;&lt; setw(8) &lt;&lt; (red &amp; white); </p>
<p>cout &lt;&lt; "\n Bitwise OR red | white = " &lt;&lt; setw(8) &lt;&lt; (red | white); </p>
<p>注意输出中表达式的括号。它们是必需的，因为&lt;&lt;的优先级高于&amp;和|。没有括号，该语句就不会编译。如果查看一下输出，就会看
出它跟这里讨论的相同。若对两个值都为1的位执行按位与操作，就会得到1，否则结果就是0。在对两个位执行按位或操作时，除非两个位都是0，否则结果就是
1。</p>
<p>然后，创建一个掩码，在通过按位异或运算符组合两个值时，该掩码用于反转red和white的值。</p>
<p>unsigned long mask=red ^ white;</p>
<p>如果查看一下mask值的输出，就会发现在两个位的值不同时，对两个位执行异或操作的结果是1，在两个位的值相同时，该操作的结果是0。利用异或运算符把mask和两个颜色值中的一个组合起来，就会得到另一个颜色值。这可以用下面的语句来说明：</p>
<p>cout &lt;&lt; "\n mask ^ red = " &lt;&lt; setw(8) &lt;&lt; (mask ^ red); </p>
<p>cout &lt;&lt; "\n mask ^ white = " &lt;&lt; setw(8) &lt;&lt; (mask ^ white); </p>
<p>最后一组语句演示了如何使用掩码从一组标记位中选择一个位。选择某个位的掩码必须使该位的值为1，其他位的值为0。因此，从一个32位long变量中选择第1、6和20位的掩码定义如下：</p>
<p>unsigned long bit1mask=0x1; //Selects bit 1</p>
<p>unsigned long bit6mask=0x20; //Selects bit 6</p>
<p>unsigned long bit20mask=0x80000; //Selects bit 20</p>
<p>要从flags中选择一个位，只需对相应的掩码和flages的值执行按位与操作。例如：</p>
<p>cout &lt;&lt; "\nSelect bit 6 from flags : " &lt;&lt; setw(8) &lt;&lt; (flags &amp; bit6mask); </p>
<p>从输出中可以看到，表达式(flags &amp; bit6mask)的结果是只设置了第6位的整数。当然，如果flages中的第6位为0，该表达式的结果就是0。</p>
<p>要关闭一个位，需要对flages变量和一个掩码执行按位与操作。在该掩码中，要关闭的那个位是0，其他位是1。对掩码和对应的位执行按位求反操作，也可以关闭该位。bit6mask就是这样的一个掩码。下面的语句把flags中的第6位关闭，并显示结果：</p>
<p>cout &lt;&lt; "\nSwitch off bit 6 in flags : " &lt;&lt; setw(8) &lt;&lt; (flags &amp;= ~bit6mask); </p>
<p>当然，如果第6位已经是0，该位就保持不变。要打开一个位，只需对flages和一个掩码执行按位或操作，在该掩码中，要打开的那个位是1：</p>
<p>cout &lt;&lt; "\nSwitch on bit 20 in flags : " &lt;&lt; setw(8) &lt;&lt; (flags |= bit20mask); </p>
<p>这个语句把flags中的第20位设置为1，并显示结果。如果这个位已经是1，该位将保持不变。</p>
<h4>4. 输出操纵程序</h4>
<p>把第2章介绍的也算在内，到目前为止我们已介绍了5个模式化输出操纵程序，它们都是在&lt;iostream&gt;头文件中定义
的：scientific、fixed、dec、hex和oct。表3-2列出所有的其他相似的操纵程序。目前不介绍后两项中的bool值，它将在第4章
讨论。</p>
<p>表3-2 输出操纵程序</p>
<div align="center">
<table style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>操 纵 程 序</p>
            </td>
            <td style="border-style: solid none; border-color: windowtext -moz-use-text-color; border-width: 1pt medium; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>执行的动作</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>dec</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>把整数值格式化为十进制。这是默认的表示法</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>hex</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>把整数值格式化为十六进制</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>oct</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>把整数值格式化为八进制</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>left</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>使输出字段中的值左对齐，其右端用填充字符填充。默认的填充字符是空格</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>right</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>使输出字段中的值右对齐，其左端用填充字符填充。这是默认的对齐方式</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>fixed</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>以固定点表示法输出浮点数值，即不带指数</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 62.95pt;" valign="top" width="84">
            <p>scientific</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.25pt;" valign="top" width="487">
            <p>以科学表示法输出浮点数值，即尾数加指数的方式。默认的模式根据要显示的数值，选择fixed或scientific表示法</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>showpoint</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>给浮点数值显示小数点和尾部的0</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>noshowpoint</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>与上一个操纵程序相反。这是默认的</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>showbase</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>在八进制的输出前面加上前导0，在十六进制的输出前面加上前导0x或0X</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>noshowbase</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>八进制和十六进制的输出中不显示前缀。这是默认的</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>showpos</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>正数前面加上+号</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>noshowpos</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>正数前面不显示+号，这是默认的</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>uppercase</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>在以十六进制格式输出整数时，给十六进制数字显示大写字母A到F。如果设置了showbase，还要显示0X。在以科学计数法输出数值时，给指数显示E，而不是使用小写字母e</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>nouppercase</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>对上述项使用小写字母，这是默认的</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>boolalpha</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>把bool值显示为true和false</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 63.1pt;" valign="top" width="84">
            <p>noboolalpha</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 365.1pt;" valign="top" width="487">
            <p>把bool值显示为1和0</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>可以一次设置多种模式，方法是在流中插入多个操纵程序。例如，如果要把整型数据输出为十六进制值，且在输出字段中左对齐，就可以使用下面的语句：</p>
<p>std::cout &lt;&lt; std::hex &lt;&lt; std::left &lt;&lt; value;</p>
<p>这个语句会把value(以及程序中后续的所有整数，除非改变了设置)输出为左对齐的十六进制数值。</p>
<p>表3-3列出了需要提供参数值的输出操纵程序。</p>
<p>表3-3 需要参数的输出操纵程序</p>
<div align="center">
<table style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 71.75pt;" valign="top" width="96">
            <p>操 纵 程 序</p>
            </td>
            <td style="border-style: solid none; border-color: windowtext -moz-use-text-color; border-width: 1pt medium; padding: 0cm 5.4pt; width: 359.05pt;" valign="top" width="479">
            <p>执行的动作</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 71.75pt;" valign="top" width="96">
            <p>setfill()</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 359.05pt;" valign="top" width="479">
            <p>把填充字符设置为参数指定的字符。默认的填充字符是空格</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 71.75pt;" valign="top" width="96">
            <p>setw()</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 359.05pt;" valign="top" width="479">
            <p>把字段宽度设置为参数指定的值</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 71.75pt;" valign="top" width="96">
            <p>setprecision()</p>
            </td>
            <td style="border-style: none none solid; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 1pt; padding: 0cm 5.4pt; width: 359.05pt;" valign="top" width="479">
            <p>把浮点值的精度设置为参数指定的值。精度是输出中十进制数字的个数</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div id="EntryTag">Tag标签: <a  href="http://www.cnblogs.com/mz121star/tag/c%2b%2b%ef%bc%8c/">c++ </a>,<a  href="http://www.cnblogs.com/mz121star/tag/%e6%8c%89%e4%bd%8d%e8%bf%90%e7%ae%97%e7%ac%a6/">按位运算符</a>,<a  href="http://www.cnblogs.com/mz121star/tag/%e4%b8%8e%e6%88%96%e9%9d%9e/">与或非</a></div>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/58071.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-08-05 17:51 <a href="http://www.cppblog.com/richardhe/articles/58071.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dll学习笔记-隐式调用</title><link>http://www.cppblog.com/richardhe/articles/57428.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 29 Jul 2008 08:09:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/57428.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/57428.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/57428.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/57428.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/57428.html</trackback:ping><description><![CDATA[<div>
今天在研究怎么在vc中调用动态dll的问题，看了一个下午，总算有些眉目。</div>
首先来说说<strong>调用的原理</strong>：
<div>
调用DLL，首先需要将DLL文件映像到用户进程的地址空间中，然后才能进行函数调用，这个函数和进程内部一般函数的调用方法相同。Windows提供了
两种将DLL映像到进程地址空间的方法：隐式调用（通过lib和头文件）和显式调用（只通过提供的dll文件）。下面对这<strong>两种方式在vc中如何调用</strong>做详细的说明：</div>
<div><strong>a.隐式：</strong></div>
<div>
这种方法需要DLL工程经编译产生的LIB文件，此文件中包含了DLL允许应用程序调用的所有函数的列表，当链接器发现应用程序调用了LIB文件列出的某
个函数，就会在应用程序的可执行文件的文件映像中加入一些信息，这些信息指出了包含这个函数的DLL文件的名字。当这个应用程序运行时，也就是它的可执行
文件被操作系统产生映像文件时，系统会查看这个映像文件中关于DLL的信息，然后将这个DLL文件映像到进程的地址空间。</div>
<div>
系统通过DLL文件的名称，试图加载这个文件到进程地址空间时，它寻找DLL
文件的路径按照先后顺序如下：</div>
<div>&#183;程序运行时的目录，即可执行文件所在的目录；</div>
<div>&#183;当前程序工作目录</div>
<div>
&#183;系统目录：对于Windows95/98来说，可以调用GetSystemDirectory函数来得到，对于WindowsNT/2000来说，指的
是32位Windows的系统目录，也可以调用GetSystemDirectory函数来得到，得到的值为SYSTEM32。</div>
<div>&#183;Windows目录</div>
<div>&#183;列在PATH环境变量中的所有目录</div>
<div>VC中加载DLL的LIB文件的方法有以下三种：</div>
<div>①LIB文件直接加入到工程文件列表中</div>
<div>在VC中打开File
View一页，选中工程名，单击鼠标右键，然后选中&#8220;Add Files to
Project&#8221;菜单，在弹出的文件对话框中选中要加入DLL的LIB文件即可。</div>
<div>②设置工程的 Project Settings来加载DLL的LIB文件</div>
<div>打开工程的 Project
Settings菜单，选中Link，然后在Object/library
modules下的文本框中输入DLL的LIB文件。</div>
<div>③通过程序代码的方式</div>
<div>加入预编译指令#pragma comment
(lib,&#8221;*.lib&#8221;)，这种方法优点是可以利用条件预编译指令链接不同版本的LIB文件。因为，在Debug方式下，产生的LIB文件是Debug版本，如Regd.lib；在Release方式下，产生的LIB文件是Release版本，如Regr.lib。</div>
<div>
当应用程序对DLL的LIB文件加载后，还需要把DLL对应的头文件（*.h）包含到其中，在这个头文件中给出了DLL中定义的函数原型，然后声明。</div>
<div><strong>b.显式</strong></div>
<div>
隐式链接虽然实现较简单，但除了必须的*.dll文件外还需要DLL的*.h文件和*.lib文件，在那些只提供*.dll文件的场合就无法使用，而只能
采用显式链接的方式。这种方式通过调用API函数来完成对DLL的加载与卸载，其能更加有效地使用内存，在编写大型应用程序时往往采用此方式。这种方法编
程具体实现步骤如下：</div>
<div>①使用Windows API函数Load
Library或者MFC提供的AfxLoadLibrary将DLL模块映像到进程的内存空间，对DLL模块进行动态加载。</div>
<div>②使用GetProcAddress函数得到要调用DLL中的函数的指针。</div>
<div>③不用DLL时，用Free
Library函数或者AfxFreeLibrary函数从进程的地址空间显式卸载DLL&nbsp;<wbr></div>
<strong>&nbsp;<wbr>VC中调用实例</strong>
<div>
数据加密是计算机安全领域的重要内容，其基本思想是通过变换信息的表现形式来保护敏感信息，使非授权者不能了解被保护信息的内容<sup>[4]</sup>。常见的数据加密算法有：DES，IDEA，RSA，ECC，AES，MD5，SHA等。</div>
<div>
《共享软件加密算法库》是一款针对个人、企业开发共享软件的加密工具，支持Windows平台下各类开发工具:VC、VB、Delphi、PB、VFP
等，算法库集成的算法有：BlowFish、MD5、Secret16、AES、SHA、CRC32、RSA、DES、字符串加/解密、文件加/解密等多
种功能强大的算法。其提供了DLL文件—Reg.dll，可以通过复用它来实现数据加密与解密。</div>
<div><strong>隐式链接</strong></div>
<div>其提供了
Reg.h与Reg.lib两个隐式链接所必须的文件，所以可以采用此种方式。</div>
<div>①在VC中打开File
View一页，选中工程名，单击鼠标右键，然后选中&#8220;Add Files to
Project&#8221;菜单，在弹出的文件对话框中选中要加入Reg.lib。</div>
<div>②在VC中打开File View一页，选中Header
files，单击鼠标右键，然后选中&#8220;Add Files to
Folder&#8221;菜单，在弹出的文件对话框中选中要加入Reg.h，然后在工程相应的头文件中加入＃i
nclude
"Reg.h"。在Reh.h头文件中给出了DLL中定义的函数原型及声明。</div>
<div>如：加密函数原型及声明为extern "C" BOOL WINAPI File
Encrypt(LPCTSTR lpInputFileName, LPCTSTR lpOutputFileName, LPCTSTR
lpKey, LPCTSTR lpRegisterCode);解密函数原型及声明为extern "C" BOOL
WINAPI File Decrypt(LPCTSTR lpInputFileName, LPCTSTR
lpOutputFileName, LPCTSTR lpKey, LPCTSTR
lpRegisterCode)。其中对于WINAPI宏，把它加到函数原型定义前，系统会把它翻译为适当的调用方式，在Win32中，是把它翻译为_stdcall调用方式。</div>
<div>③直接调用所需要的加密与解密函数，如调用File
Encrypt()函数实现文本文件和二进制文件的加密，调用File
Decrypt()函数实现文本文件和二进制文件的解密，调用时的参数要与函数定义参数相符合。</div>
<div><strong>显式链接</strong></div>
<div>如果只提供Reg.dll一个文件，那么须用此种方式。</div>
<div>①加密模块：调用File
Encrypt()函数实现文本文件和二进制文件的加密。</div>
<div>//装载加密/解密DLL</div>
<div>HINSTANCE hdll=::Load Library ("Reg.dll");</div>
<div>//通过类型定义语句typedef来定义函数指针类型</div>
<div>Typedef BOOL &nbsp;<wbr>(_stdcall
*lpFileEncrypt)(LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR);</div>
<div>//函数声明</div>
<div>LpFileEncrypt FileEncrypt1;</div>
<div>//获取加密函数File Encrypt的函数指针</div>
<div>
FileEncrypt1=(lpFileEncrypt)::GetProcAddress(hdll,"FileEncrypt");</div>
<div>//调用DLL中加密函数File
Encrypt对文件加密，user-12345678为软件注册号</div>
<div>
FileEncrypt1(加密源文件名,加密生成目标文件名,密码,"user-12345678");</div>
<div>//释放DLL模块</div>
<div>&nbsp;<wbr>::AfxFreeLibrary(hdll);</div>
<div>②解密模块：调用File
Decrypt()函数实现文本文件和二进制文件的解密。</div>
<div>//装载加密/解密DLL</div>
<div>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
HINSTANCE hdll=::Load Library ("Reg.dll");</div>
<div>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>
//通过类型定义语句typedef来定义函数指针类型</div>
<div>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
Typedef BOOL &nbsp;<wbr>(_stdcall *lpFileDecrypt)(LPCTSTR,
LPCTSTR, LPCTSTR, LPCTSTR);</div>
<div>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
//函数声明</div>
<div>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
LpFileDecrypt FileDecrypt2;</div>
<div>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
//获取解密函数File Decrypt的函数指针</div>
<div>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
FileDecrypt2=(lpFileDecrypt)::GetProcAddress(hdll,"FileDecrypt");</div>
<div>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
//调用DLL中解密函数FileDecrypt对文件加密，user-12345678为软件注册号</div>
<div>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
FileDecrypt2(解密源文件名,解密生成目标文件名,密码,"user-12345678");</div>
<div>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
//释放DLL模块</div>
<div>::AfxFreeLibrary(hdll);</div>
<div>附<strong>microsoft visual Stdio
MSDN关于dll显式调用的相关说明</strong></div>
<div>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
// File</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">：</span> <span style="font-size: 9pt; font-family: 'Courier New';">
RUNTIME.C
</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
// A simple program that uses LoadLibrary and</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
// GetProcAddress to access myPuts from MYPUTS.DLL.
#include</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
typedef VOID (*MYPROC)(LPTSTR)</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
VOID main(VOID)</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
{ HINSTANCE hinstLib</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
&nbsp;<wbr> MYPROC ProcAdd</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
&nbsp;<wbr>&nbsp;<wbr>BOOL fFreeResult,
fRunTimeLinkSuccess = FALSE</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span> <span style="font-size: 9pt; font-family: 'Courier New';">
// Get a handle&nbsp;<wbr>&nbsp;<wbr>
to&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>the DLL
module.</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
&nbsp;<wbr>hinstLib =
LoadLibrary(&#8220;myputs&#8220;)</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span> <span style="font-size: 9pt; font-family: 'Courier New';">
// If the handle is valid, try to get the function
address.</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
if (hinstLib != NULL)</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
&nbsp;<wbr>{ ProcAdd = (MYPROC) GetProcAddress(hinstLib,
&#8220;myPuts&#8220;)</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span> <span style="font-size: 9pt; font-family: 'Courier New';">
// If the function address is valid, call the function.</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
if (NULL != ProcAdd) { fRunTimeLinkSuccess = TRUE</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
(ProcAdd) (&#8220;message via DLL function\n&#8220;)</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span> <span style="font-size: 9pt; font-family: 'Courier New';">
} // Free the DLL module. fFreeResult =
FreeLibrary(hinstLib)</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span> <span style="font-size: 9pt; font-family: 'Courier New';">
} // If unable to call the DLL function, use an
alternative.</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
&nbsp;<wbr>if (! fRunTimeLinkSuccess)</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
printf(&#8220;message via alternative method\n&#8220;)</span><span style="font-size: 9pt; font-family: 宋体;" xml:lang="ZH-CN" lang="ZH-CN">；</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: left;" align="left"><span style="font-size: 9pt; font-family: 'Courier New';">
&nbsp;<wbr>}</span></p>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/57428.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-29 16:09 <a href="http://www.cppblog.com/richardhe/articles/57428.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dll基础</title><link>http://www.cppblog.com/richardhe/articles/57427.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 29 Jul 2008 08:08:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/57427.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/57427.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/57427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/57427.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/57427.html</trackback:ping><description><![CDATA[自从微软推出第一个版本的Windows操作系统以来，动态链接库（DLL）一直是Wind <br>ows操作系统的基础。 <br>动态链接库通常都不能直接运行，也不能接收消息。它们是一些独立的文件，其中 <br>包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动 <br>态链接库中的函数时，它才发挥作用。 <br>Windows API中的所有函数都包含在DLL中。其中有3个最重要的DLL，Kernel32.dll <br>，它包含用于管理内存、进程和线程的各个函数；User32.dll，它包含用于执行用 <br>户界面任务（如窗口的创建和消息的传送）的各个函数；GDI32.dll，它包含用于画 <br>图和显示文本的各个函数。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;静态库和动态库 <br>静态库：函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库 <br>的情况下，在编译链接可执行文件时，链接器从库中复制这些函数和数据并把它们 <br>和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件)。 <br>在使用动态库的时候，往往提供两个文件：一个引入库和一个DLL。引入库包含被D <br>LL导出的函数和变量的符号名，DLL包含实际的函数和数据。在编译链接可执行文件 <br>时，只需要链接引入库，DLL中的函数代码和数据并不复制到可执行文件中，在运行 <br>的时候，再去加载DLL，访问DLL中导出的函数。 <br>使用动态链接库的好处 <br>可以采用多种编程语言来编写。 <br>增强产品的功能。 <br>提供二次开发的平台。 <br>简化项目管理。 <br>可以节省磁盘空间和内存。 <br>有助于资源的共享。 <br>有助于实现应用程序的本地化。 <br>动态链接库被多个进程访问 <br>动态链接库加载的两种方式 <br>预备知识 <br>：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：： <br>：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：： <br>：：：： <br>进程的虚拟地址空间： <br>&nbsp;在32为系统中，系统为没个进程分配2^32的地址空间 <br>具体可参看《windows核心编程》 <br>预处理命令： <br>没有什么可以说的了 <br>看看代码就明白了！！ <br>环境变量：（环境变量的概念我就不介绍了，具体的可以参看windows 核心编程， <br>上面有很详细的说明）把DLL放到当前任意的环境变量中就可以加载 <br>定义函数指针 <br>格式：typedef &nbsp;int (*proc)(int a,int b); <br>注意：proc是一个函数指针类型而不是一个变量 <br>然后我们可以用这个指针类型去定义变量 <br>Proc myproc;这里的myproc就是一个指针变量 <br>要是实在无聊 内心空虚 没事可做的话 可以去这个网站看看函数的指针http://uf <br>o.tyedu.com/study/programmer/language_C/200412/1472.html &nbsp; <br>函数的调用约定（可以不必了解，但是理解后可以让你理解DLL的调用更为深刻） <br>函数的调用约定：函数调用约定是函数调用者和被调用的函数体之间关于参数传递 <br>、返回值传递、堆栈清除、寄存器使用的一种约定; <br>&nbsp;&nbsp;&nbsp;它是需要二进制级别兼容的强约定,函数调用者和函数体如果使用不同的调用约 <br>定,将可能造成程序执行错误,必须把它看作是函数声明的一部分; <br>常见的函数调用约定： <br>VC6中的函数调用约定： <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;调用约定 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;堆栈清除 &nbsp;&nbsp;&nbsp;参数传递 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__cdecl &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;调用者 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从右到左,通过堆栈传递 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__stdcall &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;函数体 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从右到左,通过堆栈传递 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__fastcall &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;函数体 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从右到左,优先使用寄存器(ECX,EDX),然后 <br>使用堆栈 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thiscall &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;函数体 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this指针默认通过ECX传递,其它参数从右 <br>到左入栈 <br>__cdecl是C\C++的默认调用约定; VC的调用约定中并没有thiscall这个关键字,它是 <br>类成员函数默认调用约定; <br>C\C++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改; <br>默认调用约定一般能够通过编译器设置进行更改,如果你的代码依赖于调用约定,请 <br>明确指出需要使用的调用约定; <br>常见的函数调用约定中,只有cdecl约定需要调用者来清除堆栈; <br>C\C++中的函数支持参数数目不定的参数列表,比如printf函数;由于函数体不知道调 <br>用者在堆栈中压入了多少参数, <br>所以函数体不能方便的知道应该怎样清除堆栈,那么最好的办法就是把清除堆栈的责 <br>任交给调用者; <br>这应该就是cdecl调用约定存在的原因吧; <br>VB一般使用的是stdcall调用约定;(ps：有更强的保证吗) <br>Windows的API中,一般使用的是stdcall约定;(ps: 有更强的保证吗) <br>建议在不同语言间的调用中(如DLL)最好采用stdcall调用约定,因为它在语言间兼容 <br>性支持最好; <br>三:函数返回值传递方式 <br>&nbsp;&nbsp;其实，返回值的传递从处理上也可以想象为函数调用的一个out形参数； 函数返 <br>回值传递方式也是函数调用约定的一部分； <br>&nbsp;&nbsp;有返回值的函数返回时：一般int、指针等32bit数据值(包括32bit结构)通过ea <br>x传递，(bool,char通过al传递，short通过 ax传递),特别的__int64等64bit结构( <br>struct) 通过edx,eax两个寄存器来传递(同理：32bit整形在16bit环境中通过dx,a <br>x传递); 其他大小的结构(struct)返回时把其地址通过eax返回；(所以返回值类型 <br>不是1,2,4,8byte时，效率可能比较差) <br>&nbsp;&nbsp;参数和返回值传递中，引用方式的类型可以看作与传递指针方式相同； <br>&nbsp;&nbsp;float\double(包括Delphi中的extended)都是通过浮点寄存器st(0)返回； <br><br>具体的分析参看：http://blog.csdn.net/avalonbbs/archive/2004/12/25/229300 <br>.aspx <br>：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：： <br>：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：：： <br>：：：：：：： <br><br><br><br><br>隐式链接 <br>本文现在对隐式链接不作具体的说明，只是做一个大概的介绍（下次再做具体的说 <br>明）.当进程运行的时候，所有的相关的DLL都被加载到内存，然后映射到进程的地 <br>址空间，当一个进程要调用很多个DLL的时候，这种方法就显得特别浪费内存，所以 <br>在加载很多个DLL的时候，最好用显示加载的方式 <br>在调用DLL里面的函数时候 <br>要用extern 声明是外部变量 <br>比如 extern int add(int num1,int num2); <br>但是还应该注意的就是：在编译DLL时，要把编译的LIB文件放到执行文件的目录下 <br>，并且在编译执行文件的时候要连接LIB文件。 <br>在写DLL的时候要导出的函数也就是在能被外部程序调用的函数前面加上 <br>一般大型项目在开发DLL中，要进行预定义声明的 <br><br>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝ <br>＝＝ <br>在定义DLL的时候要定义导出函数就要在该函数前面加__declspec(DLLexport)时， <br>C++编译器为了支持函数的重载会进行函数名字改编，当可执行模块执行该函数时由 <br>于找不到该函数的名字，于是调用就会出现错误！当使用extern &#8220;C&#8221;时就可以告 <br>诉编译器不必修改函数名和变量名。这样就可以用C++或C编译器程序调用该函数。 <br><br>以上操作只有在VC++创建的的可执行模块来调用该DLL，如果使用其他的编译器的模 <br>块来调用该DLL，就需要执行一些额外的操作。 <br>C编译在进行编译的时候也会进行名字的改编，当函数使用_stdcall(WINAPI)调用 <br>规则时，MS编译器就会改编函数的名称。 <br>比如：__declspec(DLLexport) &nbsp;LONG __stdcall &nbsp;Proc(int a ,int b); <br>编译器会改编为__Proc@8 <br>因此 当非C++或非C编译器调用该DLL中的函数Proc时，就会出现找不到函数的情况 <br>。 <br>这样我们就可以定义DEF文件来解决，并且在DEF文件加上下面的EXPORTS： <br>EXPORTS <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Proc <br>Def模块执行原理：当连接程序分析这个DEF文件时，它发现Proc和__Proc@8都被输 <br>出，由于这两个函数是相互匹配的，因此连接程序使用Proc来输出该函数，根本不 <br>使用__Proc@8来输出函数名 <br>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝ <br>＝＝＝ <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><br><br><br><br>下面是def的具体使用方法 <br><br>------------------------------------------------------------------------ <br>----------------------------------------------模块定义文件(.DEF)是一个或 <br>多个用于描述DLL属性的模块语句组成的文本文件，每个DEF文件至少必须包含以下 <br>模块定义语句： <br>* 第一个语句必须是LIBRARY语句，指出DLL的名字； <br>* EXPORTS语句列出被导出函数的名字；将要输出的函数修饰名罗列在EXPORTS之下 <br>，这 <br>个名字必须与定义函数的名字完全一致，如此就得到一个没有任何修饰的函数名了 <br>。 <br>* 可以使用DESCRIPTION语句描述DLL的用途(此句可选)； <br>* ";"对一行进行注释(可选)。 <br>------------------------------------------------------------------------ <br>---------------------------------------------- <br><br><br>//////////////////////////////////////////////////////////////////////// <br>//////////////////////////////////////////////////////////////////////// <br>dlltest.h <br>#ifdef DLL1_API <br>#else <br>#define DLL1_API extern "C" _declspec(dllimport) <br>#endif <br><br>DLL1_API int _stdcall add(int a,int b); <br>DLL1_API int _stdcall subtract(int a,int b); <br>//////////////////////////////////////////////////////////////////////// <br>////////////////////////////////////////////////////////////////////// <br><br><br>\\\\\\\\\\\\\\\\\\ <br>\\\\\\\\\\\\\\\\\\// <br>dlltest.cpp <br>#define DLL1_API extern "C" _declspec(dllexport) <br>#include "Dll1.h" <br>#include &lt;stdio.h&gt; <br>int _stdcall add(int a,int b) <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;return a+b; <br>} <br><br>int _stdcall subtract(int a,int b) <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;return a-b; <br>} <br>\\\\\\\\\\\\\\\\\\ <br>\\\\\\\\\\\\\\\\\\ <br><br>//////////////////////////////////////////////////////////////////////// <br>//////////////////////////////////////////////////////////////////// <br>// def文件 <br>LIBRARY dlltest <br>EXPORTS <br>add <br>subtract <br>//////////////////////////////////////////////////////////////////////// <br>//////////////////////////////////////////////////////////////////// <br><br>有了上面的那些文件之后就可以在如何地方调用这些函数了 <br><br>void CDllTestDlg::OnBtnSubtract() <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;// TODO: Add your control notification handler code here <br>&nbsp;&nbsp;&nbsp;&nbsp;CString str; <br>&nbsp;&nbsp;&nbsp;&nbsp;str.Format("5-3=%d",subtract(5,3)); <br>&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(str); <br>} <br><br>void CDllTestDlg::OnBtnOutput() <br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;// TODO: Add your control notification handler code here <br>&nbsp;&nbsp;&nbsp;&nbsp;Point pt; <br>&nbsp;&nbsp;&nbsp;&nbsp;pt.output(5,3); <br>}下面具体介绍显示加载 <br>显示加载 <br>VC++编译器在编译DLL的时候函数会发生名字改编；主要在非C++环境中就不能识别 <br>该函数了，所以这里应该定义模块文件类型DEF，主要就方便了非C++程序可以调用 <br>该DLL里面的函数 <br>再使用显示加载前必须要注意的是名字的改编问题，因为再动态加载中名字改编后 <br>在加载就得不原来的函数名字了，这样加载就会失败。但是可以用另外一种方法加 <br>载：MSDN上对GetProAddress中的第二个参数是这样说明的Pointer to a null-ter <br>minated string that specifies the function or variable name, or the func <br>tion's ordinal value.也就是说可以使用函数的序号来调用该函数，具体使用方法 <br>是ProcAdd = (MYPROC) GetProcAddress(hinstLib, MakeIntResource(i)); (i代表 <br>函数在DLL中的序号，可以用DUMPBIN工具查看)，但是一般的都不用这种转换序号的 <br>方式来取得函数的地址，因为这样非常的不直观！下面就用模块定义文件（DEF）来 <br>避免DLL中函数的名字的改编问题 <br><br><br><br><br><br>显示加载DLL <br>//MSDN上的对DLL进程显示加载的DEMO <br>Using Run-Time Dynamic Linking <br>You can use the same DLL in both load-time and run-time dynamic linking. <br>The following example uses the LoadLibrary function to get a handle to <br>the Myputs DLL (see Creating a Simple Dynamic-Link Library). If LoadLibr <br>ary succeeds, the program uses the returned handle in the GetProcAddress <br>function to get the address of the DLL's myPuts function. After calling <br>the DLL function, the program calls the FreeLibrary function to unload <br>the DLL. <br>Because the program uses run-time dynamic linking, it is not necessary t <br>o link the module with an import library for the DLL. <br>This example illustrates an important difference between run-time and lo <br>ad-time dynamic linking. If the DLL is not available, the application us <br>ing load-time dynamic linking must simply terminate. The run-time dynami <br>c linking example, however, can respond to the error. <br>// A simple program that uses LoadLibrary and <br>// GetProcAddress to access myPuts from Myputs.dll. <br><br>#include &lt;stdio.h&gt; <br>#include &lt;windows.h&gt; <br>typedef int (*MYPROC)(LPTSTR); <br>VOID main(VOID) <br>{ <br>&nbsp;&nbsp;&nbsp;HINSTANCE hinstLib; <br>&nbsp;&nbsp;&nbsp;MYPROC ProcAdd; <br>&nbsp;&nbsp;&nbsp;BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; <br>&nbsp;// Get a handle to the DLL module. <br>hinstLib = LoadLibrary(TEXT("DllTest")); <br>// If the handle is valid, try to get the function address. <br>if (hinstLib != NULL) <br>&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProcAdd = (MYPROC) GetProcAddress(hinstLib, TEXT("Proc")); <br>// If the function address is valid, call the function. <br>&nbsp;if (NULL != ProcAdd) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fRunTimeLinkSuccess = TRUE; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ProcAdd) (TEXT("Message via DLL function\n")); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;// Free the DLL module. <br>fFreeResult = FreeLibrary(hinstLib); <br>&nbsp;&nbsp;&nbsp;} <br>&nbsp;// If unable to call the DLL function, use an alternative. <br>if (! fRunTimeLinkSuccess) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("Message via alternative method\n"); <br>} <br><br>对以上的几个函数作一些必要的说明： <br>LoadLibrary：加载指定的DLL，加载方式是先在当前目录中查找，如果找不到再再 <br>环境变量目录下查找； <br>还是看MSDN上的说明 <br>The LoadLibrary function maps the specified executable module into the a <br>ddress space of the calling process. <br>HMODULE LoadLibrary( <br>&nbsp;LPCTSTR lpFileName <br>); <br>Parameters <br>lpFileName <br>[in] Pointer to a null-terminated string that names the executable modul <br>e (either a .dll or .exe file). The name specified is the file name of t <br>he module and is not related to the name stored in the library module it <br>self, as specified by the LIBRARY keyword in the module-definition (.def <br>) file. <br><br>GetProcAddress：是取得已知的DLL中的函数，返回指定函数的地址 <br>MSDN上的说明 <br>This function returns the address of the specified exported DLL function <br>. <br>FARPROC GetProcAddress( <br>&nbsp;HMODULE hModule, <br>&nbsp;LPCWSTR lpProcName <br>); <br>Parameters <br>hModule <br>[in] Handle to the DLL module that contains the function. <br>The LoadLibrary or GetModuleHandle function returns this handle. <br>lpProcName <br>[out] Pointer to a null-terminated string containing the function name, <br>or specifies the function's ordinal value. <br>If this parameter is an ordinal value, it must be in the low-order word; <br>the high-order word must be zero. <br>The lpProcName parameter must be in Unicode. <br>Remark: <br>The GetProcAddress function is used to retrieve addresses of exported fu <br>nctions in DLLs. <br>The spelling and case of the function name pointed to by lpProcName must <br>be identical to that in the EXPORTS statement of the source DLL's modul <br>e-definition (.def) file. <br>The exported names of Win32 APIs might differ from the names you use whe <br>n calling these functions in your code. This difference is hidden by mac <br>ros used in the SDK header files.<img src ="http://www.cppblog.com/richardhe/aggbug/57427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-29 16:08 <a href="http://www.cppblog.com/richardhe/articles/57427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>服务器公共库开发--读取ini文件格式的类</title><link>http://www.cppblog.com/richardhe/articles/57405.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 29 Jul 2008 03:50:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/57405.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/57405.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/57405.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/57405.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/57405.html</trackback:ping><description><![CDATA[<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#ifndef&nbsp;__CONFIG_H__<br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;__CONFIG_H__</span><span style="color: #000000;"><br><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">map</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">using</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">namespace</span><span style="color: #000000;">&nbsp;std;<br><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CConfig<br>{<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;CConfig();<br>&nbsp;&nbsp;&nbsp;&nbsp;CConfig(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFileName);<br>&nbsp;&nbsp;&nbsp;&nbsp;CConfig(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strFileName);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">~</span><span style="color: #000000;">CConfig();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Init();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Init(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFileName);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Init(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strFileName);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Dump();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;ReadItem(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strSection,&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strKey,&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strValue);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;WriteItem(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strSection,&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strKey,&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strValue);<br><br></span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;LoadFile();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;WriteFile();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;ReadLine(FILE</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFile,&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strLine);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;TrimString(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strToken);<br></span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;m_strFileName;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;map</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;ConfigType;<br>&nbsp;&nbsp;&nbsp;&nbsp;map</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">,&nbsp;ConfigType</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;m_mSec2Config;<br>};<br><br></span><span style="color: #0000ff;">#endif</span><span style="color: #000000;">&nbsp;/*&nbsp;__CONFIG_H__&nbsp;*/</span><span style="color: #000000;"><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008000;">/*</span><span style="color: #008000;">*******************************************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;created:&nbsp;&nbsp;&nbsp;&nbsp;2008/07/28<br>&nbsp;&nbsp;&nbsp;&nbsp;filename:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config.h<br>&nbsp;&nbsp;&nbsp;&nbsp;author:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Lichuang<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;purpose:&nbsp;&nbsp;&nbsp;&nbsp;封装读取ini格式的配置文件操作<br>********************************************************************</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br><br>#include&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">config.h</span><span style="color: #000000;">"</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">comdef.h</span><span style="color: #000000;">"</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">iostream</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br>CConfig::CConfig()<br>{<br>}<br><br>CConfig::CConfig(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFile)<br>&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;m_strFileName(pFile)<br>{<br>}<br><br>CConfig::CConfig(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strFile)<br>&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;m_strFileName(strFile)<br>{<br>}<br><br>CConfig::</span><span style="color: #000000;">~</span><span style="color: #000000;">CConfig()<br>{<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::Init(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFileName)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;m_strFileName&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileName;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;LoadFile();<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::Init(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strFileName)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;m_strFileName&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strFileName;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;LoadFile();<br>}<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::Init()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;LoadFile();<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::Dump()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;map</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">,&nbsp;ConfigType</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator&nbsp;tSecIter1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;m_mSec2Config.begin(),&nbsp;tSecIter2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;m_mSec2Config.end();<br>&nbsp;&nbsp;&nbsp;&nbsp;ConfigType::iterator&nbsp;tConfigTypeIter1,&nbsp;tConfigTypeIter2;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(tSecIter1&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;tSecIter2)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">[</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;tSecIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">first&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">]</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tConfigTypeIter1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tSecIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second.begin(),&nbsp;tConfigTypeIter2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tSecIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second.end();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(tConfigTypeIter1&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;tConfigTypeIter2)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;tConfigTypeIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">first&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;tConfigTypeIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">tConfigTypeIter1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">tSecIter1;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::ReadItem(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strSection,&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strKey,&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strValue)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">m_mSec2Config.count(strSection))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;ConfigType</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;tConfigType&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;m_mSec2Config[strSection];<br>&nbsp;&nbsp;&nbsp;&nbsp;strValue&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tConfigType[strKey];<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;(strValue.empty())&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;:&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::WriteItem(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strSection,&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strKey,&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strValue)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ConfigType</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;tConfigType&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;m_mSec2Config[strSection];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(tConfigType.count(strKey))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;tConfigType[strKey]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strValue;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;WriteFile();<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::LoadFile()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;FILE</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFile;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(NULL&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;(pFile&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::fopen(m_strFileName.c_str(),&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">r</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;strLine,&nbsp;strSection;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;strKey,&nbsp;strValue;<br>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;nPos,&nbsp;nEndPos;<br>&nbsp;&nbsp;&nbsp;&nbsp;ConfigType&nbsp;tConfigType;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;ReadLine(pFile,&nbsp;strLine))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">::npos&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;(nPos&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strLine.find_first_of(</span><span style="color: #000000;">"</span><span style="color: #000000;">[</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">::npos&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;(nEndPos&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strLine.find_first_of(</span><span style="color: #000000;">"</span><span style="color: #000000;">]</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<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;::fclose(pFile);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strSection&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strLine.substr(nPos&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;nEndPos&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;nPos&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;TrimString(strSection))<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;::fclose(pFile);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<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;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">::npos&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;(nPos&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strLine.find_first_of(</span><span style="color: #000000;">"</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strKey&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strLine.substr(</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;nPos);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strValue&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strLine.substr(nPos&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;TrimString(strKey)&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;TrimString(strValue)&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;strSection.empty())<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;::fclose(pFile);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_mSec2Config[strSection][strKey]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strValue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;::fclose(pFile);<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::WriteFile()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;FILE</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFile;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(NULL&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;(pFile&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::fopen(m_strFileName.c_str(),&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">w</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;map</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">,&nbsp;ConfigType</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator&nbsp;tSecIter1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;m_mSec2Config.begin(),&nbsp;tSecIter2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;m_mSec2Config.end();<br>&nbsp;&nbsp;&nbsp;&nbsp;ConfigType::iterator&nbsp;tConfigTypeIter1,&nbsp;tConfigTypeIter2;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;strSection,&nbsp;strConfig;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(tSecIter1&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;tSecIter2)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strSection&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">[</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;tSecIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">first&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">]\n</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::fwrite(strSection.c_str(),&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(</span><span style="color: #0000ff;">char</span><span style="color: #000000;">),&nbsp;strSection.length(),&nbsp;pFile);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tConfigTypeIter1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tSecIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second.begin(),&nbsp;tConfigTypeIter2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tSecIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second.end();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(tConfigTypeIter1&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;tConfigTypeIter2)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strConfig&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tConfigTypeIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">first&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;tConfigTypeIter1</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">\n</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::fwrite(strConfig.c_str(),&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(</span><span style="color: #0000ff;">char</span><span style="color: #000000;">),&nbsp;strConfig.length(),&nbsp;pFile);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">tConfigTypeIter1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::fwrite(</span><span style="color: #000000;">"</span><span style="color: #000000;">\n</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(</span><span style="color: #0000ff;">char</span><span style="color: #000000;">),&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;pFile);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">tSecIter1;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;::fclose(pFile);<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::ReadLine(FILE</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pFile,&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strLine)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;szBuff[BUFFER_LEN];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;nLen;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(NULL&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;::fgets(szBuff,&nbsp;BUFFER_LEN,&nbsp;pFile))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;(nLen&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::strlen(szBuff)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">true</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;szBuff[nLen&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">'</span><span style="color: #000000;">\0</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;strLine&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;szBuff;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;CConfig::TrimString(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;strToken)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(strToken.empty())<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;nPos&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strToken.find_first_not_of(</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;\t</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;nEndPos&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strToken.find_last_not_of(</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;\t</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;strToken&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;strToken.substr(nPos,&nbsp;nEndPos&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;nPos&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;(strToken.empty())&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;:&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br>//实现主要采用STL,&nbsp;实现了ini格式文件的读,写,已经打印文件信息等功能,暂时觉得这些功能已经够用了,以后有需要再进行添加.应该还少了一个宏BUFFER_LEN的定义,这个宏在一个公用的头文件//中定义,如果你想试用这个类,可以自行进行定义,我默认定义为1024字节大小.</span></div>
<br></span></div>
<br><img src ="http://www.cppblog.com/richardhe/aggbug/57405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-29 11:50 <a href="http://www.cppblog.com/richardhe/articles/57405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>std::string 与 char 类型的相互转换</title><link>http://www.cppblog.com/richardhe/articles/57154.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Fri, 25 Jul 2008 08:41:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/57154.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/57154.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/57154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/57154.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/57154.html</trackback:ping><description><![CDATA[&nbsp;//string 转换为 char 型<br>&nbsp;&nbsp;char* str = strdup ( SendData.strSql.c_str() );<br>&nbsp;&nbsp;cout &lt;&lt; str &lt;&lt; endl;
<p>&nbsp;&nbsp;char 转换为 string 型<br>&nbsp;&nbsp;char* str = "char 转换为 string 型";<br>&nbsp;&nbsp;SendData.strSql = str;<br><br>//SendData.strSql 为std::string型</p>
<table id="Calendar1_entryCal" class="Cal" title="Calendar" style="border-style: solid; border-width: 1px; border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="CalWeekendDay" style="width: 14%;" align="center"><br></td>
        </tr>
        <tr>
            <td class="CalWeekendDay" style="width: 14%;" align="center">20</td>
            <td style="width: 14%;" align="center">21</td>
            <td style="width: 14%;" align="center">22</td>
            <td style="width: 14%;" align="center">23</td>
            <td style="width: 14%;" align="center">24</td>
            <td class="CalTodayDay" style="width: 14%;" align="center">25</td>
            <td class="CalWeekendDay" style="width: 14%;" align="center">26</td>
        </tr>
        <tr>
            <td class="CalWeekendDay" style="width: 14%;" align="center">27</td>
            <td style="width: 14%;" align="center">28</td>
            <td style="width: 14%;" align="center">29</td>
            <td style="width: 14%;" align="center">30</td>
            <td style="width: 14%;" align="center">31</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">1</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">2</td>
        </tr>
        <tr>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">3</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">4</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">5</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">6</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">7</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">8</td>
            <td class="CalOtherMonthDay" style="width: 14%;" align="center">9</td>
        </tr>
    </tbody>
</table>
<div class="listtitle">统计</div>
<ul class="list">
    <li class="listitem">随笔 - 12
    </li>
    <li class="listitem">文章 - 5
    </li>
    <li class="listitem">评论 - 22
    </li>
    <li class="listitem">引用 - 0
    </li>
</ul>
<h3>常用链接</h3>
<ul>
    <li><a  href="http://www.cppblog.com/klsmlzm/MyPosts.html" id="SingleColumn1_ctl00_repeaterLinks_ctl01_lnkLinkItem">我的随笔</a></li>
    <li><a  href="http://www.cppblog.com/klsmlzm/MyComments.html" id="SingleColumn1_ctl00_repeaterLinks_ctl02_lnkLinkItem">我的评论</a></li>
    <li><a  href="http://www.cppblog.com/klsmlzm/OtherPosts.html" id="SingleColumn1_ctl00_repeaterLinks_ctl03_lnkLinkItem">我参与的随笔</a></li>
</ul>
<h3>留言簿<span style="font-size: 11px; font-weight: normal;">(8)</span></h3>
<ul>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/Contact.aspx?id=1" id="SingleColumn1__3168b46_lnkMessages">给我留言</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/default.aspx?opt=msg" id="SingleColumn1__3168b46_lnkPublicMsgView">查看公开留言</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/admin/MyMessages.aspx" id="SingleColumn1__3168b46_lnkPrivateMsgView">查看私人留言</a>
    </li>
</ul>
<h1 class="listtitle">随笔分类</h1>
<ul class="list">
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/category/577.html" id="SingleColumn1_Categories_CatList_ctl00_LinkList_ctl01_Link" class="listitem">C++学习资料(4)</a>  <a  href="http://www.cppblog.com/klsmlzm/category/577.html/rss" id="SingleColumn1_Categories_CatList_ctl00_LinkList_ctl01_RssLink" title="Subscribe to C++学习资料(4)">(rss)</a></li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/category/506.html" id="SingleColumn1_Categories_CatList_ctl00_LinkList_ctl02_Link" class="listitem">ICE FOR VC++6.0(4)</a>  <a  href="http://www.cppblog.com/klsmlzm/category/506.html/rss" id="SingleColumn1_Categories_CatList_ctl00_LinkList_ctl02_RssLink" title="Subscribe to ICE FOR VC++6.0(4)">(rss)</a></li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/category/558.html" id="SingleColumn1_Categories_CatList_ctl00_LinkList_ctl03_Link" class="listitem">ICE学习资料(4)</a>  <a  href="http://www.cppblog.com/klsmlzm/category/558.html/rss" id="SingleColumn1_Categories_CatList_ctl00_LinkList_ctl03_RssLink" title="Subscribe to ICE学习资料(4)">(rss)</a></li>
</ul>
<h1 class="listtitle">随笔档案</h1>
<ul class="list">
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archive/2006/11.html" id="SingleColumn1_Categories_CatList_ctl01_LinkList_ctl01_Link" class="listitem">2006年11月 (1)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archive/2006/09.html" id="SingleColumn1_Categories_CatList_ctl01_LinkList_ctl02_Link" class="listitem">2006年9月 (1)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archive/2006/04.html" id="SingleColumn1_Categories_CatList_ctl01_LinkList_ctl03_Link" class="listitem">2006年4月 (2)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archive/2006/02.html" id="SingleColumn1_Categories_CatList_ctl01_LinkList_ctl04_Link" class="listitem">2006年2月 (2)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archive/2005/12.html" id="SingleColumn1_Categories_CatList_ctl01_LinkList_ctl05_Link" class="listitem">2005年12月 (6)</a>  </li>
</ul>
<h1 class="listtitle">文章分类</h1>
<ul class="list">
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/category/545.html" id="SingleColumn1_Categories_CatList_ctl02_LinkList_ctl01_Link" class="listitem">ICE中间件技术(3)</a>  <a  href="http://www.cppblog.com/klsmlzm/category/545.html/rss" id="SingleColumn1_Categories_CatList_ctl02_LinkList_ctl01_RssLink" title="Subscribe to ICE中间件技术(3)">(rss)</a></li>
</ul>
<h1 class="listtitle">文章档案</h1>
<ul class="list">
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archives/2007/09.html" id="SingleColumn1_Categories_CatList_ctl03_LinkList_ctl01_Link" class="listitem">2007年9月 (1)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archives/2006/09.html" id="SingleColumn1_Categories_CatList_ctl03_LinkList_ctl02_Link" class="listitem">2006年9月 (1)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archives/2006/04.html" id="SingleColumn1_Categories_CatList_ctl03_LinkList_ctl03_Link" class="listitem">2006年4月 (1)</a>  </li>
    <li class="listitem"><a  href="http://www.cppblog.com/klsmlzm/archives/2005/12.html" id="SingleColumn1_Categories_CatList_ctl03_LinkList_ctl04_Link" class="listitem">2005年12月 (2)</a>  </li>
</ul>
<script language="JavaScript">
function SearchGoogle(key,evt,site)
{
if(evt.keyCode==13 || evt.keyCode==0 || evt.type =='click')
{
key.focus();
var keystr = encodeURIComponent(key.value);
url = "http://www.google.com/search?q=";
url = url+keystr;
url += "&ie=UTF-8&oe=GB2312&hl=zh-CN&domains="+site+"&sitesearch="+site;
window.location=url;
return false;
}
}
</script>
<h3>搜索</h3>
<ul>
    <li>
    <br></li>
    <li><input style="width: 130px;" name="q" id="q" onkeydown="return searchgoogle(document.getelementbyid('q'),event,'www.cppblog.com/klsmlzm')" type="text">&nbsp;<input onclick="SearchGoogle(document.getElementById('q'),event,'www.cppblog.com/klsmlzm')" value="搜索" name="sa" type="button">
    </li>
</ul>
<h3>最新评论
<a  href="http://www.cppblog.com/klsmlzm/CommentsRSS.aspx" id="SingleColumn1__2eb9fc2_RSSHyperlink1"><img  src="http://www.cppblog.com/images/xml.gif" style="border-width: 0px;"></a></h3>
<div class="RecentComment">
<ul>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2008/07/17/1794.html#56403" id="SingleColumn1__2eb9fc2_CommentList_ctl01_Hyperlink1">1.&nbsp;re: std::string 与 char 类型的相互转换</a>
    </li>
    <li>
    <br>char* str = strdup ( SendData.strSql.c_str() );太好了，可以将const *转化为char *
    </li>
    <li style="text-align: right; margin-right: 4px;">
    --luyu</li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2008/06/12/1794.html#53016" id="SingleColumn1__2eb9fc2_CommentList_ctl02_Hyperlink1">2.&nbsp;re: std::string 与 char 类型的相互转换</a>
    </li>
    <li>
    不过在C++中最好不要用char 型变量,在大型项目中很容易引起内在溢出或者指针越界,应该尽量用string
    </li>
    <li style="text-align: right; margin-right: 4px;">
    --企业即时通讯</li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2007/12/24/5522.html#39510" id="SingleColumn1__2eb9fc2_CommentList_ctl03_Hyperlink1">3.&nbsp;re: C++编程中，利用WINDOWS API获得系统状态信息[CPU占用率，硬盘使用情况，内存使用情况]</a>
    </li>
    <li>
    GetWinSysState.h这个找不到怎么办
    <br>
    </li>
    <li style="text-align: right; margin-right: 4px;">
    --SHI</li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2007/10/15/15737.html#34255" id="SingleColumn1__2eb9fc2_CommentList_ctl04_Hyperlink1">4.&nbsp;re: CVS服务器的相关配置及使用[ Server of CVS Configure and Usage for linux]---注,此教程是"火山哥"提供的:-)[未登录]</a>
    </li>
    <li>
    评论内容较长,点击标题查看
    </li>
    <li style="text-align: right; margin-right: 4px;">
    --猪猪</li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2007/07/09/15737.html#27731" id="SingleColumn1__2eb9fc2_CommentList_ctl05_Hyperlink1">5.&nbsp;re: CVS服务器的相关配置及使用[ Server of CVS Configure and Usage for linux]---注,此教程是"火山哥"提供的:-)[未登录]</a>
    </li>
    <li>
    评论内容较长,点击标题查看
    </li>
    <li style="text-align: right; margin-right: 4px;">
    --牵牛散步</li>
</ul>
</div>
<h3>阅读排行榜</h3>
<div class="RecentComment">
<ul>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx" id="SingleColumn1__190148_TopList_ctl01_Hyperlink1">1.&nbsp;std::string 与 char 类型的相互转换(8563)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2006/04/14/5522.aspx" id="SingleColumn1__190148_TopList_ctl02_Hyperlink1">2.&nbsp;C++编程中，利用WINDOWS API获得系统状态信息[CPU占用率，硬盘使用情况，内存使用情况](1861)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1710.aspx" id="SingleColumn1__190148_TopList_ctl03_Hyperlink1">3.&nbsp;转载:学习ICE 3.0--准备工作(1646)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1712.aspx" id="SingleColumn1__190148_TopList_ctl04_Hyperlink1">4.&nbsp;转载:学习ICE 3.0--Slice语言(1573)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1711.aspx" id="SingleColumn1__190148_TopList_ctl05_Hyperlink1">5.&nbsp;转载:学习ICE 3.0--初读代码(1539)</a>
    </li>
</ul>
</div>
<h3>评论排行榜</h3>
<div class="RecentComment">
<ul>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx" id="SingleColumn1__142dbd4_TopList_ctl01_Hyperlink1">1.&nbsp;std::string 与 char 类型的相互转换(5)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1710.aspx" id="SingleColumn1__142dbd4_TopList_ctl02_Hyperlink1">2.&nbsp;转载:学习ICE 3.0--准备工作(5)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2006/09/18/12686.aspx" id="SingleColumn1__142dbd4_TopList_ctl03_Hyperlink1">3.&nbsp;在VC++6.0 SP6 下配置ICE工程[DEBUG版本]--config ice project(debug) for vc++6.0 with sp6(4)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2006/11/28/15737.aspx" id="SingleColumn1__142dbd4_TopList_ctl04_Hyperlink1">4.&nbsp;CVS服务器的相关配置及使用[ Server of CVS Configure and Usage for linux]---注,此教程是"火山哥"提供的:-)(3)</a>
    </li>
    <li>
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/09/1651.aspx" id="SingleColumn1__142dbd4_TopList_ctl05_Hyperlink1">5.&nbsp;在ICE客户端中如何定位服务器端的位置(即如何寻找代理)(3)</a>
    </li>
</ul>
</div>
<div class="spacer">&nbsp;</div>
<div class="singlepost">
<div class="posttitle">
<a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.html" id="viewpost1_TitleUrl" class="singleposttitle">std::string 与 char 类型的相互转换</a>
</div>
<p>&nbsp;&nbsp;//string 转换为 char 型<br>&nbsp;&nbsp;char* str = strdup ( SendData.strSql.c_str() );<br>&nbsp;&nbsp;cout &lt;&lt; str &lt;&lt; endl;</p>
<p>&nbsp;&nbsp;char 转换为 string 型<br>&nbsp;&nbsp;char* str = "char 转换为 string 型";<br>&nbsp;&nbsp;SendData.strSql = str;<br><br>//SendData.strSql 为std::string型</p>
<div class="itemdesc">
posted on 2005-12-15 15:27 <a  href="http://www.cppblog.com/klsmlzm/">牵牛散步</a> 阅读(8565) <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#Post">评论(5)</a> &nbsp;<a  href="http://www.cppblog.com/klsmlzm/admin/EditPosts.aspx?postid=1794">编辑</a>&nbsp;<a  href="http://www.cppblog.com/klsmlzm/AddToFavorite.aspx?id=1794">收藏</a> <a  href="http://www.cppblog.com/klsmlzm/services/trackbacks/1794.aspx">引用</a>  所属分类: <a  href="http://www.cppblog.com/klsmlzm/category/506.html">ICE FOR VC++6.0</a>
</div>
</div>
<img  src="http://www.cppblog.com/klsmlzm/aggbug/1794.html?webview=1" width="1" height="1">
<!--
<rdf:rdf xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:description
rdf:about="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.html"
dc:identifier="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.html"
dc:title="std::string 与 char 类型的相互转换"
trackback:ping="http://www.cppblog.com/klsmlzm/services/trackbacks/1794.aspx" />
</rdf:rdf>
-->
<script type="text/javascript">
//<![cdata[
sys.webforms.pagerequestmanager._initialize('ajaxholder$scriptmanager1', document.getElementById('Form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tAjaxHolder$UpdatePanel1'], [], [], 90);
//]]&gt;
</script>
<a name="pagedcomment"></a>
<a name="评论">
</a>
<a name="评论">	</a>
<div class="moreinfotitle">
<a name="评论">		Comments
</a></div>
<a name="评论">
</a><a name="评论">
</a>
<ul class="morelist">
    <li class="morelistitem">
    <a name="评论">				</a>
    <div class="moreinfotitle">
    <a name="评论">					</a><a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#8664" title="permalink: re: std::string 与 char 类型的相互转换">#</a>&nbsp;<a name="8664"></a>re: std::string 与 char 类型的相互转换
    </div>
    <a id="AjaxHolder_Comments_CommentList_ctl01_NameLink" target="_blank">晕</a><br>
    Posted @ 2006-06-17 17:18<br>
    没有这个函数吧！大爷！！！我急啊！&nbsp;&nbsp;<a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#post" onclick="'return" SetReplyAuhor("晕")'>回复</a>&nbsp;&nbsp;<a  href="http://www.cppblog.com/comment?author=%e6%99%95" title="查看该作者发表过的评论" target="_blank">更多评论</a>
    &nbsp;&nbsp;
    </li>
    <li class="morelistitem">
    <div class="moreinfotitle">
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#10946" title="permalink: re: std::string 与 char 类型的相互转换">#</a>&nbsp;<a name="10946"></a>re: std::string 与 char 类型的相互转换
    </div>
    <a id="AjaxHolder_Comments_CommentList_ctl02_NameLink" target="_blank">偶尔看到</a><br>
    Posted @ 2006-08-08 00:16<br>
    补充一点，用完str后记得用free把内存释放，strdup会用malloc分配内存&nbsp;&nbsp;<a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#post" onclick="'return" SetReplyAuhor("偶尔看到")'>回复</a>&nbsp;&nbsp;<a  href="http://www.cppblog.com/comment?author=%e5%81%b6%e5%b0%94%e7%9c%8b%e5%88%b0" title="查看该作者发表过的评论" target="_blank">更多评论</a>
    &nbsp;&nbsp;
    </li>
    <li class="morelistitem">
    <div class="moreinfotitle">
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#11167" title="permalink: re: std::string 与 char 类型的相互转换">#</a>&nbsp;<a name="11167"></a>re: std::string 与 char 类型的相互转换
    </div>
    <a id="AjaxHolder_Comments_CommentList_ctl03_NameLink" target="_blank">haha</a><br>
    Posted @ 2006-08-13 01:42<br>
    @偶尔看到
    <br>对头,应该在最后还加个这个语句
    <br>delete str;//str即通过这个char* str = strdup ( SendData.strSql.c_str() );
    <br>得到的指针
    <br>
    <br>不过在C++中最好不要用char 型变量,在大型项目中很容易引起内在溢出或者指针越界,应该尽量用string
    <br>&nbsp;&nbsp;<a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#post" onclick="'return" SetReplyAuhor("haha")'>回复</a>&nbsp;&nbsp;<a  href="http://www.cppblog.com/comment?author=haha" title="查看该作者发表过的评论" target="_blank">更多评论</a>
    &nbsp;&nbsp;
    </li>
    <li class="morelistitem">
    <div class="moreinfotitle">
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#53016" title="permalink: re: std::string 与 char 类型的相互转换">#</a>&nbsp;<a name="53016"></a>re: std::string 与 char 类型的相互转换
    </div>
    <a  href="http://www.freeeim.com/" id="AjaxHolder_Comments_CommentList_ctl04_NameLink" target="_blank">企业即时通讯</a><br>
    Posted @ 2008-06-12 15:03<br>
    不过在C++中最好不要用char 型变量,在大型项目中很容易引起内在溢出或者指针越界,应该尽量用string &nbsp;&nbsp;<a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#post" onclick="'return" SetReplyAuhor("企业即时通讯")'>回复</a>&nbsp;&nbsp;<a  href="http://www.cppblog.com/comment?author=%e4%bc%81%e4%b8%9a%e5%8d%b3%e6%97%b6%e9%80%9a%e8%ae%af" title="查看该作者发表过的评论" target="_blank">更多评论</a>
    &nbsp;&nbsp;
    </li>
    <li class="morelistitem">
    <div class="moreinfotitle">
    <a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#56403" title="permalink: re: std::string 与 char 类型的相互转换">#</a>&nbsp;<a name="56403"></a>re: std::string 与 char 类型的相互转换<a name="Post"></a>
    </div>
    <a id="AjaxHolder_Comments_CommentList_ctl05_NameLink" target="_blank">luyu</a><br>
    Posted @ 2008-07-17 11:16<br>
    <br>char* str = strdup ( SendData.strSql.c_str() );太好了，可以将const *转化为char *&nbsp;&nbsp;<a  href="http://www.cppblog.com/klsmlzm/archive/2005/12/15/1794.aspx#post" onclick="'return" SetReplyAuhor("luyu")'>回复</a>&nbsp;&nbsp;<a  href="http://www.cppblog.com/comment?author=luyu" title="查看该作者发表过的评论" target="_blank">更多评论</a>
    &nbsp; <br></li>
</ul><img src ="http://www.cppblog.com/richardhe/aggbug/57154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-25 16:41 <a href="http://www.cppblog.com/richardhe/articles/57154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GetProcAddress函数</title><link>http://www.cppblog.com/richardhe/articles/57080.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Thu, 24 Jul 2008 12:43:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/57080.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/57080.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/57080.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/57080.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/57080.html</trackback:ping><description><![CDATA[函数功能描述:GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。<br>
<br>
函数原型：<br>
FARPROC GetProcAddress(<br>
&nbsp;&nbsp;  HMODULE hModule,&nbsp;&nbsp;&nbsp;&nbsp;  // DLL模块句柄<br>
&nbsp;&nbsp;  LPCSTR lpProcName&nbsp;&nbsp;&nbsp;  // 函数名<br>
);<br>
<br>
参数：<br>
hModule <br>
&nbsp;&nbsp;  [in] 包含此函数的DLL模块的句柄。LoadLibrary或者GetModuleHandle函数可以返回此句柄。<br>
lpProcName <br>
&nbsp;&nbsp;  [in] 包含函数名的以NULL结尾的字符串，或者指定函数的序数值。如果此参数是一个序数值，它必须在一个字的底字节，高字节必须为0。<br>
&nbsp;&nbsp;<br>
返回值：<br>
&nbsp;&nbsp;  如果函数调用成功，返回值是DLL中的输出函数地址。<br>
&nbsp;&nbsp;  如果函数调用失败，返回值是NULL。得到进一步的错误信息，调用函数GetLastError。<br>
<br>
注释：<br>
&nbsp;&nbsp;  GetProcAddress函数被用来检索在DLL中的输出函数地址。 <br>
&nbsp;&nbsp;
lpProcName指针指向的函数名，拼写和大小写必须和DLL源代码中的模块定义文件(.DEF)中输出段(EXPORTS)中指定的相同。
Win32
API函数的输出名可能不同于你在代码中调用的这些函数名，这个不同被宏隐含在相关的SDK头文件中。如果想得到更多信息，请参考Win32函数原型
(Win32 Function Prototypes)。 <br>
&nbsp;&nbsp;
lpProcName参数能够识别DLL中的函数，通过指定一个与函数相联系的序数值(在.DEF中的EXPORTS段)。GetProcAddress
函数验证那个指定的序数值是否在输出的序数1和最高序数值之间(在.DEF中)。函数用这个序数值作为索引从函数表中读函数地址，假如.DEF
文件不连续地定义函数的序数值，如从1到N(N是输出的函数序数值)，错误将会发生，GetProcAddress将会返回一个错误的、非空的地址，虽然
指定的序数没有对应的函数。<br>
&nbsp;&nbsp;  为了防止函数不存在，函数应该通过名字指定而不是序数值。<br>
<br>
要求： <br>
&nbsp;&nbsp;  Windows NT/2000: 要求Windows NT 3.1 或以后版本。<br>
&nbsp;&nbsp;  Windows 95/98: 要求Windows 95 或以后版本。<br>
&nbsp;&nbsp;  头文件: 在Winbase.h中声明，include Windows.h。<br>
&nbsp;&nbsp;  库文件: Use Kernel32.lib。<br>
<br>
参看：<br>
动态链接库纵览(Dynamic-Link Libraries Overview), 动态链接库函数(Dynamic-Link Library Functions),FreeLibrary, GetModuleHandle, LoadLibrary <br>
<br>
示例代码：<br>
<br>
&nbsp;&nbsp;  调用KERNEL32.DLL中的RegisterServiceProcess(仅在Windows98中适用)<br>
<br>
&nbsp;&nbsp;  HMODULE hModule=GetModuleHandle("kernel32.dll");<br>
&nbsp;&nbsp;  if (hModule)<br>
&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  typedef DWORD (CALLBACK *LPFNREGISTER)(DWORD,DWORD);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  LPFNREGISTER lpfnRegister;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  lpfnRegister=(LPFNREGISTER)GetProcAddress(hModule,"RegisterServiceProcess");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (lpfnRegister)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (*lpfnRegister)(NULL,1L); <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;  }<img src ="http://www.cppblog.com/richardhe/aggbug/57080.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-24 20:43 <a href="http://www.cppblog.com/richardhe/articles/57080.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>教你使用正则表达式</title><link>http://www.cppblog.com/richardhe/articles/56827.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 22 Jul 2008 02:13:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/56827.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/56827.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/56827.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/56827.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/56827.html</trackback:ping><description><![CDATA[<div class="postbody">
<h2>教你使用正则表达式</h2>
<div id="postmessage_328008" class="t_msgfont"><a  href="http://www.vckbase.com/code/downcode.asp?id=2887" target="_blank"><font color="#0000ff">下载源代码</font></a><br>
<br>
很久没有VCKbase发表文章了，这次发表一些比较基础的文章吧！看过"保证你现在和未来不失业的十种关键技术"这篇文章了吧，这次我就拿出一个不会让你失业的编程技术讲讲吧，老虾们千万不要拿鸡蛋砸我，我只是写给初学者的！ <br>
关于正则表达式的教程和用法网上有很多的资源，基本的用法我讲了也是浪费你的眼力，所以我会以一个实例来教你学习正则表达式，我两年前做的一个MIS
中使用过正则式，检验用户输入的日期是否为正确的日期格式！分析完这个正则表达式后，对于正则表达式你绝对会有一个深深的认识！但是还不能说你精通，当你
可能用正则表达式写一个编译器的时候，你就可以精通了! <br>
&#8220;磨刀不误砍柴工&#8221;，要使用正则表达式，我们还要使用支持正则表达式的语言，解释性语言Ruby,Perl,Python等都支持正则表达
式，C#,Java,VB.net等也支持正则表达式，C++还需要第三方类库才能支持，VC.net提供了一个很好的正则表达式类库
CATLRegExp(全世界效率最高的正则表达式库哦)，可是却不能在VC6上使用，要在VC6上使用，可以使用VBS(Microsoft
VBScript Regular Expression 5.5)来处理正则表达式，这是一个COM,拿一个COM来用我还是情愿用Boost库. <br>
<br>
使用Boost库的时候，你需要编译库后你才能使用，不过这很容易。<br>
1.下载Boost库<br>
3.设定环境变量(以我本机的环境变量设定为例)<br>
<br>
<br>
<img  src="http://www.vckbase.com/document/journal/vckbase47/images/RegexDatepath.gif" onclick="zoom(this)" onload="attachimg(this, 'load')" alt="" border="0"><br>
<br>
<br>
2.进入 boost_1_32_0\libs\regex\build 目录中，你可以看到vc6.mak文件 nmake vc6.mak就可以了，跟着会产生lib和dll文件，把它拷贝到你的程序目录下就可使用了! <br>
<br>
你也可以全部编译，不过我只需要正则表达式库，所以我只编译这部分! <br>
<br>
好了，砍柴刀磨好了！我们就开始正则表达式的实践吧! <br>
<br>
当时我负责的MIS是医院的一个血液检验输入模块，要求输入的日期必须是合法的，这是第一要求，不然检验单就会报废。输入日期是可以
2006.04.02 或 2006/04/02 或 2006.4.2 或 2006/4/2 的格式，而且日期还是要合法的，比如说不可以出现
2006.02.31, 2006.4.41 这样的日期，不排除输入人员工作繁记忙输入错误会出现这种情况。 <br>
好了，用正则表达式如何解决这个问题，首先正则表达式是一个对文本匹配模式的使用方法，记得正则表达式的关键字用法是没有用的，各种语言的正则表达式中的关键字用法是不同的，要认识文本中字符的模式.比如说对以上日期的表示可以用正则表达式表示为 <br>
"^\\d{4}[\\s\\.-/]\\d{1,2}[\\s\\.-/]\\d{1,2}$"
但这是完全错误的，用文字对这句正则表达式的描述为字符串是由三组数字组成，每一组由四个数组成,第二和第三组由一个或两个数字组成,中间带有空格
或"/",4003.9/12,3344.0.40 都会被判为合法的字符,这就是错误的用法！有什么或以判别呢! <br>
有闰日的年份叫闰年，一般年份365天，闰年为366天(二月则有29天),闰年的计算方法：公元纪年的年数可以被四整除，即为闰年；被100整除而
不能被400整除为平年；被100整除也可被400整除的为闰年.则这样我们可以这样设计正则表达式，第一个是要求其格式统一，第二个是要求其能正确表达
闰年！1000/2/29 合法, 2000/2/29 合法，1900/2/29 非法. <br>
想一想,一年中不论闰年或平年有的月份都是固定的，1，3，5，7，8，10，12月都是 31天, 4, 6, 9, 11 月都是30 天,
2 月可能为 28 或 29天,我们则可以这样判断,除 2 月外, 1 到 12 月中日期为 29, 30
天内的都为合法，1，3，5，7，8，10，12月为31天的都为合法, 1 月到 12 月为 28 天的都为合法,
剩下的只要判断当年是否为闰年就行了，是闰年 2月29日就合法，否则非法!!! <br>
呵，结果就出来了，用"或"把三条正则表达式组合起来就行了,第一条是判断除2月外日期的表达式，第二条是1到12 月都是1-28天的表达式,最后一条是判断是否闰年及合法2月的表达式,若符合其中一条的都为正确的日期. <br>
<br>
第一条可以这样写除 2 月外 1 到 12 月都为 30 天的表达式为 (?:0?[1,3-9]|1[0-2])-(?:29|30) <br>
<br>
除2 月外 1，3，5，7，8，10，12月都是 31天, ((?:0?[13578]|1[02])-31), 两条合并起来就是：<br>
(?<img  src="http://bbs.telreading.com/images/smilies/default/sad.gif" smilieid="2" alt="" border="0">?:0?[1,3-9]|1[0-2])-(?:29|30)|((?:0?[13578]|1[02])-31)) 第二条可以这样写 (?:0?[1-9]|1[0-2])-(?:0?[1-9]|1\d|2[0-8]) <br>
<br>
第三条表达式就是要求表示闰年了，能被4 整除的四位数是怎么组成的呢?
可以看出,四位数中最后两位能被四整除都可以得出这个四位数能被4整除,100内为4的倍数的值为
04,08,12,16,20,24,28,32,36，40，44，48，52，56，60，64，68，72，76，80，84，88，92，96,
能被100与400整除的四位数则可以为##00的形式了 <br>
则这样的闰年判别可以为：<br>
(\d\d(?:0[48]|[2468][048]|[13579][26]))与 (?:0[48]00|[2468][048]00|[13579][26]00)合并后再加入2月日期合并为：<br>
((?<img  src="http://bbs.telreading.com/images/smilies/default/sad.gif" smilieid="2" alt="" border="0">\d\d(?:0[48]|[2468][048]|[13579][26]))|(?:0[48]00|[2468][048]00|[13579][26]00))-0?2-29) 　　这样就可得出一条正确的表达式了：<br>
^(?<img  src="http://bbs.telreading.com/images/smilies/default/sad.gif" smilieid="2" alt="" border="0">[0-9]
{4}-(?:(?:0?[1,3-9]|1[0-2])-(?:29|30)|((?:0?[13578]|1[02])-31)))|([0-9]
{4}-(?:0?[1-9]|1[0-2])-(?:0?[1-9]|1\d|2[0-8]))|(((?:(\d\d(?:0[48]|[2468]
[048]|[13579][26]))|(?:0[48]00|[2468][048]00|[13579][26]00))-0?2-29)))$
这条表达式匹配的日期为2004-02-29,2004-2-29,不匹配2007-2-29,格式固定为####-##-##,只有输入日期正确了
才会匹配。<br>
<img  src="http://www.vckbase.com/document/journal/vckbase47/images/RegexDateOutput.gif" onclick="zoom(this)" onload="attachimg(this, 'load')" alt="" border="0"> <br>
<br>
<br>
这样就完成一条正则表达式了，不要被吓倒，当你对正则表达式理解越深刻的时候，你才发现它的优美! <br>
<br>
在平时的工作中，你可以把一些常用的正则表达式封装成dll，当使用的时候，你可以方便地调用，提高你的效率！ <br>
这儿我顺便给出一些常用的正则表达! <br>
<br>
合法Email的表达式 <br>
^([a-zA-Z0-9_\-])([a-zA-Z0-9_\-\.]*)@(\[((25[0-5]|2[0-4][0-9]|1[0-9]
[0-9]|[1-9][0-9]|[0-9])\.){3}|((([a-zA-Z0-9\-]+)\.)+))([a-zA-Z]{2,}|
(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\])$
合法时间表示表达式[1:00 AM], [12:00 PM], [1:00am] <br>
^(1|01|2|02|3|03|4|04|5|05|6|06|7|07|8|08|9|09|10|11|12{1,2}):(([0-5]{1}[0-9]{1}\s{0,1})([AM|PM|am|pm]{2,2}))\W{0}$ 网站连接：<br>
[http://207.68.172.254/home.ashx], [ftp://ftp.netscape.com/],
[https://www.brinkster.com/login.asp]
^((https?|ftp)\://((\[?(\d{1,3}\.){3}\d{1,3}\]?)|(([-a-zA-Z0-9]+\.)+[a-zA-Z]{2,4}))(\:\d+)?(/[-a-zA-Z0-9._?,''+&amp;%$#=~\\]+)*/?)$</div>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/56827.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-22 10:13 <a href="http://www.cppblog.com/richardhe/articles/56827.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中的强制类型转换[转]</title><link>http://www.cppblog.com/richardhe/articles/56826.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 22 Jul 2008 02:10:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/56826.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/56826.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/56826.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/56826.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/56826.html</trackback:ping><description><![CDATA[<div class="postcontent">
<p class="alt"><span><span>标准c++中主要有四种强制转换类型运算符：&nbsp;&nbsp;&nbsp;</span></span><span>&nbsp;&nbsp;</span></p>
<p class="alt"><span></span><span class="keyword">const_cast</span><span>，</span><span class="keyword">reinterpret_cast</span><span>，</span><span class="keyword">static_cast</span><span>，</span><span class="keyword">dynamic_cast</span><span>等等。&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>1）</span><span class="keyword">static_cast</span><span>&lt;T*&gt;(a)&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>将地址a转换成类型T，T和a必须是指针、引用、算术类型或枚举类型。&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>表达式</span><span class="keyword">static_cast</span><span>&lt;T*&gt;(a),&nbsp;a的值转换为模板中指定的类型T。在运行时转换过程中，不进行类型检查来确保转换的安全性。&nbsp;&nbsp;&nbsp;</span></p>
<p class="alt"><span>例子：&nbsp;&nbsp;&nbsp;</span><span></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_8_14_Open_Image" onclick="this.style.display='none'; codehighlighter1_8_14_open_text.style.display="'none';" codehighlighter1_8_14_closed_image.style.display="'inline';" codehighlighter1_8_14_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_8_14_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_8_14_closed_text.style.display="'none';" codehighlighter1_8_14_open_image.style.display="'inline';" codehighlighter1_8_14_open_text.style.display="'inline';"" align="top"><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span id="Codehighlighter1_8_14_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_8_14_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_40_46_Open_Image" onclick="this.style.display='none'; codehighlighter1_40_46_open_text.style.display="'none';" codehighlighter1_40_46_closed_image.style.display="'inline';" codehighlighter1_40_46_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_40_46_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_40_46_closed_text.style.display="'none';" codehighlighter1_40_46_open_image.style.display="'inline';" codehighlighter1_40_46_open_text.style.display="'inline';"" align="top"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;D&nbsp;:&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span id="Codehighlighter1_40_46_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_40_46_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;f(B</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pb,&nbsp;D</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pd)&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_78_206_Open_Image" onclick="this.style.display='none'; codehighlighter1_78_206_open_text.style.display="'none';" codehighlighter1_78_206_closed_image.style.display="'inline';" codehighlighter1_78_206_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_78_206_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_78_206_closed_text.style.display="'none';" codehighlighter1_78_206_open_image.style.display="'inline';" codehighlighter1_78_206_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_78_206_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_78_206_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;D</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pd2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;static_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">D</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(pb);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不安全,&nbsp;pb可能只是B的指针&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;B</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pb2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;static_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">B</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(pd);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;安全的&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;">&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000;">&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div>
<p class=""><span>&nbsp;&nbsp;</span></p>
<p class=""><span>2）</span><span class="keyword">dynamic_cast</span><span>&lt;T*&gt;(a)&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>完成类层次结构中的提升。T必须是一个指针、引用或无类型的指针。a必须是决定一个指针或引用的表达式。&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>表达式</span><span class="keyword">dynamic_cast</span><span>&lt;T*&gt;(a)&nbsp;将a值转换为类型为T的对象指针。如果类型T不是a的某个基类型，该操作将返回一个空指针。&nbsp;&nbsp;&nbsp;</span></p>
<p class="alt"><span>例子：&nbsp;&nbsp;&nbsp;</span><span></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_8_14_Open_Image" onclick="this.style.display='none'; codehighlighter1_8_14_open_text.style.display="'none';" codehighlighter1_8_14_closed_image.style.display="'inline';" codehighlighter1_8_14_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_8_14_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_8_14_closed_text.style.display="'none';" codehighlighter1_8_14_open_image.style.display="'inline';" codehighlighter1_8_14_open_text.style.display="'inline';"" align="top"><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;A&nbsp;</span><span id="Codehighlighter1_8_14_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_8_14_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_29_35_Open_Image" onclick="this.style.display='none'; codehighlighter1_29_35_open_text.style.display="'none';" codehighlighter1_29_35_closed_image.style.display="'inline';" codehighlighter1_29_35_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_29_35_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_29_35_closed_text.style.display="'none';" codehighlighter1_29_35_open_image.style.display="'inline';" codehighlighter1_29_35_open_text.style.display="'inline';"" align="top"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span id="Codehighlighter1_29_35_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_29_35_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;f()&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_56_237_Open_Image" onclick="this.style.display='none'; codehighlighter1_56_237_open_text.style.display="'none';" codehighlighter1_56_237_closed_image.style.display="'inline';" codehighlighter1_56_237_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_56_237_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_56_237_closed_text.style.display="'none';" codehighlighter1_56_237_open_image.style.display="'inline';" codehighlighter1_56_237_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_56_237_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_56_237_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;A</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pa&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;A;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;B</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;B;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pv&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;dynamic_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">A</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(pa);&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;pv&nbsp;现在指向了一个类型为A的对象&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;pv&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;dynamic_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">B</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(pb);&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;pv&nbsp;现在指向了一个类型为B的对象&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000;">&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div>
<p class="alt"><span></span>&nbsp;</p>
<p class=""><span>3）</span><span class="keyword">const_cast</span><span>&lt;T*&gt;(a)&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>去掉类型中的常量，除了</span><span class="keyword">const</span><span>或不稳定的变址数，T和a必须是相同的类型。&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>表达式</span><span class="keyword">const_cast</span><span>&lt;T*&gt;(a)被用于从一个类中去除以下这些属性：</span><span class="keyword">const</span><span>,&nbsp;</span><span class="keyword">volatile</span><span>,&nbsp;和&nbsp;__unaligned。&nbsp;&nbsp;&nbsp;</span></p>
<p class="alt"><span>例子： &nbsp;&nbsp;</span></p>
<p class=""><span></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_8_14_Open_Image" onclick="this.style.display='none'; codehighlighter1_8_14_open_text.style.display="'none';" codehighlighter1_8_14_closed_image.style.display="'inline';" codehighlighter1_8_14_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_8_14_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_8_14_closed_text.style.display="'none';" codehighlighter1_8_14_open_image.style.display="'inline';" codehighlighter1_8_14_open_text.style.display="'inline';"" align="top"><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;A&nbsp;</span><span id="Codehighlighter1_8_14_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_8_14_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;f()&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_34_189_Open_Image" onclick="this.style.display='none'; codehighlighter1_34_189_open_text.style.display="'none';" codehighlighter1_34_189_closed_image.style.display="'inline';" codehighlighter1_34_189_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_34_189_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_34_189_closed_text.style.display="'none';" codehighlighter1_34_189_open_image.style.display="'inline';" codehighlighter1_34_189_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_34_189_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_34_189_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;A&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">pa&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;A;</span><span style="color: #008000;">//</span><span style="color: #008000;">const对象&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;A&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">pb;</span><span style="color: #008000;">//</span><span style="color: #008000;">非const对象&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #008000;">//</span><span style="color: #008000;">pb&nbsp;=&nbsp;pa;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;这里将出错，不能将const对象指针赋值给非const对象&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;pb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;const_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">A</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(pa);&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;现在OK了&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">..&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;">&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div>
<p class=""><span></span>&nbsp;</p>
<p class="alt"><span>4）</span><span class="keyword">reinterpret_cast</span><span>&lt;T*&gt;(a)&nbsp;&nbsp;&nbsp;</span></p>
<p class="alt"><span>任何指针都可以转换成其它类型的指针，T必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。&nbsp;&nbsp;&nbsp;</span></p>
<p class="alt"><span>表达式</span><span class="keyword">reinterpret_cast</span><span>&lt;T*&gt;(a)能够用于诸如</span><span class="datatypes">char</span><span>*&nbsp;到&nbsp;</span><span class="datatypes">int</span><span>*，或者One_class*&nbsp;到&nbsp;Unrelated_class*等类似这样的转换，因此可能是不安全的。&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>例子：&nbsp;&nbsp;&nbsp;</span></p>
<p class=""><span>&nbsp;</span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_8_14_Open_Image" onclick="this.style.display='none'; codehighlighter1_8_14_open_text.style.display="'none';" codehighlighter1_8_14_closed_image.style.display="'inline';" codehighlighter1_8_14_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_8_14_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_8_14_closed_text.style.display="'none';" codehighlighter1_8_14_open_image.style.display="'inline';" codehighlighter1_8_14_open_text.style.display="'inline';"" align="top"><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;A&nbsp;</span><span id="Codehighlighter1_8_14_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_8_14_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_29_35_Open_Image" onclick="this.style.display='none'; codehighlighter1_29_35_open_text.style.display="'none';" codehighlighter1_29_35_closed_image.style.display="'inline';" codehighlighter1_29_35_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_29_35_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_29_35_closed_text.style.display="'none';" codehighlighter1_29_35_open_image.style.display="'inline';" codehighlighter1_29_35_open_text.style.display="'inline';"" align="top"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span id="Codehighlighter1_29_35_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_29_35_Open_Text"><span style="color: #000000;">{&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;}</span></span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;f()&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" id="Codehighlighter1_55_171_Open_Image" onclick="this.style.display='none'; codehighlighter1_55_171_open_text.style.display="'none';" codehighlighter1_55_171_closed_image.style.display="'inline';" codehighlighter1_55_171_closed_text.style.display="'inline';"" align="top"><img  src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" id="Codehighlighter1_55_171_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_55_171_closed_text.style.display="'none';" codehighlighter1_55_171_open_image.style.display="'inline';" codehighlighter1_55_171_open_text.style.display="'inline';"" align="top"></span><span id="Codehighlighter1_55_171_Closed_Text" style="border: 1px solid #808080; display: none; background-color: #ffffff;"><img  src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_55_171_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;A</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pa&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;A;&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pv&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;reinterpret_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">A</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(pa);&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;pv&nbsp;现在指向了一个类型为B的对象，这可能是不安全的&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #000000;"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;<img  src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img  src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000;">&nbsp;&nbsp;<br><img  src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div>
<p class="">&nbsp;<br>本文转自<a  href="http://www.libing.net.cn/read.php?520">http://www.libing.net.cn/read.php?520</a></p>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/56826.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-22 10:10 <a href="http://www.cppblog.com/richardhe/articles/56826.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>把C++类成员方法直接作为线程回调函数</title><link>http://www.cppblog.com/richardhe/articles/56822.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Tue, 22 Jul 2008 01:58:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/56822.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/56822.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/56822.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/56822.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/56822.html</trackback:ping><description><![CDATA[<div class="postcontent">
<p>我以前写线程时要么老老实实照着声明写,要么使用C++类的静态成员函数来作为回调函数,经常会因为线程代码而破坏封装.之前虽然知道类成员函数的展开形式，但从没想过利用过它，昨天看深入ATL时无意中学会了这一招:)&nbsp;</p>
<p>类成员方法是一个比较特殊的函数，它在编译时会被转化成普通函数，比如有TMyClass类:<br>class TMyClass{<br>&nbsp;&nbsp;&nbsp; void Func();<br>};</p>
<p>这个TMyClass::Func最终会转化成 void Func(TMyClass *this); 也就是说在原第一个参数前插入指向对象本身的this指针。</p>
<p>我们可以利用这个特性写一个非静态类成员方法来直接作为线程回调函数，先看_beginthread函数的定义:<br>unsigned long _RTLENTRY _EXPFUNC _beginthread (void (_USERENTRY *__start)(void *),unsigned __stksize, void *__arg);<br>其中的第一个参数就是作为线程执行主体的回调函数。它的原型是:void Func(void *)，这个void*参数是作为自定义数据传入的。对比一下上面所说的TMyClass::Func的最终形式，它正好可以符合这里的要求。</p>
<p>现在做个实验:<br>#include &lt;stdio.h&gt;<br>#include &lt;process.h&gt;</p>
<p>class TMyClass{<br>&nbsp;&nbsp;&nbsp; int m_nCount;<br>&nbsp;&nbsp;&nbsp; int m_nId;<br>public:<br>&nbsp;&nbsp;&nbsp; TMyClass(int nId,int nCount)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :m_nId(nId),m_nCount(nCount)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; void _USERENTRY ThreadProc()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 类成员方法<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;m_nCount; i++)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 根据m_nCount成员打印一排数字<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Class%d : %d\n",m_nId,i);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>};</p>
<p>int main(int argc, char* argv[])<br>{<br>&nbsp;&nbsp;&nbsp; union {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 联合类，用于转换类成员方法指针到普通函数指针（试过编译器不允许在这两种函数之间强制转换），不知道有没有更好的方法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (_USERENTRY *ThreadProc)(void *);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (_USERENTRY TMyClass::*MemberProc)();<br>&nbsp;&nbsp;&nbsp; } Proc;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 尽管联合里的两种函数类型现在看起来有很大不同，但它们的最终形式是相同的。</p>
<p>&nbsp;&nbsp;&nbsp; TMyClass MyClass1(1,10),MyClass2(2,5); // 产生两个TMyClass对象</p>
<p>&nbsp;&nbsp;&nbsp; Proc.MemberProc = &amp;TMyClass::ThreadProc;&nbsp;&nbsp; // 转换，Proc.ThreadProc就是对应的普通函数指针了</p>
<p>&nbsp;&nbsp;&nbsp; _beginthread(Proc.ThreadProc,4096,&amp;MyClass1);&nbsp;&nbsp; //
开始线程，这里的Proc.ThreadProc实际上是TMyClass::ThreadProc,
它要的this指针是我们给的&amp;MyClass1。<br>&nbsp;&nbsp;&nbsp; _beginthread(Proc.ThreadProc,4096,&amp;MyClass2);<br>&nbsp;&nbsp;&nbsp; system("pause");<br>&nbsp;&nbsp;&nbsp; return 0;<br>}</p>
<p>运行！神奇吧？:-)</p>
<p>其实不止线程回调函数，其实只要是形如Func(void*,...)的回调函数都可以用这种方法直接使用类成员方法。(前提是第一个void*是自定义数据，也就是说它不能有其它功能)。<br><br>转自:http://blog.csdn.net/waiting4you/archive/2007/12/29/2000796.aspx</p>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/56822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-07-22 09:58 <a href="http://www.cppblog.com/richardhe/articles/56822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>