﻿<?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>IT博客网-shanshan</title><link>http://www.cnitblog.com/shanshan/</link><description /><language>zh-cn</language><lastBuildDate>Mon, 13 Oct 2008 22:04:03 GMT</lastBuildDate><pubDate>Mon, 13 Oct 2008 22:04:03 GMT</pubDate><ttl>60</ttl><item><title>新的研究生生活开始了</title><link>http://www.cnitblog.com/shanshan/archive/2008/09/02/48615.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Tue, 02 Sep 2008 02:36:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/09/02/48615.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/48615.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/09/02/48615.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/48615.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/48615.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 来工大已经一段时间了，上课已经开始了，我总体还觉得习惯，因为以前还熟悉了一阵，还好。<br></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 寝室人都很好，而且都很厉害，值得我好好学习。<br></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关于实验室项目的问题，因为最近装修所以只是跟师兄师姐看论文，讨论交流可能再过一段时间。<br></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 总之的努力了，包括课程，项目还有英语水平。</p>
<img src ="http://www.cnitblog.com/shanshan/aggbug/48615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-09-02 10:36 <a href="http://www.cnitblog.com/shanshan/archive/2008/09/02/48615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一位软件工程师的6年总结（转）</title><link>http://www.cnitblog.com/shanshan/archive/2008/05/19/43904.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Mon, 19 May 2008 13:32:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/05/19/43904.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/43904.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/05/19/43904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/43904.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/43904.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>&#8220;又是一年毕业时&#8221;，看到一批批学子离开人生的象牙塔，走上各自的工作岗位；想想自己也曾经意气风发、踌躇满志，不觉感叹万千&#8230;&#8230;本文是自己工作6年的经历沉淀或者经验提炼，希望对所有的软件工程师们有所帮助，早日实现自己的人生目标。本文主要是关于软件开发人员如何提高自己的软件专业技术方面的具体建议，前面几点旨在确定大的方向，算是废话吧。<br>谨以此文献给那个自己为你奉献3年青春与激情的开发团队。还有团队成员：PPL、YT、YK 、TYF、LGL、CHL、CDY、CB、DPD。 </p>
<p><br>1、 分享第一条经验：&#8220;学历代表过去、能力代表现在、学习力代表未来。&#8221;其实这是一个来自国外教育领域的一个研究结果。相信工作过几年、十几年的朋友对这个道理有些体会吧。但我相信这一点也很重要：&#8220;重要的道理明白太晚将抱憾终生！&#8221;所以放在每一条，让刚刚毕业的朋友们早点看到哈！ </p>
<p><br>2、 一定要确定自己的发展方向，并为此目的制定可行的计划。不要说什么，&#8220;我刚毕业，还不知道将来可能做什么？&#8221;，&#8220;跟着感觉走，先做做看&#8221;。因为，这样的观点会通过你的潜意识去暗示你的行为无所事事、碌碌无为。一直做技术，将来成为专家级人物？向管理方向走，成为职业经理人？先熟悉行业和领域，将来自立门户？还是先在行业里面混混，过几年转行做点别的？这很重要，它将决定你近几年、十年内&#8220;做什么事情才是在做正确的事情！&#8221;。 </p>
<p><br>3、 软件开发团队中，技术不是万能的，但没有技术是万万不能的！在技术型团队中，技术与人品同等重要，当然长相也比较重要哈，尤其在MM比较多的团队中。在软件项目团队中，技术水平是受人重视和尊重的重要砝码。无论你是做管理、系统分析、设计、编码，还是产品管理、测试、文档、实施、维护，多少你都要有技术基础。算我孤陋寡闻，我还真没有亲眼看到过一个外行带领一个软件开发团队成功地完成过软件开发项目，哪怕就一个，也没有看到。倒是曾经看到过一个&#8220;高学历的牛人&#8221;(非技术型)带一堆人做完过一个项目，项目交付的第二天，项目组成员扔下一句&#8220;再也受不了啦！&#8221;四分五裂、各奔东西。那个项目的&#8220;成功度&#8221;大家可想而知了。 </p>
<p><br>4、 详细制定自己软件开发专业知识学习计划，并注意及时修正和调整(软件开发技术变化实在太快)。请牢记：&#8220;如果一个软件开发人员在1、2年内都没有更新过自己的知识，那么，其实他已经不再属于这个行业了。&#8221;不要告诉自己没有时间。来自时间管理领域的著名的&#8220;三八原则&#8221;告诫我们：另外的那8小时如何使用将决定你的人生成败！本人自毕业以来，平均每天实际学习时间超过2小时。 </p>
<p><br>5、 书籍是人类进步的阶梯，对软件开发人员尤其如此。书籍是学习知识的最有效途径，不要过多地指望在工作中能遇到&#8220;世外高人&#8221;，并不厌其烦地教你。对于花钱买书，我个人经验是：千万别买国内那帮人出的书！我买的那些家伙出的书，!00%全部后悔了，无一本例外。更气愤的是，这些书在二手市场的地摊上都很难卖掉。&#8220;拥有书籍并不表示拥有知识；拥有知识并不表示拥有技能；拥有技能并不表示拥有文化；拥有文化并不表示拥有智慧。&#8221;只有将书本变成的自己智慧，才算是真正拥有了它。 </p>
<p><br>6、 不要仅局限于对某项技术的表面使用上，哪怕你只是偶尔用一、二次。&#8220;对任何事物不究就里&#8221;是任何行业的工程师所不应该具备的素质。开发Windows应用程序，看看Windows程序的设计、加载、执行原理，分析一下PE文件格式，试试用SDK开发从头开发一个Windows应用程序；用VC＋＋、Delphi、Java、.Net开发应用程序，花时间去研究一下MFC、VCL、J2EE、.Net它们框架设计或者源码；除了会用J2EE、JBoss、Spring、Hibernate等等优秀的开源产品或者框架，抽空看看大师们是如何抽象、分析、设计和实现那些类似问题的通用解决方案的。试着这样做做，你以后的工作将会少遇到一些让你不明就里、一头雾水的问题，因为，很多东西你&#8220;知其然且知其所以然&#8221;！ </p>
<p>&nbsp;<br>7、在一种语言上编程，但别为其束缚了思想。&#8220;代码大全&#8221;中说：&#8220;深入一门语言编程，不要浮于表面&#8221;。深入一门语言开发还远远不足，任何编程语言的存在都有其自身的理由，所以也没有哪门语言是&#8220;包治百病&#8221;的&#8220;灵丹妙药&#8221;。编程语言对开发人员解决具体问题的思路和方式的影响与束缚的例子俯拾皆是。我的经验是：用面对对象工具开发某些关键模块时，为什么不可以借鉴C、C51、汇编的模块化封装方式？用传统的桌面开发工具(目前主要有VC++、Delphi)进行系统体统结构设计时，为什么不可以参考来自Java社区的IoC、AOP设计思想，甚至借鉴像Spring、Hibernate、JBoss等等优秀的开源框架？在进行类似于实时通信、数据采集等功能的设计、实现时，为什么不可以引用来自实时系统、嵌入式系统的优秀的体系框架与模式？为什么一切都必须以个人、团队在当然开发语言上的传统或者经验来解决问题？？？&#8220;他山之石、可以攻玉&#8221;。 </p>
<p>8、 养成总结与反思的习惯，并有意识地提炼日常工作成果，形成自己的个人源码库、解决某类问题的通用系统体系结构、甚至进化为框架。众所周知，对软件开发人员而言，有、无经验的一个显著区别是：无经验者完成任何任务时都从头开始，而有经验者往往通过重组自己的可复用模块、类库来解决问题（其实这个结论不应该被局限在软件开发领域、可以延伸到很多方面）。这并不是说，所有可复用的东西都必须自己实现，别人成熟的通过测试的成果也可以收集、整理、集成到自己的知识库中。但是，最好还是自己实现，这样没有知识产权、版权等问题，关键是自己实现后能真正掌握这个知识点，拥有这个技能。 </p>
<p>9、 理论与实践并重，内外双修。工程师的内涵是：以工程师的眼光观察、分析事物和世界。一个合格的软件工程师，是真正理解了软件产品的本质及软件产品研发的思想精髓的人（个人观点、欢迎探讨）。掌握软件开发语言、应用语言工具解决工作中的具体问题、完成目标任务是软件工程师的主要工作，但从软件工程师这个角度来看，这只是外在的东西，并非重要的、本质的工作。学习、掌握软件产品开发理论知识、软件开发方法论，并在实践中理解、应用软件产品的分析、设计、实现思想来解决具体的软件产品研发问题，才是真正的软件工程师的工作。站在成熟理论与可靠方法论的高度思考、分析、解决问题，并在具体实践中验证和修正这些思想与方式，最终形成自己的理论体系和实用方法论。 </p>
<p>10、心态有多开放，视野就有多开阔。不要抱着自己的技术和成果，等到它们都已经过时变成垃圾了，才拿出来丢人现眼。请及时发布自己的研究成果：开发的产品、有创意的设计或代码，公布出来让大家交流或者使用，你的成果才有进化和升华的机会。想想自己2000年间开发的那些Windows系统工具，5、6年之后的今天，还是那个样子，今天流行的好多Windows系统工具都比自己的晚，但进化得很好，且有那么多用户在使用。并且，不要保守自己的技术和思想，尽可能地与人交流与分享，或者传授给开发团队的成员。&#8220;与人交换苹果之后，每个人还是只有一个苹果；但交换思想之后，每个人都拥有两种思想&#8221;，道理大家都懂，但有多少人真正能做到呢？ </p>
<p>11、尽量参加开源项目的开发、或者与朋友共同研制一些自己的产品，千万不要因为没有钱赚而不做。网络早已不再只是&#8220;虚拟世界&#8221;，网上有很多的开源项目、合作开发项目、外包项目，这都是涉猎工作以外的知识的绝好机会，并且能够结识更广的人缘。不要因为工作是做ERP，就不去学习和了解嵌入式、实时、通信、网络等方面的技术，反过来也是一样。如果当他别人拿着合同找你合作，你却这也不会，那也不熟时，你将后悔莫及。 </p>
<p>12、书到用时方恨少，不要将自己的知识面仅仅局限于技术方面。诺贝尔经济学奖得主西蒙教授的研究结果表明： &#8220;对于一个有一定基础的人来说，他只要真正肯下功夫，在6个月内就可以掌握任何一门学问。&#8221;教育心理学界为感谢西蒙教授的研究成果，故命名为西蒙学习法。可见，掌握一门陌生的学问远远没有想想的那么高难、深奥。多方吸取、广泛涉猎。极力夯实自己的影响圈、尽量扩大自己的关注圈。财务、经济、税务、管理等等知识，有空花时间看看，韬光养晦、未雨绸缪。 </p>
<p>13、本文的总结与反思： <br>A：不要去做技术上的高手，除非你的目标如此。虽然本文是关于提高软件开发知识的建议，做技术的高手是我一向都不赞同的。你可以提高自己的专业知识，但能胜任工作即止。<br>B：提高软件知识和技术只是问题的表面，本质是要提高自己认识问题、分析问题、解决问题的思想高度。软件专业知识的很多方法和原理，可以很容易地延伸、应用到生活的其它方面。 <br>C：在能胜任工作的基础上，立即去涉猎其它领域的专业知识，丰富自己的知识体系、提高自己的综合素质，尤其是那些目标不在技术方面的朋友 </p>
<p>&nbsp;</p>
<img src ="http://www.cnitblog.com/shanshan/aggbug/43904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-05-19 21:32 <a href="http://www.cnitblog.com/shanshan/archive/2008/05/19/43904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>李开复说人才（转）</title><link>http://www.cnitblog.com/shanshan/archive/2008/05/19/43903.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Mon, 19 May 2008 13:31:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/05/19/43903.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/43903.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/05/19/43903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/43903.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/43903.html</trackback:ping><description><![CDATA[<p>我们都知道21世纪最有价值的是人才，是什么人才呢，就是我今天要演讲的题目。我想我这个演讲有一个很大的假设就是21世纪需要的人才与20世纪、19世纪有着很大的差别，因为21世纪有几个很重大的革命发生。在21世纪我们更多的工作是靠我们脑力的创造，是靠平等的竞争，已经没有国界的差别，世界被铲为平地，任何一个国家的人都可以和另外一个国家的人合作或者竞争，而他们都可以接触到、使用到、共享到同样的信息。不像过去，谁能独占信息他就能对另一个人或者对那个公司发挥相当大的价值。</p>
<p>　　今天的信息是因为共享才能发挥它真正的潜力。所以在这样的情况下，每个人都可以自由地选择，平等地竞争，他们会积极地去获取自己的信息，追求自己的兴趣。他们期望自己工作的公司采取的不再是控制式的管理，而是放权式的管理。因为在21世纪，一个人他是靠自己的脑力创造财富，他很聪明很有创意，他跟全世界每一个人平等地竞争，然后每一个人都有同样的信息，没有一个人会愿意在一个不公平的控制下做一个公司的齿轮。每个人都会希望发挥自己的潜能，他希望自己到一个公司工作，这个公司能够放权地让每一个员工做自己的事情。还有呢，21世纪什么都改变得非常快。你才认为说某某一个技术或者某某一个公司是很火热的，忽然一个新的技术或者一个新的公司已经出来了。这都是因为互联网，每个国家，每个领域之间的边界因此在不断地消除，世界各地的人们可以一起工作，竞争和合作。所以在这样的一个环境之下，21世纪需要的不再是19、20世纪听话，没有自己意见，努力有毅力的所谓的蓝领或者白领工人，更需要的是我的演讲要谈到的7种人。</p>
<p>　　1.创新实践者——What matters is not innovation , but useful innovation。 <br>&nbsp;&nbsp; <br>　　这7种人中的第1种是创新实践者。在今天谈到的所有人时，我都会引用一句我认为很好的话。那么第一句话是谁说得呢，是我说的。这句话跟创新有关，待会还会谈到。我想说的是在21世纪真正有价值的人是能够创新的人。他不是一个只会使用别人的方法做事情的人，他不是那种只会听话做事情的一颗棋子，一个齿轮。因为，在如今的竞争之下，一个公司唯一可以延续的竞争优势就是它的创新。任何东西都可以很容易地被模仿，只有创新很难被模仿。而创新一旦被模仿，你唯一的办法就是继续地创新。所以一批有生命力的能够持续创新的员工是唯一能够带给企业持续竞争力的财富。</p>
<p>　　你们可能会说，李开复是不是要讲Google，讲其他科技公司要学计算机科学，要做最高深的研究这才是创新呢？其实不是的。在每一个领域都可以创新，也就是这些每一个不同领域的创新，让每一个工作变得多彩多姿。我可以举个例子。如果你在美国加州101公路硅谷段上开车，你可能会看到一个广告牌。整个广告牌上面没有公司名也没有任何广告词，只简简单单刷着&#8220;(在&#8216;e&#8217;的数列中所能找到的第一个十位数质数).com&#8221;。很多在硅谷工作的聪明人开车看到了这个广告，他们回家就会去算，有些用计算机来算，有些用数学方法来推算，算出来答案以后登陆这个网站一看，发现另外有一个更难的题目。然后他们再做了这道题目，又会到达另外一个网站，就着样做了一个题目又一个题目，最后他们发现自己到了一个很特殊的网站，这个网站就是Google的招聘网站。我们可以从这个例子看到，在Google这样一个创新的公司，它的创新其实远远不止在于一个工程部门。你可以看到招聘，市场都是充满了创意的。</p>
<p>　　关于创新还有一点要注意的，21世纪的创新必须实时、实践。因为我们有了互联网的存在，每个公司的步伐都非常快。如果你花很多的时候去做一些验证，一些用户调查，再花一两年的时间才把一个东西编出来再做测试，一个产品四五年做出来以后很可能已经过时了。所以在这21世纪，光做一个创新者是不够的，要做一个创新实践者。这就回答了我上面那句话：What matters is not innovation, but useful innovation。只是为了创新而创新是没有意义的，要做有用的创新才是有意义的。</p>
<p>　　记得我在SCI公司的时候，曾经犯过的一个最大的错误就是只想到创新，没有想到实践。我们做了一个非常酷的三维浏览器，今天可能都还没有人在使用。当时，我们每次演示的时候，观众的下巴都会掉下来，说：哇，怎么会做这么酷的一个东西！但是我们忘记了这么酷的东西却是没有市场的。最后结果是相当的失败，让我也有了一个很惨痛的经验，尤其是当我看到一百多名员工失去他们工作的时候，让我下了一个决心，就是上面这句话。</p>
<p>　　我们虽然要创新，但是不是为了创新而创新，而是为了做有用的事情而创新。我们如果回顾历史，可以看到许多成功的人才，他们有些创新，有些实践，有些左脑发达，有些右脑发达。但是那些真正对世界有重大贡献的人，我想他们不仅是创新者，也是实践者，比如说爱迪生，比尔盖茨，Larry 和Sergey，都是很好的例子。一个真正的创新实践者每一次在创新的时候都忘不了实践，在实践的时候也忘不了创新，这样的人，我想是21世纪不可缺少的人才。</p>
<p>　　2.跨领域合成者——What matters is not analysis but synthesis。</p>
<p>　　第2点呢，我想非常需要的是跨领域合成者。刚才听到了竺可桢学院，它本身是多学科的，强化班也是由来自不同专业的同学组成的。这点确实也是非常符合了所谓的合成者。相信在中国的未来，在全世界的未来，我们更需要的人才不只是那些把一个学科学得非常非常深的，而是那些把自己学科学好，同时能够与其他领域做一个跨领域结合的人才。原因其实非常简单，如果是世界上有1000种知识，这个知识本身你可以学得很深，但是两个人的知识通过交叉碰撞又可以产生新的知识，三个人的碰撞就能产生十亿个组合。</p>
<p>　　以计算机为例，如果你是学计算机的，又对心理学感兴趣，这样一个跨学科的合成，你可能对用户界面或者可用度测试会有一些贡献。所以，很多新的领域的产生，都是靠过去的两种学科所交叉碰撞出来的，这是一个很好的机会。如果把一门学科学得太深了，可能会去钻牛角尖，反而失去创新实践的机会。真正重要的不是analysis，不是要分析得很深，而是synthesis，怎么样有合成的机会。</p>
<p>　　所以，对各位同学我的建议就是，当然读好你的专业是有必要的，但是同时要考虑下是否还有别的什么专业是你有兴趣的。这两个专业最新的思想能不能结合起来，做一些即有创意又可以实践的东西，这可能是最有成长空间的一些机会。</p>
<p>　　3.高情商合作者——EQ is 9 times more important than IQ。</p>
<p>　　第3种最需要的人是高情商合作者。EQ is 9 times more important than IQ，这句话来自Daniel Goleman的《EQ》这本书。《EQ》这本书谈到情商和智商的一些差别，还有哪个比较重要。他做了一个研究，找了几千个企业的领导者。他研究是什么因素让这些非常优秀的领导者和普通的领导者有所区别。他研究的结论最重要的差别不在于IQ，而是比IQ要更重要9倍的EQ，即情商。</p>
<p>　　情商包括了怎样与人合作，包括了对自己的一种自觉，包括了对自己的一种管理，也包括了和别人团结合作以及社交的一些能力。EQ的重要性在21世纪是非常显著的，因为在21世纪，我们需要全球的合作，需要跨领域的合成。比如说你学的是心理学，你要跟学计算机的人合作才能做得出用户界面。跨领域的合作，跨国度的合作，跨语言的合作，这些都是必须要的。所以，过去也许在很多的环境里面，你作为一个孤僻自傲的天才会得到很大的重视，但是这个情况现在已经在大大地改变了。</p>
<p>　　过去，我曾在我的人才观里提到，在这个信息社会里，与过去的工业社会很大的一个差别就是信息社会最好的一个人才，一个程序员、一个科学家，可能比普通人生产力好个3倍、5倍、10倍或者20倍甚至更多。但是我想在这里补充的一句话就是说，即使他在技术方面好个多少倍，如果他是一个孤僻自傲、不能合作，甚至引起团队无法工作的人，那么他对这个团队，反而是一个负面的效果。</p>
<p>　　当我们做管理的时候，我们也必须考虑到，如果你要建立一个非常健康的团队，不管是在Google工作还是未来的Google Camp，一定要在每个人很客观高情商地愿意与他人合作，尊敬别人的前提之下，才可能有很好的结果，尤其是在21世纪这样一个情商和合作是那么重要的世纪里面。所以，我对各位同学的建议是，在你可以抓住的每一个机会里，多参与社团工作，多建立一些与人合作的基础，无论是在上课，还是参与社团项目，或是暑期工作的机会。让自己除了读书之外，多做一个能够与人团结、合作、客观、尊敬别人、聆听别人的一个高情商的学生。</p>
<p>　　 4.高效能沟通者——The man who can think and does not know how to express what he thinks is at the level of him who cannot think。</p>
<p>　　第4种人是高效能的沟通者。一个人如果有思想但是不能表达自己，他其实就是一个没有思想的人，这句话其实相当的有道理。我想在座很多理工科的同学以前可能认为只要有思想就够了，不过这句话告诉我们你只有思想不能沟通，其实你是没有思想的。这句话其实并没有夸张，在21世纪全世界都是信息的前提下，很好的信息传播渠道还是经过人。人怎么传播信息的，靠沟通。一个人他的沟通能力很好，他可以把一个很难懂的信息很好地传播给别人。一个人沟通能力很差，他就无法传播信息，因此别人可能看不起他，认为他没有思想。所以沟通能力是非常需要学习的。</p>
<p>　　这种沟通的能力怎么得到呢，我可以给同学们几个很好的建议。你沟通的时候一定要理解你的听众，你要知道你的听众在想什么，听众从你的讲话中能得到什么好处，即What&#8217;s in it for you。还有要注意说话的方式，不要用说教，而应该采取引导的方式。当你与别人沟通的时候，你要先想好你主要要传达的Message是什么，用听众能够接受的方式表达出来。</p>
<p>　　5.热爱工作者——If you find a job you love , you will never work a day in your life。</p>
<p>　　第5种非常需要的人才是热爱工作者。因为在全球被铲平之后，每一个人都是平等的。如果你能够做一个工作是你非常热爱的，那么你可能在睡觉、洗澡、吃饭时都在想你的工作。你可能就会更有热情去做你的工作。你不认为你的工作是一个枯燥的事情，而是可以享受的事情。所有就有这么一句话，有一天有个美国朋友到我的办公室来说你们的孔夫子实在是太聪明了。我说怎么回事呢。他说你看他讲的这句话多有道理啊：If you find a job you love， you will never work a day in your life。我就跟他说谢谢你夸奖我们的孔夫子，不过我实在想不起来孔夫子说了这句话。</p>
<p>　　后来当天开车回家的时候我才想到可能是&#8220;知之者不如好之者，好之者不如乐之者&#8221;这句话。但是今天看起来，我认为可能这句英文的翻译还更贴切一些，在21世纪更能够被更多的人理解。因为如果你真的很爱你的工作，你就不是在工作了，你是在享受了。如果你是在享受的话，你一定会有更多的热情投入，更多的时间投入，更乐意去做更多的工作。到了星期五可能不想回家，到了星期天可能就想来上班了。那么你想比别人做得差可能都很困难。</p>
<p>　　我们能看到的是，如果你能找到你的最爱，你的一生都会过得比较快乐。所以各位同学，如果你们还没找到你们的最爱，我的建议是保持一颗好奇的心，多去尝试不同的事情。然后要理解你的专业和你的工作不见得是完全一样的。要多做咨询，了解有什么样的公司，什么样的环境，什么样的工作你毕业后可以从中选择。如果你在一个你喜欢的专业里面呢，珍惜它，好好地去找一份未来相应的工作。如果是在一个可以选择的十字路口，比如说考研，出国等等，这个时候你要好好地去选一个你真正喜欢的专业，而且也许把刚才谈到的跨领域合作的概念借鉴过来。并不是说我过去学的是一个不喜欢的专业，我就要从文科转到理科。也许你可以找到一个更好的跨越的台阶。如果你不喜欢你的专业呢，你也可以在这个专业里面尽量找一个大专业里面的小专业，也许是你比较喜欢的；或者你可以在一个你认为你比较喜欢的专业和你现在不喜欢的专业之间的交叉学科找一些机会。所以不管怎么样，最后能够找到你爱的事情，你就能发挥你的潜力，成为21世纪需要的热爱工作者。</p>
<p>　　6.积极主动者——In a few hundred years , the most important event those historians will see is that for the first time , people will have a choice. They will have to manage themselves。</p>
<p>　　第6种是积极主动者。这句话是Peter Drucker所说的。他说几百年之后，历史学家回顾今天，他们会说这个世纪里最重要的事情，不是互联网，而是人有了选择。有了选择就要积极主动，然后需要管理自己。这是最重要的一点，这也就是我们从工业社会转变到现在的信息社会所发生的最重要的事情。一个积极主动者他对自己的一切一定要负责，因为如果你自己不在乎，没有别人会比你更在乎，没有人会比你更知道你想做什么。在来到大学之前，一切都是消极，由父母来决定的。进入大学之后，要开始对自己的一切负责。不去解决也是一种解决，不做决定其实也是一种决定，这个决定就是让自己走入一个消极而不是积极的方向。<br>　　在我出书的时候许多人喜欢让我把他们的座右铭写在书上，当我有时间的时候我也会尽量配合，但是有一句话我绝对是不写的，这句话就是沉默是金。因为在今天的环境里面，每个人需要合适地推销自己，让别人知道你的成果。因为如果你不表达，那其实别人就会认为你没有思想。当然，在适当的环境里，你才能做适当的表达，并不是要你抢别人的机会，也不是要你过分地做一个出头鸟。但是，如果你有一些想法有一些思想一定要表达出来。</p>
<p>　　在这个21世纪里，每个人都有想法，都有信息。那些最有信息或者最有想法的人可能会得到很多或者更多的注意。比如说在这次成立Google Camp的时候，工作人员有一天来找我说我们这个Google Camp有一些想法你觉得怎么样？当时我记得非常清楚的就是我在全国20多个高校做巡回演讲的时候在那些学校见到了一些非常积极主动的同学。我就跟他说，你去下面四个学校见见曾经主持我办的活动的同学吧，因为我认为他们是积极主动的，是符合Google Camp的精神的。我认为他们会给你很多想法，也许他们会成为我们的Google Camp的骨干。所以，如果你们在想，怎么挑到这四个学校的呢，很大的原因就是当时我做巡回演讲的时候这是四个让我感触最深最积极主动的学校，最优秀的同学。所以这是一个活生生的今天在Google Camp成立的时候发生的例子。</p>
<p>　　我们可以看到正是因为当时有这么一批积极主动的同学让我们今天有机会在浙大成立这个Google Camp。积极主动者，他并不只是积极地等待机会，他还需要积极地把握机会，为自己创造机会。这点可能是中国的学生，中国的员工最需要常常提醒自己的地方。前一阵我们在中国差不多招了三十多个员工，工作了三四个月。有一天我们在聚会，他们就问我说：开复，你对我们这三十个刚开始的关门弟子有什么建议没有。我的回答是：从技术方面，从对公司的理想、价值观认同以及努力方面，我都非常非常的满意。但是，如果要讲一点我希望你们未来可以做的更好的，我希望你们未来能够更加积极主动，要提出你们的想法。</p>
<p>　　 7.乐观向上者——The glass is half full or half empty depending on whether you&#8217;re pouring in or out</p>
<p>　　最后我想讲的是乐观向上者。这句话来自美国的一个喜剧演员Bill Cosby，他是这么说的，我们常说一杯水是一半满的还是一半空的，其实要看你是继续把水注进杯子里，还是把水从杯子里面倒出去。如果你在继续注水的话，你会期望着水位上升；如果你在倒水的话，你会想到很快杯子就会空掉了。其实这告诉我们的是一个人的思想，是一个乐观的人，还是一个悲观的人。如果你是一个乐观向上的人，你会总告诉自己未来会更好。台湾有位企业家叫做张忠谋，他是台基电的董事长，他最近写了一篇文章，我觉得里面有些很有哲理的话。他有个朋友请他提几个字挂在墙上。然后张忠谋就跟他说，我的字写得不好，但是我随便帮你写几个字，然后他就写了&#8220;常想一二&#8221;这四个字。他朋友说什么叫&#8220;常想一二&#8221;呢。然后张忠谋就告诉他说，你没有听过吗？我们都说人生不如意之事十有八九，我要告诉你常想那剩下那一二比较如意的事情。他说他从小就看了很多大人物的传记，他发现了一个规律，凡是成功者都是受苦受难的。然后他们的生命几乎就是人生不如意事十有八九的真实写照。但是他发现这些人之所以能够成功，就是因为他们保持了正面的思考，通过&#8220;常想一二&#8221;，他们能够超越苦难。苦难对他们来说反而成了生命中最好的养料，为他们未来的成功做了良好的铺垫。<br>　　所以这些成功者在面对苦难时的坚持、乐观和勇气是最重要的。人生的如意或不如意，更重要的不是取决于人生的际遇而是思想的瞬间。所以，人生的真正品质取决于你有没有&#8220;常想一二&#8221;这种乐观的思维方式，观点反而比这个事实更重要。这是他很有哲理的一篇文章，我想你用Google可以搜索得到。</p>
<p>　　其实在21世纪，还有很多其他的理由要做一个乐观向上的人。因为21世纪是一个更实时善变的环境，我们尝试的事情会碰到很多很多的失败。我们都听到说Google很酷，有一个20％的Project，每一个人都有20％的时间做自己想做的事情。但是，如果我们做一个统计，我想一定会发现，这个20％自己想做的Project绝大多数一定是失败的。如果你没有一个良好的心态，不能客观地说我学到了一个Lesson有助于我做下一个项目时，那你很快就会处于一个非常沮丧的心态。所以Google公司不但不惩罚失败，还鼓励每个人客观地从失败中爬起来。我们要有一种心态，要认为挫折不是一种惩罚，而是一个学习的机会。</p>
<p>　　当我回顾我一生的职业生涯，我想我学到最多的绝对不是来源于我的成功。反而是我在读博士的时候被评为最坏的老师，在一个公司做了一个很酷的技术却没有用，导致公司被卖掉、员工失业等等失败的经历让我学到了很多，超过了我在语音识别或者其他领域所取得的成就。所以一定要把握每一个失败的时候，让自己过渡好每一个痛苦的时期。然后要能有正面的思想，要站起来，要正视自己的错误，能够从错误中学习。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>　　最后我做一个总结：在21世纪里面，我们需要认真读书的同学，但是我们更需要创新实践的人才。我们需要每一科的专才，但是我们更需要跨领域合成者。我们需要高智商的人，但是更需要高情商的人。我们需要每一个学生能够高效能地理解，但是未来你们更需要高效能地沟通。<br>　　毕业后，当然要找一个热门的工作，但是更重要的是你要热爱你的工作。不要再继续做一个只会被动听话的学生，而要做一个积极主动的学生。不要只是做一个小心翼翼的人，而要做一个乐观向上的人。</p>
<p>&nbsp;</p>
<img src ="http://www.cnitblog.com/shanshan/aggbug/43903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-05-19 21:31 <a href="http://www.cnitblog.com/shanshan/archive/2008/05/19/43903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc与matlab引擎联合编程</title><link>http://www.cnitblog.com/shanshan/archive/2008/05/11/43604.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Sun, 11 May 2008 13:18:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/05/11/43604.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/43604.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/05/11/43604.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/43604.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/43604.html</trackback:ping><description><![CDATA[<p><span><strong><span>一、Matlab</span><span>与</span><span><a href="http://www.it-waibao.com/it-waibao/termCommentate/100_124_14079.html">VC</a></span><span>混合编程的实现方法</span></strong><span> </span></span><span><br><span>Matlab</span></span><span><span>作为控制系统设计的一种通用工具，它可以和</span><span><a href="http://www.it-waibao.com/it-waibao/termCommentate/100_124_14079.html">VC</a></span><span>方便的进行连接。一般而言，</span><span>Matlab</span><span>与</span><span>VC</span><span>混合编程的实现方法主要有以下三种方法：（</span><span>1</span><span>）通过引擎（</span><span>Engine</span><span>）</span><span>,</span><span>采用客户机</span><span><a href="http://www.it-waibao.com/it-waibao/termCommentate/fwq/index.html"><span><span>服务器</span></span></a></span><span>的计算模式，通过</span><span>Window</span><span>的</span><span>ActiveX</span><span>通道和</span><span>Matlab</span><span>进行连接。具体应用时，往往在</span><span>VC</span><span>中设计程序框架，以编译的程序作为前端客户机；通过调用</span><span>Matlab</span><span>引擎在后台实现与服务器的连接，实现动态通信（</span><span>2</span><span>）应用</span><span>Matlab</span><span>数学函数库，</span><span>Matlab</span><span>中包含了内容丰富的函数库，而且还提供了与</span><span>VC</span><span>的数学函数接口，用户可以方便的在</span><span>VC</span><span>的</span><span>IDE</span><span>（集成开发环境）中调用。（</span><span>3</span><span>）通过</span><span>DLL</span><span>实现</span><span>VC</span><span>与</span><span>Matlab</span><span>的混合编程。</span><span>DLL</span><span>是一个可执行的</span><span><a href="http://www.it-waibao.com/it-waibao/termCommentate/100_124_14156.html"><span><span>二进制文件</span></span></a></span><span>。把很多通用的功能放在</span><span>DLL</span><span>中，可以供多个应用程序调用，这样可以很好的减少外部</span><span><a href="http://www.it-waibao.com/it-waibao/termCommentate/mutilplayer/100_557_11331.html"><span><span>存储空间</span></span></a></span><span>的占有量，并实现代码的</span><span><a href="http://www.it-waibao.com/it-waibao/termCommentate/100_124_14177.html"><span><span>共享</span></span></a>[2]</span><span>。在上述三种方法中，第一种方法对调用</span><span>Matlab</span><span>的工具箱很实用，所有在进行控制系统的设计和分析时，一般都是通过调用</span><span>Matlab</span><span>引擎（</span><span>Engine</span><span>）来实现的。本文主要介绍采用通过引擎（</span><span>Engine</span><span>）来实现</span><span>VC</span><span>与</span><span>Matlab</span><span>的混合编程。</span><span> <br></span></span><span><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt"><br>二、配置编译器</span></strong><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt"><br></span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">　</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">　</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">要在</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">VC</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">中成功编译</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Matlab</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">引擎程序，必须包含引擎头文件</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">engine.h</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">并引入</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Matlab</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">对应的库文件</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">libmx.lib</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">、</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">libmat.lib</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">、</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">libeng.lib</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">。具体的说，打开一个工程后，做如下设置（以</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">VC6</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">为例）：</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt"><br></span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">　　</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">1) </span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">通过菜单工程</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">/</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">选项，打开设置属性页，进入</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Directories</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">页面，在目录下拉列表框中选择</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Include files</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">，添加路径：</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">"C:\matlab\extern\include"</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">（假定</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">matlab</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">安装在</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">C:\matlab</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">目录）。</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt"><br></span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">　　</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">2) </span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">选择</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Library files</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">，添加路径：</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">C:\matlab\extern\lib\win32\microsoft\msvc60</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">。</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt"><br></span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">　　</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">3) </span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">通过菜单工程</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">/</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">设置，打开工程设置属性页，进入</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Link</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">页面，在</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Object/library modules</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">编辑框中，添加文件名</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">libmx.lib libmat.lib libeng.lib</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">。</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt"><br></span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">　　以上步骤</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">1)</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">、</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">2)</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">只需设置一次，而步骤</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">3)</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">对每个工程都要单独设定，对于其它</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">C++</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">编译器如</span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">Borland C++ builder</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt">，设置大体相同，不再赘述。<br></span><span lang=EN-US style="FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt"><o:p></o:p></span><br><strong>三、编程实例<br></strong>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;#include "engine.h"//matlab引擎"<br><br>&nbsp;&nbsp;&nbsp;double *coeff;<br>&nbsp;&nbsp;&nbsp;double delt[9];<br>&nbsp; &nbsp;delt[0] = log(1);<br>&nbsp;&nbsp; delt[1] = log(sqrt(2));<br>&nbsp;&nbsp; delt[2] = log(2);<br>&nbsp;&nbsp; delt[3] = log(sqrt(5));<br>&nbsp;&nbsp; delt[4] = log(sqrt(8));<br>&nbsp; &nbsp;delt[5] = log(3);<br>&nbsp;&nbsp; delt[6] = log(sqrt(10));<br>&nbsp;&nbsp; delt[7] = log(sqrt(13));<br>&nbsp; &nbsp;delt[8] = log(sqrt(18));<br><br>&nbsp;&nbsp;&nbsp;Engine *ep; //定义Matlab引擎指针。<br>&nbsp;if (!(ep=engOpen(NULL))) //测试是否启动Matlab引擎成功。<br>&nbsp;{<br>&nbsp;&nbsp;MessageBox(NULL,"Engine message","Can't start Matlab engine!",MB_OK);<br>&nbsp;&nbsp;exit(1);<br>&nbsp;}<br>&nbsp;&nbsp;mxArray *x=NULL;//Matlab引擎中用的是mxArray型的数据<br>&nbsp;&nbsp;x = mxCreateDoubleMatrix(1,9,mxREAL);<br>&nbsp;&nbsp;memcpy((char*)mxGetPr(x),(char*)delt,9*sizeof(double));<br>&nbsp;&nbsp;engPutVariable(ep,"x",x);</span></p>
<p><span>&nbsp;&nbsp;mxArray *y=NULL;<br>&nbsp;&nbsp;y = mxCreateDoubleMatrix(1,9,mxREAL);</span></p>
<p><span>&nbsp;&nbsp;mxArray *result=NULL;<br>&nbsp;&nbsp;result = mxCreateDoubleMatrix(1,2,mxREAL);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;//例一<br>&nbsp;&nbsp;&nbsp;mxArray *X=NULL;//Matlab引擎中用的是mxArray型的数据<br>&nbsp;&nbsp;&nbsp;&nbsp;X = mxCreateDoubleMatrix(1,9,mxREAL);//生成矩阵传递参数给matlab<br>&nbsp;&nbsp;&nbsp;&nbsp;memcpy((char*)mxGetPr(X),(char*)test,9*sizeof(double));<br>&nbsp;&nbsp;&nbsp;&nbsp;engPutVariable(ep,"X",X);//向matlab引擎参数<br>&nbsp;&nbsp;&nbsp; engEvalString(ep,"T=5*X;");//向matlab引擎发送命令<br>&nbsp;&nbsp;&nbsp; engEvalString(ep,"plot(X,T);");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;//例二<br>&nbsp;&nbsp;&nbsp; &#8230;&#8230;&#8230;&#8230;<br></span>&nbsp;&nbsp;&nbsp;&nbsp;memcpy((char*)mxGetPr(y),(char*)Var,9*sizeof(double));//Var的值是有段程序计算的，未写出<br>&nbsp;&nbsp;&nbsp;&nbsp;engPutVariable(ep,"y",y);<br>&nbsp;&nbsp;&nbsp;&nbsp;engEvalString(ep,"p=polyfit(x,y,1);");<br>&nbsp;&nbsp;&nbsp;&nbsp;result = engGetVariable(ep,"p");//从matlab引擎里取数据<br>&nbsp;&nbsp;&nbsp;&nbsp;coeff = (double *)mxGetData(result);<br>&nbsp;&nbsp;&nbsp;&nbsp;H[i][j] = coeff[0];<br><br>&nbsp;&nbsp;&nbsp;//释放这些矩阵<br>&nbsp;&nbsp;&nbsp;mxDestroyArray(y);<br>&nbsp;&nbsp;&nbsp;mxDestroyArray(result);<br>&nbsp;&nbsp;&nbsp;mxDestroyArray(x);<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;engClose(ep); //关闭Matlab引擎<br>&nbsp; &#8230;&#8230;&#8230;&#8230;&#8230;&#8230;<br><br><strong>错误问题：</strong><br>关键问题在于matlab的版本上,要看这样一句错误提示:<br>F:\chen101903\chen101903Dlg.cpp(205) : error C2065: 'mxSetName_is_obsolete' : undeclared identifier<br><br>如果你到matrix.h中看mxSetName的声明会发现有这样一句<br><br>#ifndef matrix_h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//判断是不是和V5兼容<br>#define V5_COMPT<br>#define matrix_h<br>.........................<br>#else<br><br>#define mxSetName mxSetName_is_obsolete//走这个预处理分枝就等于没有声明mxSetName()了<br>&nbsp; <br>#endif<br><br>于是matrix.h里就相当于根本没有定义mxSetName这个东西.你只需要在<br>#include "matrix.h"<br>之前加一句<br>#define V5_COMPT&nbsp;&nbsp;&nbsp; 就可以了&nbsp;<br>形式如下：<br>#ifndef matrix_h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>#define V5_COMPT<br>#define matrix_h<br><br></p>
<img src ="http://www.cnitblog.com/shanshan/aggbug/43604.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-05-11 21:18 <a href="http://www.cnitblog.com/shanshan/archive/2008/05/11/43604.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc与matlab接口之com（转帖）</title><link>http://www.cnitblog.com/shanshan/archive/2008/05/10/43581.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Sat, 10 May 2008 09:01:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/05/10/43581.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/43581.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/05/10/43581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/43581.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/43581.html</trackback:ping><description><![CDATA[实际上VC与matlab的接口实现方法有很多种，matcom只是其中一种，本文再介绍一种比较容易实现的方法：COM接口方法。COM（Compponent Object Model组件对象模型）是一项比较复杂的技术，详细讲的话几本书也讲不完，所以在这里不作介绍，本文通过一个例子详细介绍如何在matlab下做COM组件，以及如何在VC中调用COM组件。<br>　　首先在Matlab编辑器里编辑m函数文件：启动matlab-&gt;File-&gt;New-&gt;M-file 函数内容如图1：该函数无输入输出参数，文件保存为huatu.m。<br><br><img height=383 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img1.jpg" width=637 border=0><br>图1 m函数huatu.m<br><br>在matlab下建立COM组件，步骤如下： <br>1、在matlab command window 输入如下命令： <br>&gt;&gt; comtool <br>出现com编辑界面，如图2： <br><br><img height=424 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img2.jpg" width=535 border=0><br>图2 com组件编辑界面<br><br>2、新建工程：File-&gt;New Project&#8230;,如图3。 <br><img height=485 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img3.jpg" width=281 border=0><br>图2 com组件属性设置<br><br>3、设置组件属性，在"Component name"项中填写组件名称"component",这时候会自动生成类"component",在"Class name"项中填写类名称"huatu",如图4, <br><img height=490 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img4.jpg" width=284 border=0><br>图4 com组件属性设置1<br><br>　　为了便于区分,选中"Classes"中的"component",点击&#8220;remove&#8221;按钮，将类component移除，再点击"Add&gt;&gt;"添加新类huatu,结果如图5。点击"OK"，接下来出现一个对话框，选择"Yes". <br><img height=484 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img5.jpg" width=282 border=0><br>图5 com组件属性设置2<br><br>4. 添加文件：选中左边工作区的"huatu",点击Project-&gt;Add File&#8230;，选择已经编辑好的函数文件huatu.m,如图6。需要注意的是m文件必须是m函数,否则会报错,如果是m脚本文件的话,只需要改为无输入输出参数的m函数即可。 <br><img height=439 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img6.jpg" width=632 border=0><br>图6 添加m文件<br><br>5、生成 com组件:点击Build-&gt;COM Object&#8230;，结果如图7。 <br><img height=434 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img7.jpg" width=851 border=0><br>图7 <br><br>com组件已经由matlab做好，默认的保存位置为：matlab安装位置\work\component。 <br><br>VC中调用COM组件,步骤如下： <br>1、在VC中建立名为ComHuaTu的基于对话框的MFC(exe)。 <br>2、面板上添加一个名为&#8220;画图&#8221;的button按钮，如图8。 <br><br><img height=335 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img8.jpg" width=491 border=0><br>图7 工程界面 <br><br>3、将component_idl.h 和component_idl_i.c文件拷贝到VC建立的工程ComHuaTu目录下。两文件默认目录为<matlab根目录>\work\component\src <br>4、将上面两文件加入工程：工程-&gt;添加工程-&gt;Files，选择刚刚拷到目录下的component_idl.h 和component_idl_i.c文件。 <br>5、将目录<matlab根目录>/extern/include/下的mwcomtypes.h拷贝到工程ComHuaTu目录下，并加入到工程中，方法同上。 <br>6、为程序添加头文件component_idl.h 、component_idl_i.c和mwcomtypes.h，结果如图9 <br><img height=262 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img9.jpg" width=497 border=0><br>图9 添加头文件<br><br><br>
<pre></pre>
7、按钮画图函数添加代码： <br><img height=165 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img10.jpg" width=747 border=0><br>图10 添加按钮函数代码<br><br>函数代码的意义涉及到COM，正在写VC调用COM组件所涉及到的有关COM方面的知识。 <br>8、设置预编译头文件：工程-&gt;设置(快捷键Alt+F7)，选择C/C++项precomplied Headers，设置如图11 <br><img height=456 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img11.jpg" width=680 border=0><br>图11 预编译头文件设置<br><br>9、编译、连接、运行，结果如图12。 <br><img height=595 src="http://www.vckbase.com/document/journal/vckbase43/images/VCMatlab3img12.jpg" width=761 border=0><br>图11 运行结果<br><br>　　可以看出利用VC调用com组件的方式来调用matlab比较简单，而且几乎支持matlab所有的函数，在m文件较大、用matcom、调用math library或使用mcc方式无法实现的时候，推荐使用。需要说明的是，以上程序拷到另一台机器上是无法直接运行的，因为COM组件没有新机器上注册，如果要在另一台机器上使用的话，还需要打包安装COM组件，并且由于本程序代码很简单，所以也就不提供源程序了，自己可以动手做一下。 <br>　　本人正在写一本关于VC和matlab接口方面的书，估计年底完稿，详细介绍VC和matlab接口的几种方法，并提供详细的例子，例子都是我自己写过的，欢迎大家提供些好的意见和建议。<br>我的QQ:44760299,<br>邮箱:c_dinco@sina.com。 <br><br><br>以下是我遇到的错误及解决方法：<br>错误：<br>component_idl_i.obj&nbsp;:&nbsp;error&nbsp;LNK2005:&nbsp;_CLSID_huatu&nbsp;already&nbsp;defined&nbsp;in&nbsp;ComHuaTDlg.obj<br>component_idl_i.obj&nbsp;:&nbsp;error&nbsp;LNK2005:&nbsp;_LIBID_component&nbsp;already&nbsp;defined&nbsp;in&nbsp;ComHuaTDlg.obj<br>component_idl_i.obj&nbsp;:&nbsp;error&nbsp;LNK2005:&nbsp;_IID_Ihuatu&nbsp;already&nbsp;defined&nbsp;in&nbsp;ComHuaTDlg.obj<br>Debug/ComHuaT.exe&nbsp;:&nbsp;fatal&nbsp;error&nbsp;LNK1169:&nbsp;one&nbsp;or&nbsp;more&nbsp;multiply&nbsp;defined&nbsp;symbols&nbsp;found<br>Error&nbsp;executing&nbsp;link.exe.<br><br>ComHuaT.exe&nbsp;-&nbsp;4&nbsp;error(s),&nbsp;0&nbsp;warning(s)<br><br>解决方法：ComHuaTuDlg.cpp中将 #include&nbsp;"component_idl_i.c" 注释掉就可以了<br>即//#include&nbsp;"component_idl_i.c"<br>
<img src ="http://www.cnitblog.com/shanshan/aggbug/43581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-05-10 17:01 <a href="http://www.cnitblog.com/shanshan/archive/2008/05/10/43581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>虚拟现实新进展</title><link>http://www.cnitblog.com/shanshan/archive/2008/04/27/42821.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Sun, 27 Apr 2008 07:03:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/04/27/42821.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/42821.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/04/27/42821.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/42821.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/42821.html</trackback:ping><description><![CDATA[&nbsp;
<p><strong><span>3D</span></strong><strong><span>人体洞穴&#8221;医疗新突破</span></strong></p>
<p><span>近日世界著名的虚拟技术研究机构加拿大卡尔加里大学的科学家们把洞穴虚拟现实系统（<span>cave automated virtual environment</span>）应用于医学研究获得初步成功，成功制造出了第一个数字模拟人体，这将极大的发展数字虚拟技术在医学临床领域的应用和发展。</span></p>
<p><span>科学家们在一个黑暗的被称为洞穴（ 洞穴虚拟现实系统<span>cave automated virtual environment</span>）的房间里，通过数字虚拟成像技术成功制造出了是一个比真人还大的虚拟病人——洞穴人（<span>caveman</span>）。</span></p>
<p><span>洞穴人（<span>caveman</span>）目前是世界上最先进的数字模型人体，经过长时间的研究卡尔加里大学的科学家和图形艺术家成功的将虚拟现实技术应用到了医学临床领域。这个数字模型人体可以作为医学解剖的标本和模型，它能够清楚地将病人的每一个器官，骨骼，神经和生物系统详细的显示，甚至可以模拟病人的动态行为。 <span>&nbsp;</span></span></p>
<p><span>在&#8220;洞穴&#8221;的地板和墙壁上，投影机全方位的展示了虚拟病人的全部内容，甚至可以将虚拟病人的神经组织和生物系统进行<span>10</span>倍的放大。科学家认为数字模型人体目前可以作为医生的训练工具，但最主要的作用在于通过从磁共振成像扫描来真实的反映病人身体的实际数据和图像，帮助医生对病人的实际情况作出准确的诊断。</span></p>
<p><span>卡尔加里大学的科学家们打算下一步将在系统中加入触觉反馈传感器，使洞穴人（<span>caveman</span>）模拟动态的过程，如呼吸和血液流动，使医生可以在治疗前后，对病人的状况作出准确的判断和预测。</span></p>
<p>&nbsp;</p>
<p><strong><span>21</span></strong><strong><span>世纪对人类发展必不可少的</span><span>4</span></strong><strong><span>大主题</span></strong><span>：可持续发展、卫生、减少脆弱性以及生活愉悦。委员会决定不为这些技术挑战项目进行排名，挑战项目名单包括：增强虚拟现实、生产可负担得起的太阳能、以核聚变提供能源、开发碳隔离技术、管理氮循环、全球都可用到洁净水、恢复和改善城市基础设施、推进医疗信息学、研制更好的药物、人脑逆向工程、防止核恐怖行动、确保网络空间安全、推进个性化学习以及发展科学发现工具。</span></p>
<img src ="http://www.cnitblog.com/shanshan/aggbug/42821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-04-27 15:03 <a href="http://www.cnitblog.com/shanshan/archive/2008/04/27/42821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC调试篇</title><link>http://www.cnitblog.com/shanshan/archive/2008/04/25/42753.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Fri, 25 Apr 2008 11:17:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/04/25/42753.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/42753.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/04/25/42753.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/42753.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/42753.html</trackback:ping><description><![CDATA[难怪很多前辈说调试是一个程序员最基本的技能，其重要性甚至超过学习一门语言。不会调试的程序员就意味着他即使会一门语言，却不能编制出任何好的软件。&nbsp; <br>
<p align=center>我以前接触的程序大多是有比较成形的思路和方法，调试起来出的问题都比较小，最近这个是我自己慢慢摸索调试，接触了很多新的调试方法，并查了很多前辈的总结，受益匪浅，总结以前的和新的收获如下：<br><br><strong>VC调试篇</strong><br><span><br><strong>设置</strong><br></span><span>为了调试一个程序，首先必须使程序中包含调试信息。一般情况下，一个从</span><span>AppWizard</span><span>创建的工程中包含的</span><span>Debug Configuration</span><span>自动包含调试信息，但是是不是</span><span>Debug</span><span>版本并不是程序包含调试信息的决定因素，程序设计者可以在任意的</span><span>Configuration</span><span>中增加调试信息，包括</span><span>Release</span><span>版本。</span><span><br></span><span>为了增加调试信息，可以按照下述步骤进行：</span><span> </span></p>
<ul type=disc>
    <li><span>打开</span><span>Project settings</span><span>对话框（可以通过快捷键</span><span>ALT+F7</span><span>打开，也可以通过</span><span>IDE</span><span>菜单</span><span>Project/Settings</span><span>打开</span><span>) </span>
    <li><span>选择</span><span>C/C++</span><span>页，</span><span>Category</span><span>中选择</span><span>general </span><span>，则出现一个</span><span>Debug Info</span><span>下拉列表框，可供选择的调试信息</span><span> </span><span>方式包括：</span><span> <br></span><span>　</span><span> </span></li>
</ul>
<table cellSpacing=0 cellPadding=0 width=553 border=1>
    <tbody>
        <tr>
            <td width=54>
            <p align=center><strong><span>命令行</span></strong></p>
            </td>
            <td width=138>
            <p align=center><strong><span>Project settings</span></strong></p>
            </td>
            <td width=360>
            <p align=center><strong><span>说明</span></strong></p>
            </td>
        </tr>
        <tr>
            <td width=54>
            <p align=left><span>无</span></p>
            </td>
            <td width=138>
            <p align=left><span>None</span></p>
            </td>
            <td width=360>
            <p align=left><span>没有调试信息</span></p>
            </td>
        </tr>
        <tr>
            <td width=54>
            <p align=left><span>/Zd</span></p>
            </td>
            <td width=138>
            <p align=left><span>Line Numbers Only</span></p>
            </td>
            <td width=360>
            <p align=left><span>目标文件或者可执行文件中只包含全局和导出符号以及代码行信息，不包含符号调试信息</span></p>
            </td>
        </tr>
        <tr>
            <td width=54>
            <p align=left><span>/Z7</span></p>
            </td>
            <td width=138>
            <p align=left><span>C 7.0- Compatible</span></p>
            </td>
            <td width=360>
            <p align=left><span>目标文件或者可执行文件中包含行号和所有符号调试信息，包括变量名及类型，函数及原型等</span></p>
            </td>
        </tr>
        <tr>
            <td width=54>
            <p align=left><span>/Zi</span></p>
            </td>
            <td width=138>
            <p align=left><span>Program Database</span></p>
            </td>
            <td width=360>
            <p align=left><span>创建一个程序库</span><span>(PDB)</span><span>，包括类型信息和符号调试信息。</span></p>
            </td>
        </tr>
        <tr>
            <td width=54>
            <p align=left><span>/ZI</span></p>
            </td>
            <td width=138>
            <p align=left><span>Program Database for Edit and Continue</span></p>
            </td>
            <td width=360>
            <p align=left><span>除了前面</span><span>/Zi</span><span>的功能外，这个选项允许对代码进行调试过程中的修改和继续执行。这个选项同时使</span><span>#pragma</span><span>设置的优化功能无效</span></p>
            </td>
        </tr>
    </tbody>
</table>
<ul type=disc>
    <li><span>选择</span><span>Link</span><span>页，选中复选框</span><span>"Generate Debug Info"</span><span>，这个选项将使连接器把调试信息写进可执行文件和</span><span>DLL </span>
    <li><span>如果</span><span>C/C++</span><span>页中设置了</span><span>Program Database</span><span>以上的选项，则</span><span>Link incrementally</span><span>可以选择。选中这个选项，将使程序可以在上一次编译的基础上被编译（即增量编译），而不必每次都从头开始编译。</span><span> </span></li>
</ul>
<p align=left><strong><span>调试方法：</span></strong></p>
<p align=left><span>1</span><span>、使用</span><span> Assert</span><span>（原则：尽量简单）　</span><span>assert</span><span>只在</span><span>debug</span><span>下生效，</span><span>release</span><span>下不会被编译。</span></p>
<p align=left><span>2</span><span>、防御性的编程</span></p>
<p align=left><span>3</span><span>、使用</span><span>Trace<br>4</span><span>、用</span><span>GetLastError</span><span>来检测返回值，通过得到错误代码来分析错误原因</span><span><br>5</span><span>、把错误信息记录到文件中</span></p>
<p>&nbsp;</p>
<p align=left><strong><span>位置断点（</span></strong><strong><span>Location Breakpoint</span></strong><strong><span>）</span></strong><span> <br>&nbsp;&nbsp;</span><span>大家最常用的断点是普通的位置断点，在源程序的某一行按</span><span>F9</span><span>就设置了一个位置断点。但对于很多问题，这种朴素的断点作用有限。譬如下面这段代码：</span><span> </span></p>
<p align=left><span>void CForDebugDlg::OnOK() </span></p>
<p align=left><span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>for (int i = 0; i &lt; 1000; i++)<span>&nbsp;&nbsp;&nbsp; </span>//A</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int k = i * 10 - 2;<span> </span>//B</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>SendTo(k);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//C</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int tmp = DoSome(i);<span> </span>//D</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int j = i / tmp;<span>&nbsp;&nbsp;&nbsp; </span>//E</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p><span>&nbsp;&nbsp;</span><span>执行此函数，程序崩溃于</span><span>E</span><span>行，发现此时</span><span>tmp</span><span>为</span><span>0</span><span>，假设</span><span>tmp</span><span>本不应该为</span><span>0</span><span>，怎么这个时候为</span><span>0</span><span>呢？所以最好能够跟踪此次循环时</span><span>DoSome</span><span>函数是如何运行的，但由于是在循环体内，如果在</span><span>E</span><span>行设置断点，可能需要按</span><span>F5</span><span>（</span><span>GO</span><span>）许多次。这样手要不停的按，很痛苦。使用</span><span>VC6</span><span>断点修饰条件就可以轻易解决此问题。步骤如下。</span><span> <br>&nbsp;&nbsp;1 Ctrl+B</span><span>打开断点设置框，如下图：</span><span> <br><img src="http://www.vckbase.com/document/journal/vckbase36/images/debug1.jpg"><br><br><strong><span>Figure 1</span></strong></span><span>设置高级位置断点</span><span> <br>&nbsp;&nbsp;2 </span><span>然后选择</span><span>D</span><span>行所在的断点，然后点击</span><span>condition</span><span>按钮，在弹出对话框的最下面一个编辑框中输入一个很大数目，具体视应用而定，这里</span><span>1000</span><span>就够了。</span><span> <br>&nbsp;&nbsp;3 </span><span>按</span><span>F5</span><span>重新运行程序，程序中断。</span><span>Ctrl+B</span><span>打开断点框，发现此断点后跟随一串说明：</span><span>...487 times remaining</span><span>。意思是还剩下</span><span>487</span><span>次没有执行，那就是说执行到</span><span>513</span><span>（</span><span>1000</span><span>－</span><span>487</span><span>）次时候出错的。因此，我们按步骤</span><span>2</span><span>所讲，更改此断点的</span><span>skip</span><span>次数</span><span>,</span><span>将</span><span>1000</span><span>改为</span><span>513</span><span>。</span><span> <br>&nbsp;&nbsp;4 </span><span>再次重新运行程序，程序执行了</span><span>513</span><span>次循环，然后自动停在断点处。这时，我们就可以仔细查看</span><span>DoSome</span><span>是如何返回</span><span>0</span><span>的。这样，你就避免了手指的痛苦，节省了时间。</span><span> <br>&nbsp;&nbsp;</span><span>再看位置断点其他修饰条件。如</span><strong><span>Figure 1</span></strong><span>所示，在</span><span>&#8220;Enter the expression to be evaluated:&#8221;</span><span>下面，可以输入一些条件，当这些条件满足时，断点才启动。譬如，刚才的程序，我们需要</span><span>i</span><span>为</span><span>100</span><span>时程序停下来，我们就可以输入在编辑框中输入</span><span>&#8220;i==<st1:chmetcnv w:st="on" TCSC="0" NumberType="1" Negative="False" HasSpace="False" SourceValue="100" UnitName="&#8221;">100&#8221;</st1:chmetcnv></span><span>。</span><span> <br>&nbsp;&nbsp;</span><span>另外，如果在此编辑框中如果只输入变量名称，则变量发生改变时，断点才会启动。这对检测一个变量何时被修改很方便，特别对一些大程序。</span><span> <br>&nbsp;&nbsp;</span><span>用好位置断点的修饰条件，可以大大方便解决某些问题。</span></p>
<p align=left><strong><span>数据断点（</span></strong><strong><span>Data Breakpoint</span></strong><strong><span>）</span></strong><span> <span><br>&nbsp;&nbsp;</span></span><span>软件调试过程中，有时会发现一些数据会莫名其妙的被修改掉（如一些数组的越界写导致覆盖了另外的变量），找出何处代码导致这块内存被更改是一件棘手的事情（如果没有调试器的帮助）。恰当运用数据断点可以快速帮你定位何时何处这个数据被修改。譬如下面一段程序：</span><span> </span></p>
<p align=left><span>#include "stdafx.h"</span></p>
<p align=left><span>#include </span></p>
<p align=left>&nbsp;<span>int main(int argc, char* argv[])</span></p>
<p align=left><span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>char szName1[10];</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>char szName2[4];</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>strcpy(szName1,"shenzhen");<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printf("%s\n", szName1);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//A</span></p>
<p align=left>&nbsp;<span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>strcpy(szName2, "vckbase");<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//B</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printf("%s\n", szName1);</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printf("%s\n", szName2);</span></p>
<p align=left>&nbsp;<span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return 0;</span></p>
<p align=left><span>}</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span>&nbsp;&nbsp;</span><span>这段程序的输出是</span><span> </span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>szName1: shenzhen</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>szName1: ase</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>szName2: vckbase</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>szName1</span><span>何时被修改呢？因为没有明显的修改</span><span>szName1</span><span>代码。我们可以首先在</span><span>A</span><span>行设置普通断点，</span><span>F5</span><span>运行程序，程序停在</span><span>A</span><span>行。然后我们再设置一个数据断点。如下图：</span><span> <img src="http://www.vckbase.com/document/journal/vckbase36/images/debug2.jpg"><br><br><strong><span>Figure 2</span></strong><span> </span></span><span>数据断点</span><span> <br>&nbsp;&nbsp;F5</span><span>继续运行，程序停在</span><span>B</span><span>行，说明</span><span>B</span><span>处代码修改了</span><span>szName1</span><span>。</span><span>B</span><span>处明明没有修改</span><span>szName1</span><span>呀？但调试器指明是这一行，一般不会错，所以还是静下心来看看程序，哦，你发现了：</span><span>szName2</span><span>只有</span><span>4</span><span>个字节，而</span><span>strcpy</span><span>了</span><span>7</span><span>个字节，所以覆写了</span><span>szName1</span><span>。</span><span> <br>&nbsp;&nbsp;</span><span>数据断点不只是对变量改变有效，还可以设置变量是否等于某个值。譬如，你可以将</span><span>Figure 2</span><span>中红圈处改为条件</span><span>&#8221;szName2[0]==''''y''''&#8220;,</span><span>那么当</span><span>szName2</span><span>第一个字符为</span><span>y</span><span>时断点就会启动。</span><span> <br>&nbsp;&nbsp;</span><span>可以看出，数据断点相对位置断点一个很大的区别是不用明确指明在哪一行代码设置断点。</span></p>
<p align=left><span>其他调试手段：系统提供一系列特殊的函数或者宏来处理<span>Debug</span>版本相关的信息，如下： </span></p>
<table cellSpacing=0 cellPadding=0 width="99%" border=1>
    <tbody>
        <tr>
            <td width="23%">
            <p align=center><strong><span>宏名<span>/</span>函数名</span></strong></p>
            </td>
            <td width="76%">
            <p align=center><strong><span>说明</span></strong></p>
            </td>
        </tr>
        <tr>
            <td width="23%">
            <p align=center><span>TRACE</span></p>
            </td>
            <td width="76%">
            <p align=left><span>使用方法和<span>printf</span>完全一致，他在<span>output</span>框中输出调试信息</span></p>
            </td>
        </tr>
        <tr>
            <td width="23%">
            <p align=center><span>ASSERT</span></p>
            </td>
            <td width="76%">
            <p align=left><span>它接收一个表达式，如果这个表达式为<span>TRUE</span>，则无动作，否则中断当前程序执行。对于系统中出现这个宏 导致的中断，应该认为你的函数调用未能满足系统的调用此函数的前提条件。例如，对于一个还没有创建的窗口调用<span>SetWindowText</span>等。</span></p>
            </td>
        </tr>
        <tr>
            <td width="23%">
            <p align=center><span>VERIFY</span></p>
            </td>
            <td width="76%">
            <p align=left><span>和<span>ASSERT</span>功能类似，所不同的是，在<span>Release</span>版本中，<span>ASSERT</span>不计算输入的表达式的值，而<span>VERIFY</span>计算表达式的值。</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><strong>&nbsp;</strong></p>
<p><strong><span>值</span></strong><span><br><strong>Watch</strong><br>VC</span><span>支持查看变量、表达式和内存的值。所有这些观察都必须是在断点中断的情况下进行。</span><span><br></span><span>观看变量的值最简单，当断点到达时，把光标移动到这个变量上，停留一会就可以看到变量的值。</span><span><br>VC</span><span>提供一种被成为</span><span>Watch</span><span>的机制来观看变量和表达式的值。在断点状态下，在变量上单击右键，选择</span><span>Quick Watch</span><span>，</span><span> </span><span>就弹出一个对话框，显示这个变量的值。</span><span><br></span><span>单击</span><span>Debug</span><span>工具条上的</span><span>Watch</span><span>按钮，就出现一个</span><span>Watch</span><span>视图（</span><span>Watch1,Watch2,Watch3,Watch4</span><span>），在该视图中输入变量或者表达式，就可以观察</span><span> </span><span>变量或者表达式的值。注意：这个表达式不能有副作用，例如</span><span>++</span><span>运算符绝对禁止用于这个表达式中，因为这个运算符将修改变量的值，导致</span><span> </span><span>软件的逻辑被破坏。</span><span><br><strong>Memory</strong><br></span><span>由于指针指向的数组，</span><span>Watch</span><span>只能显示第一个元素的值。为了显示数组的后续内容，或者要显示一片内存的内容，可以使用</span><span>memory</span><span>功能。在</span><span> Debug</span><span>工具条上点</span><span>memory</span><span>按钮，就弹出一个对话框，在其中输入地址，就可以显示该地址指向的内存的内容。</span><strong><span><br>Varibles</span></strong><span><br>Debug</span><span>工具条上的</span><span>Varibles</span><span>按钮弹出一个框，显示所有当前执行上下文中可见的变量的值。特别是当前指令涉及的变量，以红色显示。</span><span><br></span><strong><span>寄存器</span></strong><span><br>Debug</span><span>工具条上的</span><span>Reigsters</span><span>按钮弹出一个框，显示当前的所有寄存器的值。</span></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span>调试技巧</span></strong><span>：</span></p>
<p><span>1</span><span>、<span>VC++</span>中<span>F5</span>进行调试运行</span></p>
<p><span>a)</span><span>、在<span>output Debug</span>窗口中可以看到用<span>TRACE</span>打印的信息</span></p>
<p><span>b)</span><span>、<span> Call Stack</span>窗口中能看到程序的调用堆栈</span></p>
<p><span>2</span><span>、当<span>Debug</span>版本运行时发生崩溃，选择<span>retry</span>进行调试，通过看<span>Call Stack</span>分析出错的位置及原因</span></p>
<p><span>3</span><span>、使用映射文件调试</span></p>
<p><span>a)</span><span>、创建映射文件：<span>Project settings</span>中<span>link</span>项，选中<span>Generate mapfile</span>，输出程序代码地址：<span>/MAPINFO: LINES</span>，得到引出序号：<span>/MAPINFO: EXPORTS</span>。</span></p>
<p><span>b)</span><span>、程序发布时，应该把所有模块的映射文件都存档。</span></p>
<p><span>c)</span><span>、查看映射文件：见&#8221; 通过崩溃地址找出源代码的出错行&#8221;文件。</span></p>
<p><span>4</span><span>、可以调试的<span>Release</span>版本</span></p>
<p><span>　　<span>Project settings</span>中<span>C++</span>项的<span>Debug Info</span>选择为<span>Program Database</span>，<span>Link</span>项的<span>Debug</span>中选择<span>Debug Info</span>和<span>Microsoft format</span>。</span></p>
<p><span>5</span><span>、查看<span>API</span>的错误码，在<span>watch</span>窗口输入<span>@err</span>可以查看或者<span>@err,hr</span>，其中&#8221;<span>,hr</span>&#8221;表示错误码的说明。</span></p>
<p><span>6</span><span>、<span>Set Next Statement</span>：该功能可以直接跳转到指定的代码行执行，一般用来测试异常处理的代码。</span></p>
<p><span>7</span><span>、调试内存变量的变化：当内存发生变化时停下来。？？？</span></p>
<p align=left><strong><span>进程控制</span></strong><span><br>VC</span><span>允许被中断的程序继续运行、单步运行和运行到指定光标处，分别对应快捷键</span><span>F5</span><span>、</span><span>F10/F11</span><span>和</span><span>CTRL+F10</span><span>。各个快捷键功能如下：</span><span> <br></span><span>　</span><span> </span></p>
<table cellSpacing=0 cellPadding=0 width="91%" border=1>
    <tbody>
        <tr>
            <td width="30%">
            <p align=center><strong><span>快捷键</span></strong></p>
            </td>
            <td width="70%">
            <p align=center><strong><span>说明</span></strong></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>F5</span></p>
            </td>
            <td width="70%">
            <p align=left><span>调试</span><span>/</span><span>继续运行</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>F10</span></p>
            </td>
            <td width="70%">
            <p align=left><span>单步，如果涉及到子函数，不进入子函数内部</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>F11</span></p>
            </td>
            <td width="70%">
            <p align=left><span>单步，如果涉及到子函数，进入子函数内部</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>CTRL+F10</span></p>
            </td>
            <td width="70%">
            <p align=left><span>运行到当前光标处。</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>F7</span></p>
            </td>
            <td width="70%">
            <p align=left><span>重建</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>F9</span></p>
            </td>
            <td width="70%">
            <p align=left><span>设置断点</span><span>/</span><span>清除断点</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>Ctrl+Shift+F9</span></p>
            </td>
            <td width="70%">
            <p align=left><span>清除所有断点</span></p>
            </td>
        </tr>
        <tr>
            <td width="30%">
            <p align=center><span>Shift+F5</span></p>
            </td>
            <td width="70%">
            <p align=left><span>结束调试</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><span>Call Stack<br></span><span>调用堆栈反映了当前断点处函数是被那些函数按照什么顺序调用的。单击</span><span>Debug</span><span>工具条上的</span><span>Call stack</span><span>就显示</span><span>Call Stack</span><span>对话框。在</span><span>CallStack</span><span>对话框中显示了一个调用系列，最上面的是当前函数，往下依次是调用函数的上级函数。单击这些函数名可以跳到对应的函数中去。</span></p>
<p align=left><strong><span>关注</span></strong><span><br></span><span>一个好的程序员不应该把所有的判断交给编译器和调试器，应该在程序中自己加以程序保护和错误定位，具体措施包括：</span><span> </span></p>
<ul type=disc>
    <li><span>对于所有有返回值的函数，都应该检查返回值，除非你确信这个函数调用绝对不会出错，或者不关心它是否出错。</span><span> </span>
    <li><span>一些函数返回错误，需要用其他函数获得错误的具体信息。例如</span><span>accept</span><span>返回</span><span>INVALID_SOCKET</span><span>表示</span><span>accept</span><span>失败，为了查明</span><span> </span><span>具体的失败原因，应该立刻用</span><span>WSAGetLastError</span><span>获得错误码，并针对性的解决问题。</span><span> </span>
    <li><span>有些函数通过异常机制抛出错误，应该用</span><span>TRY-CATCH</span><span>语句来检查错误</span><span> </span>
    <li><span>程序员对于能处理的错误，应该自己在底层处理，对于不能处理的，应该报告给用户让他们决定怎么处理。如果程序出了异常，</span><span> </span><span>却不对返回值和其他机制返回的错误信息进行判断，只能是加大了找错误的难度。</span><span> </span></li>
</ul>
<p align=left><strong><span>另外</span></strong><span>：</span><span>VC</span><span>中要编制程序不应该一开始就写</span><span>cpp/h</span><span>文件，而应该首先创建一个合适的工程。因为只有这样，</span><span>VC</span><span>才能选择合适的编译、连接</span><span> </span><span>选项。对于加入到工程中的</span><span>cpp</span><span>文件，应该检查是否在第一行显式的包含</span><span>stdafx.h</span><span>头文件，这是</span><span>Microsoft Visual Studio</span><span>为了加快编译</span><span> </span><span>速度而设置的预编译头文件。在这个</span><span>#include "stdafx.h"</span><span>行前面的所有代码将被忽略，所以其他头文件应该在这一行后面被包含。</span><span><br></span><span>对于</span><span>.c</span><span>文件，由于不能包含</span><span>stdafx.h</span><span>，因此可以通过</span><span>Project settings</span><span>把它的预编译头设置为</span><span>&#8220;</span><span>不使用</span><span>&#8221;</span><span>，方法是：</span><span> </span></p>
<ul type=disc>
    <li><span>弹出</span><span>Project settings</span><span>对话框</span><span> </span>
    <li><span>选择</span><span>C/C++ </span>
    <li><span>Category</span><span>选择</span><span>Precompilation Header </span>
    <li><span>选择不使用预编译头。</span><span> </span></li>
</ul>
<p><strong><span>便于调试的代码风格</span></strong><span>：</span></p>
<p><span>不用全局变量 </span></p>
<p><span>所有变量都要初始化，成员变量在构造函数中初始化<span> </span></span></p>
<p><span>尽量使用<span>const </span></span></p>
<p><span>详尽的注释</span></p>
<p>&nbsp;</p>
<p><strong><span>总结</span></strong><span> <br>&nbsp;&nbsp;</span><span>调试最重要的还是你要思考，要猜测你的程序可能出错的地方，然后运用你的调试器来证实你的猜测。</span><strong></strong></p>
<p>&nbsp;</p>
<img src ="http://www.cnitblog.com/shanshan/aggbug/42753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-04-25 19:17 <a href="http://www.cnitblog.com/shanshan/archive/2008/04/25/42753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>新的IT博客，开始记录我的心得</title><link>http://www.cnitblog.com/shanshan/archive/2008/04/23/42665.html</link><dc:creator>shanshan</dc:creator><author>shanshan</author><pubDate>Wed, 23 Apr 2008 13:35:00 GMT</pubDate><guid>http://www.cnitblog.com/shanshan/archive/2008/04/23/42665.html</guid><wfw:comment>http://www.cnitblog.com/shanshan/comments/42665.html</wfw:comment><comments>http://www.cnitblog.com/shanshan/archive/2008/04/23/42665.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/shanshan/comments/commentRss/42665.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/shanshan/services/trackbacks/42665.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><br>&nbsp;&nbsp;&nbsp;以前C++的东西没有学好，现在编起程序来着实比较费劲，看看了下面这个还很有帮助。<br>&nbsp;&nbsp;&nbsp;在<span lang=EN-US>MFC</span>中，很多类都是需要你继承的，它们的成员函数很多都要重载，比如编写<span lang=EN-US>MFC</span>应用程序最常用的<span lang=EN-US>CView::OnDraw(CDC*)</span>函数，就必须重载使用。把它定义为虚函数（实际上，在<span lang=EN-US>MFC</span>中<span lang=EN-US>OnDraw</span>不仅是虚函数，还是纯虚函数），可以保证时刻调用的是用户自己编写的<span lang=EN-US>OnDraw</span>。虚函数的重要用途在这里可见一斑。虚函数虚就虚在所谓&#8220;推迟联编&#8221;或者&#8220;动态联编&#8221;上，一个类函数的调用并不是在编译时刻被确定的，而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数，所以被成为&#8220;虚&#8221;函数。基类声明的虚函数，在派生类中也是虚函数，即使不再使用<span lang=EN-US>virtual</span>关键字。<br>&nbsp;&nbsp; &nbsp;下面这个是转的vc文档中心的帖子，很通俗很到位。<br><font size=3>一、 基本概念<br>&nbsp;&nbsp;&nbsp; 首先，C++通过虚函数实现多态."无论发送消息的对象属于什么类，它们均发送具有同一形式的消息，对消息的处理方式可能随接手消息的对象而变"的处理方式被称为多态性。"在某个基类上建立起来的类的层次构造中，可以对任何一个派生类的对象中的同名过程进行调用，而被调用的过程提供的处理可以随其所属的类而变。"虚函数首先是一种成员函数，它可以在该类的派生类中被重新定义并被赋予另外一种处理功能。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"> 二、 虚函数的定义与派生类中的重定义 </font>
<pre>class 类名{
public:
virtual 成员函数说明；
}
class 类名：基类名{
public:
virtual 成员函数说明；
}
</pre>
三、 虚函数在内存中的结构<br><br>1．我们先看一个例子：
<pre>#include "iostream.h"
#include "string.h"
class A {
public:
virtual void fun0() { cout &lt;&lt; "A::fun0" &lt;&lt; endl; }
};
int main(int argc, char* argv[])
{
A  a;
cout &lt;&lt; "Size of A = " &lt;&lt; sizeof(a) &lt;&lt; endl;
return 0;
}      </pre>
结果如下：Size of A = 4<br><br>2．如果再添加一个虚函数：virtual void fun1() { cout &lt;&lt; "A::fun" &lt;&lt; endl;}<br>得到相同的结果。如果去掉函数前面的virtual修饰符
<pre>class A {
public:
void fun0() { cout &lt;&lt; "A::fun0" &lt;&lt; endl; }
};
int main(int argc, char* argv[])
{
A  a;
cout &lt;&lt; "Size of A = " &lt;&lt; sizeof(a) &lt;&lt; endl;
return 0;
}      </pre>
结果如下：Size of A = 1<br>&nbsp;<br>3．在看下面的结果：
<pre>class A {
public:
virtual void fun0() { cout &lt;&lt; "A::fun0" &lt;&lt; endl; }
int a;
int b;
};
int main(int argc, char* argv[])
{
A  a;
cout &lt;&lt; "Size of A = " &lt;&lt; sizeof(a) &lt;&lt; endl;
return 0;
}      </pre>
结果如下：Size of A = 12 <br><br>其实虚函数在内存中结构是这样的:<br><br><img src="http://www.vckbase.com/document/journal/vckbase27/images/virtualimg1.gif" border=0><br>图一<br><br>&nbsp;&nbsp;&nbsp; 在window2000下指针在内存中占4个字节，虚函数在一个虚函数表(VTABLE)中保存函数地址。在看下面例子。
<pre>class A {
public:
virtual void fun0() { cout &lt;&lt; "A::fun0" &lt;&lt; endl; }
virtual void fun1() { cout &lt;&lt; "A::fun1" &lt;&lt; endl; }
int a;
int b;
};
int main(int argc, char* argv[])
{
A  a;
cout &lt;&lt; "Size of A = " &lt;&lt; sizeof(a) &lt;&lt; endl;
return 0;
}
</pre>
结果如下：结果如下： <br>Size of A = 4<br><br>&nbsp;&nbsp;&nbsp; 虚函数的内存结构如下，你也可以通过函数指针，先找到虚函数表(VTABLE),然后访问每个函数地址来验证这种结构，在国外网站作者是：Zeeshan Amjad写的"ATL on the Hood中有详细介绍"<br><br><img src="http://www.vckbase.com/document/journal/vckbase27/images/virtualimg2.gif" border=0><br>图二<br><br>4．我们再来看看继承中虚函数的内存结构，先看下面的例子
<pre>class A {
public:
virtual void f() { }
};
class B {
public:
virtual void f() { }
};
class C {
public:
virtual void f() { }
};
class Drive : public A, public B, public C {
};
int main() {
Drive d;
cout &lt;&lt; "Size of A = " &lt;&lt; sizeof(d) &lt;&lt; endl;
return 0;
}      </pre>
结果如下：Size&nbsp;of A&nbsp;= 12 ，相信大家一看下面的结构图就会很清楚， <br><br><img src="http://www.vckbase.com/document/journal/vckbase27/images/virtualimg3.gif" border=0><br>图三 <br><br></span>
<img src ="http://www.cnitblog.com/shanshan/aggbug/42665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/shanshan/" target="_blank">shanshan</a> 2008-04-23 21:35 <a href="http://www.cnitblog.com/shanshan/archive/2008/04/23/42665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>