﻿<?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++博客-RTY 实践出真知-随笔分类-C/C++</title><link>http://www.cppblog.com/lauer3912/category/15568.html</link><description>没有理由不学习</description><language>zh-cn</language><lastBuildDate>Mon, 21 Jul 2014 02:53:07 GMT</lastBuildDate><pubDate>Mon, 21 Jul 2014 02:53:07 GMT</pubDate><ttl>60</ttl><item><title>Dynamic Library Design Guidelines (Xcode)</title><link>http://www.cppblog.com/lauer3912/archive/2012/09/13/190472.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Thu, 13 Sep 2012 00:58:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/09/13/190472.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/190472.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/09/13/190472.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/190472.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/190472.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Dynamic Library Design GuidelinesDynamic libraries, in addition to grouping common functionality, help reduce an app&#8217;s launch time. However, when designed improperly, dynamic libraries can deg...&nbsp;&nbsp;<a href='http://www.cppblog.com/lauer3912/archive/2012/09/13/190472.html'>阅读全文</a><img src ="http://www.cppblog.com/lauer3912/aggbug/190472.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-09-13 08:58 <a href="http://www.cppblog.com/lauer3912/archive/2012/09/13/190472.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Qt internal error: qt_menu.nib could not be loaded. </title><link>http://www.cppblog.com/lauer3912/archive/2012/06/06/177793.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Wed, 06 Jun 2012 06:55:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/06/06/177793.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/177793.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/06/06/177793.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/177793.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/177793.html</trackback:ping><description><![CDATA[<span style="font-family: Arial, FreeSans, Helvetica, sans-serif; font-size: 13px; line-height: 17px; background-color: #f0f0f0; ">"Qt internal error: qt_menu.nib could not be loaded. The .nib file should be placed in QtGui.framework/Versions/Current/Resources/ or in the resources directory of your applicaiton bundle."<br /></span><img src ="http://www.cppblog.com/lauer3912/aggbug/177793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-06-06 14:55 <a href="http://www.cppblog.com/lauer3912/archive/2012/06/06/177793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Cocoa读取和写入plist文件</title><link>http://www.cppblog.com/lauer3912/archive/2012/05/27/176331.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Sun, 27 May 2012 01:09:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/05/27/176331.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/176331.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/05/27/176331.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/176331.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/176331.html</trackback:ping><description><![CDATA[<div>http://www.cocoachina.com/b/?p=237<br /><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; ">plist文件是标准的xml文件，在cocoa中可以很简单地使用。这里介绍一下使用方法：</p><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; ">以下代码在Mac和iPhone中均适用。</p><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; "></p><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; ">写入plist文件：</p><div no=""  objc"="" style="background-color: #ffffff; overflow: auto; white-space: nowrap; margin-bottom: 1em; position: relative; font-family: Helvetica, monospace; font-size: 12px; color: #35383d; line-height: 17px; "><ol style="margin: 0px; padding: 0px 0px 0.5em 1em; border-left-style: none; list-style-type: none; "><li style="padding: 2px 0px 2px 15px; list-style-type: none; background-image: url(http://www.cocoachina.com/b/wp-content/themes/illacrimo/images/PostContentLiIco.png); line-height: 15px; color: #4c4c4c; background-position: 0% 0%; background-repeat: no-repeat no-repeat; "><div style="background-image: none; color: #000000; padding-left: 5px; "><span style="color: #0000ff; ">NSMutableDictionary</span>*&nbsp;dict&nbsp;=&nbsp;<span style="color: #005000; ">[</span>&nbsp;<span style="color: #005000; ">[</span>&nbsp;<span style="color: #0000ff; ">NSMutableDictionary</span>&nbsp;<span style="color: #0000ff; ">alloc</span>&nbsp;<span style="color: #005000; ">]</span>&nbsp;<span style="color: #0000ff; ">initWithContentsOfFile</span>:@<span style="color: #7f2d00; ">"/Sample.plist"</span>&nbsp;<span style="color: #005000; ">]</span>;</div></li><li style="padding: 2px 0px 2px 15px; list-style-type: none; background-image: url(http://www.cocoachina.com/b/wp-content/themes/illacrimo/images/PostContentLiIco.png); line-height: 15px; color: #4c4c4c; background-position: 0% 0%; background-repeat: no-repeat no-repeat; "><div style="background-image: none; color: #000000; padding-left: 5px; "><span style="color: #005000; ">[</span>&nbsp;dict&nbsp;<span style="color: #0000ff; ">setObject</span>:@<span style="color: #7f2d00; ">"Yes"</span>&nbsp;<span style="color: #0000ff; ">forKey</span>:@<span style="color: #7f2d00; ">"RestartSpringBoard"</span>&nbsp;<span style="color: #005000; ">]</span>;</div></li><li style="padding: 2px 0px 2px 15px; list-style-type: none; background-image: url(http://www.cocoachina.com/b/wp-content/themes/illacrimo/images/PostContentLiIco.png); line-height: 15px; color: #4c4c4c; background-position: 0% 0%; background-repeat: no-repeat no-repeat; "><div style="background-image: none; color: #000000; padding-left: 5px; "><span style="color: #005000; ">[</span>&nbsp;dict&nbsp;<span style="color: #0000ff; ">writeToFile</span>:@<span style="color: #7f2d00; ">"/Sample.plist"</span>&nbsp;<span style="color: #0000ff; ">atomically</span>:<span style="color: #0000ff; ">YES</span>&nbsp;<span style="color: #005000; ">]</span>;</div></li></ol></div><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; ">&nbsp;</p><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; ">读取plist文件：</p><div no=""  objc"="" style="background-color: #ffffff; overflow: auto; white-space: nowrap; margin-bottom: 1em; position: relative; font-family: Helvetica, monospace; font-size: 12px; color: #35383d; line-height: 17px; "><ol style="margin: 0px; padding: 0px 0px 0.5em 1em; border-left-style: none; list-style-type: none; "><li style="padding: 2px 0px 2px 15px; list-style-type: none; background-image: url(http://www.cocoachina.com/b/wp-content/themes/illacrimo/images/PostContentLiIco.png); line-height: 15px; color: #4c4c4c; background-position: 0% 0%; background-repeat: no-repeat no-repeat; "><div style="background-image: none; color: #000000; padding-left: 5px; "><span style="color: #0000ff; ">NSMutableDictionary</span>*&nbsp;dict&nbsp;=&nbsp;&nbsp;<span style="color: #005000; ">[</span>&nbsp;<span style="color: #005000; ">[</span>&nbsp;<span style="color: #0000ff; ">NSMutableDictionary</span>&nbsp;<span style="color: #0000ff; ">alloc</span>&nbsp;<span style="color: #005000; ">]</span>&nbsp;<span style="color: #0000ff; ">initWithContentsOfFile</span>:@<span style="color: #7f2d00; ">"/Sample.plist"</span>&nbsp;<span style="color: #005000; ">]</span>;</div></li><li style="padding: 2px 0px 2px 15px; list-style-type: none; background-image: url(http://www.cocoachina.com/b/wp-content/themes/illacrimo/images/PostContentLiIco.png); line-height: 15px; color: #4c4c4c; background-position: 0% 0%; background-repeat: no-repeat no-repeat; "><div style="background-image: none; color: #000000; padding-left: 5px; "><span style="color: #0000ff; ">NSString</span>*&nbsp;<span style="color: #0000ff; ">object</span>&nbsp;=&nbsp;<span style="color: #005000; ">[</span>&nbsp;dict&nbsp;<span style="color: #0000ff; ">objectForKey</span>:@<span style="color: #7f2d00; ">"RestartSpringBoard"</span>&nbsp;<span style="color: #005000; ">]</span>;</div></li></ol></div><p style="font-size: 12px; line-height: 17px; color: #35383d; font-family: Myriad, 'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; ">&nbsp;</p></div><img src ="http://www.cppblog.com/lauer3912/aggbug/176331.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-05-27 09:09 <a href="http://www.cppblog.com/lauer3912/archive/2012/05/27/176331.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么叫IOC（编程术语)</title><link>http://www.cppblog.com/lauer3912/archive/2012/05/15/174960.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 15 May 2012 05:11:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/05/15/174960.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/174960.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/05/15/174960.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/174960.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/174960.html</trackback:ping><description><![CDATA[<h1><div style="text-align: left;"><a id="cb_post_title_url" href="http://www.cnblogs.com/jazzka702/archive/2009/06/17/1504756.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #6466b3; text-decoration: none; ">什么叫IOC（编程术语</a>)<br /><div><span style="font-size: 10pt; ">IoC就是Inversion of Control，控制反转。在Java开发中，IoC意味着将你设计好的类交给系统去控制，而不是在你的类内部控制。这称为控制反转。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">下面我们以几个例子来说明什么是IoC</span></div><div></div><div></div><div><span style="font-size: 10pt; ">假设我们要设计一个Girl和一个Boy类，其中Girl有kiss方法，即Girl想要Kiss一个Boy。那么，我们的问题是，Girl如何能够认识这个Boy？</span></div><div></div><div></div><div><span style="font-size: 10pt; ">在我们中国，常见的MM与GG的认识方式有以下几种&nbsp;</span></div><div><span style="font-size: 10pt; ">1 青梅竹马； 2 亲友介绍； 3 父母包办&nbsp;</span></div><div><span style="font-size: 10pt; ">那么哪一种才是最好呢？</span></div><div></div><div></div><div><span style="font-size: 10pt; ">青梅竹马：Girl从小就知道自己的Boy。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">public class Girl {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; void kiss(){&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Boy boy = new Boy();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; }&nbsp;</span></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div></div><div><span style="font-size: 10pt; ">然而从开始就创建的Boy缺点就是无法在更换。并且要负责Boy的整个生命周期。如果我们的Girl想要换一个怎么办？（严重不支持Girl经常更换Boy,#_#）</span></div><div></div><div></div><div><span style="font-size: 10pt; ">亲友介绍：由中间人负责提供Boy来见面</span></div><div></div><div></div><div><span style="font-size: 10pt; ">public class Girl {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;void kiss(){&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Boy boy = BoyFactory.createBoy();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;}&nbsp;</span></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div></div><div><span style="font-size: 10pt; ">亲友介绍，固然是好。如果不满意，尽管另外换一个好了。但是，亲友BoyFactory经常是以Singleton的形式出现，不然就是，存在于Globals，无处不在，无处不能。实在是太繁琐了一点，不够灵活。我为什么一定要这个亲友掺和进来呢？为什么一定要付给她介绍费呢？万一最好的朋友爱上了我的男朋友呢？</span></div><div></div><div></div><div><span style="font-size: 10pt; ">父母包办：一切交给父母，自己不用费吹灰之力，只需要等着Kiss就好了。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">public class Girl {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;void kiss(Boy boy){&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// kiss boy&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;boy.kiss();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;}&nbsp;</span></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div></div><div><span style="font-size: 10pt; ">Well，这是对Girl最好的方法，只要想办法贿赂了Girl的父母，并把Boy交给他。那么我们就可以轻松的和Girl来Kiss了。看来几千年传统的父母之命还真是有用哦。至少Boy和Girl不用自己瞎忙乎了。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">这就是IOC，将对象的创建和获取提取到外部。由外部容器提供需要的组件。&nbsp;</span></div><div></div><div></div><div><span style="font-size: 10pt; ">我们知道好莱坞原则：&#8220;Do not call us, we will call you.&#8221; 意思就是，You, girlie, do not call the boy. We will feed you a boy。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">我们还应该知道依赖倒转原则即 Dependence Inversion Princinple，DIP</span></div><div></div><div></div><div><span style="font-size: 10pt; ">Eric Gamma说，要面向抽象编程。面向接口编程是面向对象的核心。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">组件应该分为两部分，即 Service, 所提供功能的声明 Implementation, Service的实现</span></div><div></div><div></div><div><span style="font-size: 10pt; ">好处是：多实现可以任意切换，防止 &#8220;everything depends on everything&#8221; 问题．即具体依赖于具体。&nbsp;</span></div><div></div><div></div><div><span style="font-size: 10pt; ">所以，我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话，还可以kiss可爱的kitten和慈祥的grandmother。</span></div><div><span style="font-size: 10pt; ">二、IOC的type</span></div><div>&nbsp;</div><div></div><div><span style="font-size: 10pt; ">IoC的Type指的是Girl得到Boy的几种不同方式。我们逐一来说明。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">IOC type 0：不用IOC&nbsp;</span></div><div><span style="font-size: 10pt; ">public class Girl implements Servicable {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;private Kissable kissable;&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;public Girl() {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kissable = new Boy();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;}&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;public void kissYourKissable() {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kissable.kiss();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;}&nbsp;</span></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div><span style="font-size: 10pt; ">Girl自己建立自己的Boy，很难更换，很难共享给别人，只能单独使用，并负责完全的生命周期。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">IOC type 1，先看代码：代码</span></div><div></div><div></div><div><span style="font-size: 10pt; ">public class Girl implements Servicable {&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; Kissable kissable;&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;public void service(ServiceManager mgr) {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kissable = (Kissable) mgr.lookup(&#8220;kissable&#8221;);&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; }&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;public void kissYourKissable() {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kissable.kiss();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;}&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div></div><div><span style="font-size: 10pt; ">这种情况出现于Avalon Framework。一个组件实现了Servicable接口，就必须实现service方法，并传入一个ServiceManager。其中会含有需要的其它组件。只需要在service方法中初始化需要的Boy。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">另外，J2EE中从Context取得对象也属于type 1。它依赖于配置文件。</span></div><div></div><div></div><div><span style="font-size: 10pt; ">IOC type 2：</span></div><div></div><div></div><div><span style="font-size: 10pt; ">public class Girl {&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;private Kissable kissable;&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;public void setKissable(Kissable kissable) {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.kissable = kissable;&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; }&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; public void kissYourKissable() {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kissable.kiss();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; }&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div></div><div><span style="font-size: 10pt; ">Type 2出现于Spring Framework，是通过JavaBean的set方法来将需要的Boy传递给Girl。它必须依赖于配置文件。</span></div><div></div><div><span style="font-size: 10pt; ">IOC type 3:</span></div><div></div><div></div><div><span style="font-size: 10pt; ">public class Girl {&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; private Kissable kissable;&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; public Girl(Kissable kissable) {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.kissable = kissable;&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; }&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp;public void kissYourKissable() {&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kissable.kiss();&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp; }&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">}</span></div><div></div><div></div><div><span style="font-size: 10pt; ">这就是PicoContainer的组件 。通过构造函数传递Boy给Girl&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">PicoContainer container = new DefaultPicoContainer();&nbsp;</span></div><div><span style="font-size: 10pt; ">container.registerComponentImplementation(Boy.class);&nbsp;</span></div><div><span style="font-size: 10pt; ">container.registerComponentImplementation(Girl.class);&nbsp;</span></div><div><span style="font-size: 10pt; ">Girl girl = (Girl) container.getComponentInstance(Girl.class);&nbsp;</span></div><div><span style="font-size: 10pt; ">girl.kissYourKissable();</span></div><div></div><div><span style="font-size: 10pt; ">参考资料&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">1 http://www.picocontainer.org/presentations/JavaPolis2003.ppt&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; http://www.picocontainer.org/presentations/JavaPolis2003.pdf&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">2 DIP， Robert C Martin, Bob大叔的优秀论文&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp;http://www.objectmentor.com/resources/articles/dip.pdf&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">3 Dependency Injection 依赖注射，Matrin Fowler对DIP的扩展&nbsp;</span></div><div><span style="font-size: 10pt; ">&nbsp; &nbsp;http://www.martinfowler.com/articles/injection.html&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">4 IOC框架&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">PicoContainer 优秀的IOC框架&nbsp;</span></div><div><span style="font-size: 10pt; ">http://picocontainer.org/&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">Avalon&nbsp;</span></div><div><span style="font-size: 10pt; ">http://avalon.apache.org/&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">Spring Framework&nbsp;</span></div><div><span style="font-size: 10pt; ">http://www.springframework.org/&nbsp;</span></div><div></div><div><span style="font-size: 10pt; ">HiveMind&nbsp;</span></div><div><span style="font-size: 10pt; ">http://jakarta.apache.org/commons/hivemind&nbsp;</span></div><div>分类: C#</div></div><div style="text-align: left;"></div><pre style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre-wrap; word-wrap: break-word; color: #393939; font-size: 14px; font-weight: normal; text-align: left; background-color: #faf7ef; "><h1><a id="cb_post_title_url" href="http://www.cnblogs.com/jazzka702/archive/2009/06/17/1504756.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #ff6600; text-decoration: none; ">什么叫IOC（编程术语</a></h1><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; clear: both; color: #464646; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; "></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-right: 2px; padding-bottom: 5px; padding-left: 5px; line-height: 1.5; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: black; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; "><div id="cnblogs_post_body" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><pre style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre-wrap; word-wrap: break-word; "><br /><br /><br /></pre></div><div id="blog_post_info_block" style="margin-top: 20px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><div id="blog_post_info" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></div></div></div></pre></h1><img src ="http://www.cppblog.com/lauer3912/aggbug/174960.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-05-15 13:11 <a href="http://www.cppblog.com/lauer3912/archive/2012/05/15/174960.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> otool 与dylib</title><link>http://www.cppblog.com/lauer3912/archive/2012/05/07/173940.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Mon, 07 May 2012 15:25:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/05/07/173940.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/173940.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/05/07/173940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/173940.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/173940.html</trackback:ping><description><![CDATA[<blockquote style="font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">Shared by eric&nbsp;<br />mac osx的dyld是挺烦的</blockquote><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">所谓dylib，就是bsd风格的动态库。基本可以认为等价于windows的dll和linux的so。mac基于bsd，所以也使用的是dylib。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">如果你需要引用一个第三方的dylib，在xcode下编译出cocoa程序，在本机上运行是不会出问题的。但是发布出来，给其他用户用，就可能出问题。因为用户不一定有这个库。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">这个问题给我造成了相当的困扰，我到现在也没找到正规的方法。但是我确实解决了这个问题，虽然方法不一定正宗。不管怎么说，写下来，<strong>如果暂时没有更好的办法，那么先这样做。如果谁有更好的办法，也请一定不吝留言或邮件给我</strong>。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">我的办法是这样的:</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><br /><strong>1 otool -L yourapp.app/Contents/MacOS/yourapp</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">这一步的意思是对你编译出的app使用otool命令，以便获得依赖哪些dylib的信息。注意这个路径。cocoa的app在命令行下表现为目录。所有相关的东西都在里面。<br />结果如下所示：<br />yourapp.app/Contents/MacOS/yourapp:<br />/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 12.0.0)<br /><span style="color: #ff0000; ">/usr/local/lib/lib01.dylib (compatibility version 0.0.0, current version 0.1.0)</span><br /><span style="color: #ff0000; ">/usr/local/lib/lib02.dylib (compatibility version 0.0.0, current version 0.1.0)</span><br /><span style="color: #ff0000; ">/usr/local/lib/lib03.dylib (compatibility version 0.0.0, current version 0.1.0)</span><br />/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)<br />/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)<br />/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)<br />/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 476.0.0)<br />/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 949.0.0)<br />/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 677.12.0)</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">注意我标红的地方。假如lib01,lib02,lib03是本程序引用的第三方库，那么在这个程序里面，他们的引用地址是位于/usr/local/lib上的。这是开发机上的安装情况。而使用这个程序的客户机未必安装这些东西，所以程序就要出错。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">显然，我们需要做2件事。a 把这些库附带在app上 b 把他们的引用地址修改到正确的位置。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><strong>2 mkdir yourapp.app/Contents/dylib</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">在编译出来的app中，创建dylib目录</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">然后把所有需要的库复制过去</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">cp /usr/local/lib/lib01.dylib yourapp.app/Contents/dylib/<br />cp /usr/local/lib/lib02.dylib yourapp.app/Contents/dylib/<br />cp /usr/local/lib/lib03.dylib yourapp.app/Contents/dylib/</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><strong>3 install_name_tool -change /usr/local/lib/lib01.dylib @loader_path/../dylib/lib01.dylib "yourapp.app/Contents/MacOS/yourapp"<br /></strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">install_name_tool 是苹果提供的用来修改dylib安装名称的命令。这个命令执行之后，再用otool -L 就可以看到变化了</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">yourapp.app/Contents/MacOS/yourapp:<br />/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 12.0.0)<br /><span style="color: #ff0000; ">@loader_path/../dylib/lib01.dylib (compatibility version 0.0.0, current version 0.1.0)</span><br />/usr/local/lib/lib02.dylib (compatibility version 0.0.0, current version 0.1.0)<br />/usr/local/lib/lib03.dylib (compatibility version 0.0.0, current version 0.1.0)<br />/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)<br />/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)<br />/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)<br />/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 476.0.0)<br />/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 949.0.0)<br />/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 677.12.0)</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">注意标红的位置。已经变化了。@loader_path 指的是应用程序运行的位置，也就是yourapp.app/Contents/MacOS/yourapp，所以要用一个..，以便定位到第2步创建的dylib目录。<br />重复这个命令，修改lib02,lib03</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><br /><strong>4 otool -L yourapp.app/Contents/dylib/*.dylib</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">继续用otool 来检查dylib下面使用的第三方库是否还有其他依赖，install_name是否正确，重复1，2，3的步骤，把所需要的dylib复制过来，修改install_name。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">如果都改对了，那么这个app就附带上了dylib，可以在其他机器上正确运行了，不用非要寻找/usr/local/lib下面的库了。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><br />刚才我们修改的结果是一个build的结果。当然，每次build都这么折腾一下很麻烦。所以继续这样做：</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">1 前面的步骤得到了一个完整的dylib目录。把这个dylib复制一份备用。比如放在你的xcode项目下面。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">2 编写一个脚本：</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">mkdir "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/dylib"<br />cp -f /your/path/to/xcode_project_name/dylib/*.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/dylib/"</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">install_name_tool -change /usr/local/lib/lib01.dylib @loader_path/../dylib/lib01.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME"<br />(用这个格式重复前面对app使用过的dylib)</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">3 在xcode中，展开targets节点，右键点工程名称，在菜单中选Add-&gt;New Build Phasa-&gt;New Run Script Build Phasa，在打开的对话框里面，把刚才的脚本贴进去。如图所示。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">这个脚本会在build之后自动运行。不过我这里有个奇怪的问题，如果Shell里面写了/bin/sh，会报告找不到这个文件(实际上存在)，而让shell为空，反而可以正确的运行shell命令。<br /><a href="http://picasaweb.google.com/lh/photo/FwVjnl4gM7iRUH5yMbTXQA?feat=embedwebsite" style="color: #336699; text-decoration: none; "><img src="http://lh4.ggpht.com/_fMpSudYvJOo/Skq16lg_8yI/AAAAAAAAAhw/5PAtplmUj_Q/s400/Picture%205.png" alt="" style="border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; border-image: initial; " /></a></p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><a href="http://picasaweb.google.com/lh/photo/PO8ZsBhdcFBWogeMuu2cmQ?feat=embedwebsite" style="color: #336699; text-decoration: none; "><img src="http://lh6.ggpht.com/_fMpSudYvJOo/Skq16mBp44I/AAAAAAAAAh0/ASKXHFDGems/s400/Picture%206.png" alt="" style="border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; border-image: initial; " /></a></p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">经过这些处理，每次编译出来的app就可以拿到其他机器上运行了。可真够麻烦的...</p><img src ="http://www.cppblog.com/lauer3912/aggbug/173940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-05-07 23:25 <a href="http://www.cppblog.com/lauer3912/archive/2012/05/07/173940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>找不到 dirent.h 文件</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/28/172990.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Fri, 27 Apr 2012 22:42:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/28/172990.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/172990.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/28/172990.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/172990.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/172990.html</trackback:ping><description><![CDATA[转载：http://www.cnblogs.com/fzzl/archive/2009/07/14/1522913.html<br /><h1><a id="cb_post_title_url" href="http://www.cnblogs.com/fzzl/archive/2009/07/14/1522913.html">【转】vs2005下的dirent.h</a>&nbsp; 该方法同样适用于VS2008 及VS2010</h1> 	<div id="cnblogs_post_body"><p><a href="http://www.analogcn.com/Article/wz3/200802/20080202211037.html">http://www.analogcn.com/Article/wz3/200802/20080202211037.html</a><br /></p><p>&nbsp;</p> <p>dirent.h是gcc下的一个头文件，而在VS2005中是没有的。这个文件中封装了几个对目录进行操作函数：</p> <p>static DIR *opendir (const char *dirname);<br />static struct dirent *readdir (DIR *dirp);<br />static int closedir (DIR *dirp);</p> <p>&nbsp;对于在linux-&gt;windows之间进行程序移植来讲常常会造成一些困扰，在网上仔细搜了一下，发现原来已经有位好同志写了相应的移植代码，如下所示：</p> <p><br />typedef struct dirent {<br />&nbsp; /* name of current directory entry (a multi-byte character string) */<br />&nbsp; char d_name[MAX_PATH + 1];</p> <p>&nbsp; /* file attributes */<br />&nbsp; WIN32_FIND_DATA data;<br />} dirent;</p> <p><br />typedef struct DIR {<br />&nbsp; /* current directory entry */<br />&nbsp; dirent current;</p> <p>&nbsp; /* is there an un-processed entry in current? */<br />&nbsp; int cached;</p> <p>&nbsp; /* file search handle */<br />&nbsp; HANDLE search_handle;</p> <p>&nbsp; /* search pattern (3 = zero terminator + pattern "\\*") */<br />&nbsp; TCHAR patt[MAX_PATH + 3];<br />} DIR;</p> <p><br />static DIR *opendir (const char *dirname);<br />static struct dirent *readdir (DIR *dirp);<br />static int closedir (DIR *dirp);</p> <p><br />/* use the new safe string functions introduced in Visual Studio 2005 */<br />#if defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1400<br /># define STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)<br />#else<br /># define STRNCPY(dest,src,size) strncpy((dest),(src),(size))<br />#endif</p> <p><br />/*<br />&nbsp;* Open directory stream DIRNAME for read and return a pointer to the<br />&nbsp;* internal working area that is used to retrieve individual directory<br />&nbsp;* entries.<br />&nbsp;*/<br />static DIR*<br />opendir(<br />&nbsp;&nbsp;&nbsp; const char *dirname)<br />{<br />&nbsp; DIR *dirp;<br />&nbsp; assert (dirname != NULL);<br />&nbsp; assert (strlen (dirname) &lt; MAX_PATH);</p> <p>&nbsp; /* construct new DIR structure */<br />&nbsp; dirp = (DIR*) malloc (sizeof (struct DIR));<br />&nbsp; if (dirp != NULL) {<br />&nbsp;&nbsp;&nbsp; TCHAR *p;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; /* prepare search pattern */<br />#ifdef _UNICODE</p> <p>&nbsp;&nbsp;&nbsp; /* convert directory name to wide character string */<br />&nbsp;&nbsp;&nbsp; MultiByteToWideChar(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CP_ACP,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* code page */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* conversion flags */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirname,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* mb-string to convert */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* length of mb-string */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirp-&gt;patt,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* wc-string to produce */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAX_PATH);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* max length of wc-string */<br />&nbsp;&nbsp;&nbsp; dirp-&gt;patt[MAX_PATH] = '\0';<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; /* append search pattern to directory name */<br />&nbsp;&nbsp;&nbsp; p = wcschr (dirp-&gt;patt, '\0');<br />&nbsp;&nbsp;&nbsp; if (dirp-&gt;patt &lt; p&nbsp; &amp;&amp;&nbsp; *(p-1) != '\\'&nbsp; &amp;&amp;&nbsp; *(p-1) != ':') {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *p++ = '\\';<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; *p++ = '*';<br />&nbsp;&nbsp;&nbsp; *p = '\0';</p> <p>#else /* !_UNICODE */<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; /* take directory name... */<br />&nbsp;&nbsp;&nbsp; STRNCPY (dirp-&gt;patt, dirname, sizeof(dirp-&gt;patt));<br />&nbsp;&nbsp;&nbsp; dirp-&gt;patt[MAX_PATH] = '\0';<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; /* ... and append search pattern to it */<br />&nbsp;&nbsp;&nbsp; p = strchr (dirp-&gt;patt, '\0');<br />&nbsp;&nbsp;&nbsp; if (dirp-&gt;patt &lt; p&nbsp; &amp;&amp;&nbsp; *(p-1) != '\\'&nbsp; &amp;&amp;&nbsp; *(p-1) != ':') {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *p++ = '\\';<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; *p++ = '*';<br />&nbsp;&nbsp;&nbsp; *p = '\0';<br />&nbsp;&nbsp;&nbsp; <br />#endif /* !_UNICODE */</p> <p>&nbsp;&nbsp;&nbsp; /* open stream and retrieve first file */<br />&nbsp;&nbsp;&nbsp; dirp-&gt;search_handle = FindFirstFile (dirp-&gt;patt, &amp;dirp-&gt;current.data);<br />&nbsp;&nbsp;&nbsp; if (dirp-&gt;search_handle == INVALID_HANDLE_VALUE) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* invalid search pattern? */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free (dirp);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br />&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; /* there is an un-processed directory entry in memory now */<br />&nbsp;&nbsp;&nbsp; dirp-&gt;cached = 1;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp; }<br />&nbsp; return dirp;<br />}</p> <p> <br />/*<br />&nbsp;* Read a directory entry, and return a pointer to a dirent structure<br />&nbsp;* containing the name of the entry in d_name field.&nbsp; Individual directory<br />&nbsp;* entries returned by this very function include regular files,<br />&nbsp;* sub-directories, pseudo-directories "." and "..", but also volume labels,<br />&nbsp;* hidden files and system files may be returned.&nbsp; <br />&nbsp;*/<br />static struct dirent *<br />readdir(<br />&nbsp;&nbsp;&nbsp; DIR *dirp)<br />{<br />&nbsp; assert (dirp != NULL);</p> <p>&nbsp; if (dirp-&gt;search_handle == INVALID_HANDLE_VALUE) {<br />&nbsp;&nbsp;&nbsp; /* directory stream was opened/rewound incorrectly or it ended normally */<br />&nbsp;&nbsp;&nbsp; return NULL;<br />&nbsp; }</p> <p>&nbsp; /* get next directory entry */<br />&nbsp; if (dirp-&gt;cached != 0) {<br />&nbsp;&nbsp;&nbsp; /* a valid directory entry already in memory */<br />&nbsp;&nbsp;&nbsp; dirp-&gt;cached = 0;<br />&nbsp; } else {<br />&nbsp;&nbsp;&nbsp; /* read next directory entry from disk */<br />&nbsp;&nbsp;&nbsp; if (FindNextFile (dirp-&gt;search_handle, &amp;dirp-&gt;current.data) == FALSE) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* the very last file has been processed or an error occured */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FindClose (dirp-&gt;search_handle);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirp-&gt;search_handle = INVALID_HANDLE_VALUE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp; }</p> <p>&nbsp; /* copy directory entry to d_name */<br />#ifdef _UNICODE<br />&nbsp; <br />&nbsp; /* convert entry name to multibyte */<br />&nbsp; WideCharToMultiByte(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CP_ACP,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* code page */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* conversion flags */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirp-&gt;current.data.cFileName,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* wc-string to convert */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* length of wc-string */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirp-&gt;current.d_name,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* mb-string to produce */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAX_PATH,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* max length of mb-string */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* use sys default character */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* don't care&nbsp; */<br />&nbsp; dirp-&gt;current.d_name[MAX_PATH] = '\0';<br />&nbsp; <br />#else /* !_UNICODE */</p> <p>&nbsp; /* copy as a multibyte character string */<br />&nbsp; STRNCPY (dirp-&gt;current.d_name, dirp-&gt;current.data.cFileName, sizeof(dirp-&gt;current.d_name));<br />&nbsp; dirp-&gt;current.d_name[MAX_PATH] = '\0';</p> <p>#endif /* !_UNICODE */<br />&nbsp; <br />&nbsp; return &amp;dirp-&gt;current;<br />}</p> <p><br />/*<br />&nbsp;* Close directory stream opened by opendir() function.&nbsp; Close of the<br />&nbsp;* directory stream invalidates the DIR structure as well as any previously<br />&nbsp;* read directory entry.<br />&nbsp;*/<br />static int<br />closedir(<br />&nbsp;&nbsp;&nbsp; DIR *dirp)<br />{<br />&nbsp; assert (dirp != NULL);<br />&nbsp;<br />&nbsp; /* release search handle */<br />&nbsp; if (dirp-&gt;search_handle != INVALID_HANDLE_VALUE) {<br />&nbsp;&nbsp;&nbsp; FindClose (dirp-&gt;search_handle);<br />&nbsp;&nbsp;&nbsp; dirp-&gt;search_handle = INVALID_HANDLE_VALUE;<br />&nbsp; }</p> <p>&nbsp; /* release directory handle */<br />&nbsp; free (dirp);<br />&nbsp; return 0;<br />}<br /></p> <p>此文件可从<a href="http://www.softagalleria.net/dirent/index.en.html"><u>http://www.softagalleria.net/dirent/index.en.html</u></a>下载得到，直接将它放在VS2005的include目录就OK 了！</p><p style="margin-bottom:0pt; margin-top:0pt; "><a href="http://www.5678520.com/"><span style=" color:#0000ff; text-decoration:underline ;font-family:'宋体'; ">开网店</span></a><a href="http://www.5678520.com/"><span style=" color:#800080; text-decoration:underline ;font-family:'宋体'; ">http://www.5678520.com/</span></a><span style=" font-size:10.5000pt; font-family:'宋体'; ">怎么样开网店</span></p></div><img src ="http://www.cppblog.com/lauer3912/aggbug/172990.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-28 06:42 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/28/172990.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc调试窗口表达式格式化资料</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/24/172670.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 24 Apr 2012 14:37:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/24/172670.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/172670.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/24/172670.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/172670.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/172670.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 2011-04-15 11:09&nbsp;46人阅读&nbsp;评论(0)&nbsp;收藏&nbsp;举报摘自msdn，列在这里方便查阅。The following tables show the format specifiers recognized by the debugger.&nbsp;SpecifierFormatExpressionValue Displayedd,isigned...&nbsp;&nbsp;<a href='http://www.cppblog.com/lauer3912/archive/2012/04/24/172670.html'>阅读全文</a><img src ="http://www.cppblog.com/lauer3912/aggbug/172670.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-24 22:37 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/24/172670.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Context Operator (C/C++ Language Expressions)</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/24/172665.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 24 Apr 2012 13:42:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/24/172665.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/172665.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/24/172665.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/172665.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/172665.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HomeLibraryLearnDownloadsSupportCommunitySign in&nbsp;|&nbsp;中国（简体中文）&nbsp;|&nbsp;&nbsp;|&nbsp;MSDN LibraryDevelopment Tools and LanguagesVisual Studio 2008Visual StudioApplication Development in Visu...&nbsp;&nbsp;<a href='http://www.cppblog.com/lauer3912/archive/2012/04/24/172665.html'>阅读全文</a><img src ="http://www.cppblog.com/lauer3912/aggbug/172665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-24 21:42 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/24/172665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Managed Expressions in C++ (VC 2010 调试)</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/24/172664.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 24 Apr 2012 13:39:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/24/172664.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/172664.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/24/172664.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/172664.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/172664.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HomeLibraryLearnDownloadsSupportCommunitySign in&nbsp;|&nbsp;中国（简体中文）&nbsp;|&nbsp;&nbsp;|&nbsp;MSDN LibraryDevelopment Tools and LanguagesVisual Studio 2010Visual StudioApplication Development in Visu...&nbsp;&nbsp;<a href='http://www.cppblog.com/lauer3912/archive/2012/04/24/172664.html'>阅读全文</a><img src ="http://www.cppblog.com/lauer3912/aggbug/172664.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-24 21:39 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/24/172664.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Find path of an application</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/18/171908.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Wed, 18 Apr 2012 14:44:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/18/171908.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/171908.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/18/171908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/171908.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/171908.html</trackback:ping><description><![CDATA[<center style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; "><table width="823" border="0" cellpadding="0" cellspacing="0" style="font-size: 12px; margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><tbody><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><table width="100%" border="0" cellpadding="0" cellspacing="0" style="font-size: 12px; margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><tbody><tr><td width="350" valign="TOP" align="CENTER" style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><a href="http://lists.apple.com/" style="color: #000066; text-decoration: none; "><img src="http://lists.apple.com/images/mailing2.gif" alt="Mailing Lists: Apple Mailing Lists" width="350" height="85" border="0" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; " /></a><br /></td><td width="20" style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "></td><td width="200" valign="TOP" style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><img src="http://lists.apple.com/images/stamp.gif" alt="Image of Mac OS face in stamp" width="150" height="65" border="0" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; " /></td></tr></tbody></table></td></tr></tbody></table></center><table border="0" cellspacing="2" width="100%" style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; font-size: 12px; margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; color: #000000; "><tbody><tr><td align="right" valign="top" width="25%" bgcolor="#CCCCCC" style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">[<a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00036.html" style="color: #000066; text-decoration: none; ">Date Prev</a>][<a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00038.html" style="color: #000066; text-decoration: none; ">Date Next</a>][<a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00036.html" style="color: #000066; text-decoration: none; ">Thread Prev</a>][<a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00038.html" style="color: #000066; text-decoration: none; ">Thread Next</a>][<a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/index.html#00037" style="color: #000066; text-decoration: none; ">Date Index</a>][<a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/threads.html#00037" style="color: #000066; text-decoration: none; ">Thread Index</a>]</td></tr></tbody></table><h1>Re: Find path of an application</h1><hr style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><ul style="list-style-type: none; list-style-position: outside; list-style-image: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 1em; padding-left: 0px; font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; "><li style="padding-bottom: 0.3em; "><strong>Subject</strong>:&nbsp;<strong>Re: Find path of an application</strong></li><li style="padding-bottom: 0.3em; ">From: Terry Lambert &lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#109;&#97;&#105;&#108;&#64;&#104;&#105;&#100;&#100;&#101;&#110;" style="color: #000066; text-decoration: none; ">email@hidden</a>&gt;</li><li style="padding-bottom: 0.3em; ">Date: Tue, 16 Dec 2008 02:01:54 -0800</li><li style="padding-bottom: 0.3em; ">Delivered-to: email@hidden</li><li style="padding-bottom: 0.3em; ">Delivered-to: email@hidden</li></ul><hr style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>On Dec 16, 2008, at 1:00 AM, Rakesh Singhal wrote:</tt><blockquote style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; border-left-color: #5555ee; border-left-width: 0.2em; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0.85em; "><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">I am done with finding the process is running or not. Thanks a lot. Still I am stuck with second issue to find the path to my application in my system. Actually there are 3 steps:</pre><br /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">1. To know that application is running or not?  Now it is done. 2. If not then get the path of application where it was installed (user can change the path during installation). 3. Launch the application.</pre><br /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">My code is standard C++ tool so I want to use only C and C++ APIs. Please suggest me. </pre></blockquote><tt><br />You said this was a GUI app that you didn't control the sources to. So control it anyway by renaming the binary in the bundle and putting a stub in there that will save off the id for you and then reexec the real binary:</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">--- example with no error checking --- #include &lt;mach-o/dyld.h&gt;	/* _NSGetExecutablePath */ #include &lt;limits.h&gt;		/* PATH_MAX */ #include &lt;unistd.h&gt;		/* execve */ #include &lt;libgen.h&gt;		/* dirname */ #include &lt;string.h&gt;		/* strcpy */</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">#define BINARYNAME	"myreal_executable"</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">int main(int ac, char *av[]) { 	char pathbuf[PATH_MAX + 1]; 	char real_executable[PATH_MAX + 1]; 	char *bundle_id; 	int  bufsize = sizeof(pathbuf);</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">	_NSGetExecutablePath( pathbuf, &amp;bufsize);</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">	bundle_id = dirname(pathbuf);</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">	strcpy(real_executable, bundle_id); 	strcat(real_executable, "/"); 	strcat(real_executable, BINARYNAME);</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">	execv(real_executable, av); } --------------------</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>Then write the path into /var/run/program.&lt;pid&gt; before you do the execv call to give control to the real binary.</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>Then in your other program go looking for /var/run/program.*. When you find one, take the pid and do an atoi() on it to get the integer pid back. Then end it a kill(pid, 0).</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">This function will return one of three things:</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>(1) 0, indicating that the process exists and you have the right to send it signals</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>(2) -1, with errno set to EPERM, indicating that the process exists and you do not have rights to send it a signal</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>(3) -1, with errno set to ESRCH, indicating that the process does not (yet) exist</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">-</pre><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>Ideally, all this would be unnecessary because you put your daemon and the program you want to give it a UI into the same bundle, which ,means either one of them can find the other by looking at the dirname() from their own call to _NSGetExecutablePath().</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><tt>No grovelling around trying to find out where something came from, because it tells you.</tt><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><br style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; " /><pre style="margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; ">-- Terry _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-dev mailing list      (email@hidden) Help/Unsubscribe/Update your Subscription: <tt>This email sent to email@hidden </tt> <hr /> <ul style="list-style-type: none; list-style-position: outside; list-style-image: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 1em; padding-left: 0px; "><li style="padding-bottom: 0.3em; "><strong>Follow-Ups</strong>: <ul style="list-style-type: none; list-style-position: outside; list-style-image: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 1em; padding-left: 0px; "> <li style="padding-bottom: 0.3em; "><strong><a name="00038" href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00038.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> <ul style="list-style-type: none; list-style-position: outside; list-style-image: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 1em; padding-left: 0px; "><li style="padding-bottom: 0.3em; "><em>From:</em> Eli Bach &lt;email@hidden&gt;</li></ul></li> </ul></li></ul> <table width="100%" border="0" style="font-family: 'Lucida Grande', Geneva, Arial, Verdana, Helvetica, sans-serif; font-size: 12px; margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><tbody><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; "><strong>References:</strong></td><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&nbsp;</td></tr><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&nbsp;</td><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&gt;<strong><a name="00022" href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00022.html" style="color: #000066; text-decoration: none; ">Find path of an application</a></strong> (From: "Rakesh Singhal" &lt;email@hidden&gt;)</td></tr><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&nbsp;</td><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&gt;<strong><a name="00025" href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00025.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> (From: Jean-Daniel Dupas &lt;email@hidden&gt;)</td></tr><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&nbsp;</td><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&gt;<strong><a name="00029" href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00029.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> (From: "Rakesh Singhal" &lt;email@hidden&gt;)</td></tr><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&nbsp;</td><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&gt;<strong><a name="00031" href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00031.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> (From: Jean-Daniel Dupas &lt;email@hidden&gt;)</td></tr><tr><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&nbsp;</td><td style="margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px; ">&gt;<strong><a name="00034" href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00034.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> (From: "Rakesh Singhal" &lt;email@hidden&gt;)</td></tr></tbody></table> <br /> <ul style="list-style-type: none; list-style-position: outside; list-style-image: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 1em; padding-left: 0px; "> <li style="padding-bottom: 0.3em; ">Prev by Date: <strong><a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00036.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> </li> <li style="padding-bottom: 0.3em; ">Next by Date: <strong><a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00038.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> </li> <li style="padding-bottom: 0.3em; ">Previous by thread: <strong><a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00036.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> </li> <li style="padding-bottom: 0.3em; ">Next by thread: <strong><a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/msg00038.html" style="color: #000066; text-decoration: none; ">Re: Find path of an application</a></strong> </li> <li style="padding-bottom: 0.3em; ">Index(es): <ul style="list-style-type: none; list-style-position: outside; list-style-image: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 1em; padding-left: 0px; "> <li style="padding-bottom: 0.3em; "><a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/index.html#00037" style="color: #000066; text-decoration: none; "><strong>Date</strong></a></li> <li style="padding-bottom: 0.3em; "><a href="http://lists.apple.com/archives/darwin-dev/2008/Dec/threads.html#00037" style="color: #000066; text-decoration: none; "><strong>Thread</strong></a></li> </ul> </li> </ul>       <center> </center></pre><img src ="http://www.cppblog.com/lauer3912/aggbug/171908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-18 22:44 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/18/171908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XCODE 4.3 WITH NO GCC?</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/07/170388.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Sat, 07 Apr 2012 13:50:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/07/170388.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/170388.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/07/170388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/170388.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/170388.html</trackback:ping><description><![CDATA[<p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">真的坑爹，今天才开始玩MAC OX，装了个最新版本的10.7.3，只能装XCODE 4.3 这个月刚发行的版本。</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">安装时发现没有install过程，直接双击就进入开发环境了。而且装完后没有gcc 等各种编译工具，在TERMINAL下各种命令不识别，想装ruby的各种开发工具，都不行了。</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">查了半天才发现：</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">Apple announced Xcode 4.3 for OSX Lion and 4.4 for OSX Mountain Lion last week. The major difference is that Xcode no longer provide an installer which is good thing because you now could update Xcode with AppStore in the future, plus it is much easier to carry the development environment with you. However, there is a little problem with this new version of Xcode, is that all command line toolsets and compilers are not visible in terminal.&nbsp;<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />解决方案一：<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />A simple fix is to update your PATH env:</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; "><code style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">export PATH=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:$PATH</code></p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">Please be noted that clang does not reside in /Developer/usr/bin, it is now in /Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">Now you could access to gcc, g++, git or any toolsets bundled with Xcode. For your convenience, it is recommended to include it in your&nbsp;<code style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">.bash_profile</code>.</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; ">解决方案二：</p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">You can install these additional tools directly in Xcode :</span><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">Preferences &gt; Downloads &gt; Command Line Tools &gt; Install</span></p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /></span></p><p style="color: #333333; margin-top: 8px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-break: break-all; line-height: 26px; font-family: Simsun; text-align: left; background-color: #ffffff; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">SO. What a fUUUcking day！</span></p><img src ="http://www.cppblog.com/lauer3912/aggbug/170388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-07 21:50 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/07/170388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>error C2143: syntax error : missing ';' before 'type' in Visual C++ 可能的原因</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/05/170196.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Thu, 05 Apr 2012 11:53:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/05/170196.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/170196.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/05/170196.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/170196.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/170196.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">今天偶然写了下面的程序(原来我写的程序不一样，下面的只是为了把问题简化)</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "></p><div bg_cpp"="" style="width: 687px; "><div><div><strong>[cpp]</strong>&nbsp;<a href="http://blog.csdn.net/cdjogh/article/details/5961742#" title="view plain" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">view plain</a><a href="http://blog.csdn.net/cdjogh/article/details/5961742#" title="copy" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">copy</a><div style="position: absolute; left: 557px; top: 420px; width: 18px; height: 18px; z-index: 99; border-image: initial; "><embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_1" align="center" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&amp;width=18&amp;height=18" wmode="transparent"></div></div></div><ol start="1"><li style="border-width: initial; border-color: initial; line-height: 18px; ">void&nbsp;foo()&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">{&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold; ">int</span>&nbsp;p&nbsp;=&nbsp;0;&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;p&nbsp;==&nbsp;0&nbsp;)&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold; ">int</span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold; ">int</span>&nbsp;a;&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">}&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; "><span style="color: #2e8b57; font-weight: bold; ">int</span>&nbsp;main()&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">{&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">&nbsp;&nbsp;&nbsp;&nbsp;foo();&nbsp;&nbsp;</li><li style="border-width: initial; border-color: initial; line-height: 18px; ">}&nbsp;&nbsp;</li></ol></div>&nbsp;&nbsp;<span style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">本文来自CSDN博客，转载请标明出处：</span><a href="http://blog.csdn.net/fancylea/archive/2009/06/10/4256793.aspx" style="color: #336699; text-decoration: none; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">http://blog.csdn.net/fancylea/archive/2009/06/10/4256793.aspx</a>&nbsp;<br /><p>&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">不幸的是偶然将这个文件保存成了test.c，然后编译的时候出现了</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">error， error C2143: syntax error : missing ';' before 'type'</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">感觉很奇怪,细细看来所有的语法都似乎都是对的，更奇怪的是把文件改成cpp或者cc能正常编译，把int a;和if调换下也能正常编译。这样的错误可能发生在当变量的声明放在可执行代码之后。而这个是在K&amp;R C中规定的，但在ANSI C中废除。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">MSDN (<a href="http://support.microsoft.com/kb/58559" style="color: #336699; text-decoration: none; ">http://support.microsoft.com/kb/58559</a>)给出的解释如下：</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><hr style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; " /><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">In Microsoft C, compiler errors C2143 and C2144 are defined as follows:</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><div><div>&nbsp;&nbsp;&nbsp; C2143: syntax error : missing 'token1' before 'token2'<br />&nbsp;&nbsp;&nbsp; C2144: syntax error : missing 'token' before type 'type'</div></div></div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">You may receive this error message if your program places executable code before a data declaration, an acceptable practice in Kernighan-and-Ritchie C. This practice has been outlawed in later versions of the ANSI drafts.&nbsp;<br /><br />This error message will normally occur if a required closing curly brace (}), right parenthesis [)], or semicolon (;) is missing.</p><hr style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; " /><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">注: The C Programming Language的作者简称K&amp;R，也是C语言之父, 经常用K&amp;R C来和ANSI C做对比。这本书的第二版已经用ANSI.</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">我用的编译器是VS2008, 看来微软向来无视标准。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">总结：</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">在 ANSI C或者C++中，在可执行代码中随时定义变量是允许的，但是在K&amp;R C中是不允许的，VS2008实现的C竟然是K&amp;R C。注意这样的错误也体现在VS中要是用for (int i = 0; i++; i&lt;10)同时你的文件名是.c的也会出现这样的错误。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">Code complete中讨论过变量名的最迟绑定有利于增加代码的可读性等。所以在VS中写c要注意了。</p><img src ="http://www.cppblog.com/lauer3912/aggbug/170196.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-05 19:53 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/05/170196.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++查缺补漏4，赶紧的</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/05/170159.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Thu, 05 Apr 2012 06:54:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/05/170159.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/170159.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/05/170159.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/170159.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/170159.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" style="line-height: 1.8; color: #333333; font-family: Verdana,Arial,sans-serif,'Lucida Grande'; font-size: 13px; text-align: left; background-color: #d6d3d6;"><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">请说出const与#define 相比，有何优点？<br />答案：</span><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">1）&nbsp;<strong>const 常量有数据类型，而宏常量没有数据类型</strong>。编译器可以对前者进行类型<strong>安全检查</strong>。而对后者只进行字符替换，没有类型安全检查，并且在字符替换可能会产生意料不到的错误。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）&nbsp;<strong>有些集成化的调试工具可以对const 常量进行调试</strong>，但是不能对宏常量进行调试。</span></p><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">在8086 汇编下，逻辑地址和物理地址是怎样转换的？（Intel）<br />答案：通用寄存器给出的地址，是段内偏移地址，相应段寄存器地址*10H+通用寄存器内地址，就得到了真正要访问的地址。</span></p><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少，如果不是零，请解释一下编译器为什么没有让它为零。（Autodesk）<br />答案：肯定不是零。举个反例，如果是零的话，声明一个class A[10]对象数组，而每一个对象占用的空间是零，这时就没办法区分A[0],A[1]&#8230;了。</span></p><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">&nbsp;描述内存分配方式以及它们的区别?<br />1）<strong>&nbsp;从静态存储区域分配</strong>。内存在程序编译的时候就已经分配好，这块内存在程序的整个运行期间都存在。例如<strong>全局变量，static 变量</strong>。<br />2）&nbsp;<strong>在栈上创建</strong>。在执行函数时，<strong>函数内局部变量的存储单元都可以在栈上创建</strong>，函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。<br />3）&nbsp;<strong>从堆上分配</strong>，<strong>亦称动态内存分配</strong>。程序在运行的时候用malloc 或new 申请任意多少的内存，程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定，使用非常灵活，但问题也最多。</span></p><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">&nbsp;main 函数执行以前，还会执行什么代码？<br />答案：全局对象的构造函数会在main 函数之前执行。</span></p><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium; ">&nbsp;C++是不是类型安全的？<br />答案：不是。两个不同类型的指针之间可以强制转换（用reinterpret cast)。C#是类型安全的。</span></p><p>&nbsp;</p><p><span style="color: #3300ff; font-family: 楷体_GB2312; font-size: medium; ">有哪几种情况只能用intialization list 而不能用assignment?</span></p><p>&nbsp;</p><p><span style="color: #3300ff; font-family: 楷体_GB2312; font-size: medium; ">答案：当类中含有const、reference 成员变量；基类的构造函数都需要初始化表。</span></p><p><span style="color: #3300ff; font-family: 楷体_GB2312; font-size: medium; ">define DOUBLE(x) x+x ，i = 5*DOUBLE(5)； i 是多少？<br />答案：i 为30</span></p><p><span style="color: #3300ff; font-family: 楷体_GB2312; font-size: medium; ">New delete 与malloc free 的联系与区别?<br />答案：都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象，new 会自动调用对象的构造函数。delete 会调用对象的destructor，而free 不会调用对象的destructor.</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">1、写一个&#8220;标准&#8221;宏，这个宏输入两个参数并返回较小的一个。<br />.#define Min(X, Y) ((X)&gt;(Y)?(Y):(X))//结尾没有;<br />2、嵌入式系统中经常要用到无限循环，你怎么用C编写死循环。<br />while(1){}或者for(;;)<br />3、关键字static的作用是什么？<br />定义静态变量<br />4、关键字const有什么含意？<br />表示常量不可以修改的变量。<br />5、关键字volatile有什么含意？并举出三个不同的例子？<br />提示编译器对象的值可能在编译器未监测到的情况下改变。</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">int (*s[10])(int) 表示的是什么啊<br />int (*s[10])(int) 函数指针数组，每个指针指向一个int func(int param)的函数。</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">1.有以下表达式：<br />int a=248; b=4;int const c=21;const int *d=&amp;a;<br />int *const e=&amp;b;int const *f const =&amp;a;<br />请问下列表达式哪些会被编译器禁止？为什么？<br />*c=32;d=&amp;b;*d=43;e=34;e=&amp;a;f=0x321f;<br />*c 这是个什么东东，禁止<br />*d 说了是const， 禁止<br />e = &amp;a 说了是const 禁止<br />const *f const =&amp;a; 禁止<br />2.交换两个变量的值，不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;<br />有两种解法, 一种用算术算法, 一种用^(异或)<br />a = a + b;<br />b = a - b;<br />a = a - b;&nbsp;<br />or<br />a = a^b;// 只能对int,char..<br />b = a^b;<br />a = a^b;<br />or<br />a ^= b ^= a;<br />3.c和c++中的struct有什么不同？<br />c和c++中struct的主要区别是c中的struct不可以含有成员函数，而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同，struct默认为public，而class默认为private<br />4.＃i nclude &lt;stdio.h&gt;<br />＃i nclude &lt;stdlib.h&gt;<br />void getmemory(char *p)<br />{<br />&nbsp;&nbsp;&nbsp; p=(char *) malloc(100);<br />&nbsp;&nbsp;&nbsp; strcpy(p,"hello world");<br />}<br />int main( )<br />{<br />&nbsp;&nbsp;&nbsp; char *str=NULL;<br />&nbsp;&nbsp;&nbsp; getmemory(str);<br />&nbsp;&nbsp;&nbsp; printf("%s/n",str);<br />&nbsp;&nbsp;&nbsp; free(str);<br />&nbsp;&nbsp;&nbsp; return 0;<br />&nbsp;&nbsp; }<br />程序崩溃，getmemory中的malloc 不能返回动态内存， free（）对str操作很危险<br />5.char szstr[10];<br />strcpy(szstr,"0123456789");<br />产生什么结果？为什么？<br />长度不一样，会造成非法的OS<br />6.列举几种进程的同步机制，并比较其优缺点。<br />&nbsp;&nbsp; 原子操作&nbsp;<br />信号量机制<br />&nbsp;&nbsp; 自旋锁<br />&nbsp;&nbsp; 管程，会合，分布式系统</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">7.进程之间通信的途径<br />共享存储系统<br />消息传递系统<br />管道：以文件系统为基础<br />11.进程死锁的原因<br />资源竞争及进程推进顺序非法<br />12.死锁的4个必要条件<br />互斥、请求保持、不可剥夺、环路<br />13.死锁的处理<br />鸵鸟策略、预防策略、避免策略、检测与解除死锁<br />15.&nbsp;&nbsp; 操作系统中进程调度策略有哪几种？<br />FCFS(先来先服务)，优先级，时间片轮转，多级反馈<br />8.类的静态成员和非静态成员有何区别？<br />类的静态成员每个类只有一个，非静态成员每个对象一个<br />9.纯虚函数如何定义？使用时应注意什么？<br />virtual void f()=0;<br />是接口，子类必须要实现<br />10.数组和链表的区别<br />数组：数据顺序存储，固定大小<br />连表：数据可以随机存储，大小可动态改变</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">12.ISO的七层模型是什么？tcp/udp是属于哪一层？tcp/udp有何优缺点？<br />应用层<br />表示层<br />会话层<br />运输层<br />网络层<br />物理链路层<br />物理层<br />tcp /udp属于运输层<br />TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。<br />与 TCP 不同， UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单， UDP 头包含很少的字节，比 TCP 负载消耗少。<br />tcp: 提供稳定的传输服务，有流量控制，缺点是包头大，冗余性不好<br />udp: 不提供稳定的服务，包头小，开销小&nbsp;&nbsp;</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">1：(void *)ptr 和 (*(void**))ptr的结果是否相同？其中ptr为同一个指针<br />.(void *)ptr 和 (*(void**))ptr值是相同的<br />2：int main()<br />&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp; int x=3;<br />&nbsp;&nbsp;&nbsp; printf("%d",x);<br />&nbsp;&nbsp;&nbsp; return 1;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp; }<br />问函数既然不会被其它函数调用，为什么要返回1？<br />mian中，c标准认为0表示成功，非0表示错误。具体的值是某中具体出错信息</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">1，要对绝对地址0x100000赋值，我们可以用<br />(unsigned int*)0x100000 = 1234;<br />那么要是想让程序跳转到绝对地址是0x100000去执行，应该怎么做？<br />*((void (*)( ))0x100000 ) ( );<br />首先要将0x100000强制转换成函数指针,即:<br />(void (*)())0x100000<br />然后再调用它:<br />*((void (*)())0x100000)();<br />用typedef可以看得更直观些:<br />typedef void(*)() voidFuncPtr;<br />*((voidFuncPtr)0x100000)();<br />2，已知一个数组table，用一个宏定义，求出数据的元素个数<br />#define NTBL<br />#define NTBL (sizeof(table)/sizeof(table[0]))</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">面试题: 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?<br />进程是死的，只是一些资源的集合，真正的程序执行都是线程来完成的，程序启动的时候操作系统就帮你创建了一个主线程。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">每个线程有自己的堆栈。<br />DLL中有没有独立的堆栈，这个问题不好回答，或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行，只有线程拥有堆栈，如果DLL中的代码是EXE中的线程所调用，那么这个时候是不是说这个DLL没有自己独立的堆栈？如果DLL中的代码是由DLL自己创建的线程所执行，那么是不是说DLL有独立的堆栈？</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">以上讲的是堆栈，如果对于堆来说，每个DLL有自己的堆，所以如果是从DLL中动态分配的内存，最好是从DLL中删除，如果你从DLL中分配内存，然后在EXE中，或者另外一个DLL中删除，很有可能导致程序崩溃</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">unsigned short A = 10;<br />printf("~A = %u\n", ~A);</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">char c=128;&nbsp;<br />printf("c=%d\n",c);</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">输出多少？并分析过程<br />第一题，～A ＝0xfffffff5,int值 为－11，但输出的是uint。所以输出4294967285<br />第二题，c＝0x10,输出的是int，最高位为1，是负数，所以它的值就是0x00的补码就是128，所以输出－128。<br />这两道题都是在考察二进制向int或uint转换时的最高位处理。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">分析下面的程序：<br />void GetMemory(char **p,int num)<br />{<br />&nbsp;&nbsp;&nbsp; *p=(char *)malloc(num);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />int main()<br />{<br />&nbsp;&nbsp;&nbsp; char *str=NULL;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; GetMemory(&amp;str,100);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; strcpy(str,"hello");<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; free(str);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; if(str!=NULL)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(str,"world");<br />&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; printf("\n str is %s",str);<br />&nbsp;&nbsp;&nbsp; getchar();<br />}&nbsp;&nbsp;&nbsp;&nbsp;<br />问输出结果是什么？希望大家能说说原因，先谢谢了<br />输出str is world。<br />free 只是释放的str指向的内存空间,它本身的值还是存在的.<br />所以free之后，有一个好的习惯就是将str=NULL.<br />此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,<br />尽管这段程序确实是存在大大的问题（上面各位已经说得很清楚了），但是通常会打印出world来。<br />这是因为，进程中的内存管理一般不是由操作系统完成的，而是由库函数自己完成的。<br />当你malloc一块内存的时候，管理库向操作系统申请一块空间（可能会比你申请的大一些），然后在这块空间中记录一些管理信息（一般是在你申请的内存前面一点），并将可用内存的地址返回。但是释放内存的时候，管理库通常都不会将内存还给操作系统，因此你是可以继续访问这块地址的，只不过。。。。。。。。楼上都说过了，最好别这么干。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">char a[10],strlen(a)为什么等于15？运行的结果</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">＃i nclude "stdio.h"<br />＃i nclude "string.h"</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">void main()<br />{</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">char aa[10];<br />printf("%d",strlen(aa));<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">sizeof()和初不初始化，没有关系；<br />strlen()和初始化有关。</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">char (*str)[20];/*str是一个数组指针，即指向数组的指针．*/<br />char *str[20];/*str是一个指针数组，其元素为指针型数据．*/</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">long a=0x801010;<br />a+5=?<br />0x801010用二进制表示为：&#8220;1000 0000 0001 0000 0001 0000&#8221;，十进制的值为8392720，再加上5就是8392725罗</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">1)给定结构struct A&nbsp;<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char t:4;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char k:4;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned short i:8;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long m;<br />};问sizeof(A) = ?<br />给定结构struct A&nbsp;<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char t:4; 4位<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char k:4; 4位<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned short i:8; 8位&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long m; // 偏移2字节保证4字节对齐<br />}; // 共8字节<br />2)下面的函数实现在一个数上加一个数，有什么错误？请改正。<br />int add_n ( int n )<br />{<br />&nbsp;&nbsp;&nbsp; static int i = 100;<br />&nbsp;&nbsp;&nbsp; i += n;<br />&nbsp;&nbsp;&nbsp; return i;<br />}<br />当你第二次调用时得不到正确的结果，难道你写个函数就是为了调用一次？问题就出在 static上？</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">// 帮忙分析一下<br />＃i nclude&lt;iostream.h&gt;<br />＃i nclude &lt;string.h&gt;<br />＃i nclude &lt;malloc.h&gt;<br />＃i nclude &lt;stdio.h&gt;<br />＃i nclude &lt;stdlib.h&gt;<br />＃i nclude &lt;memory.h&gt;<br />typedef struct AA<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int b1:5;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int b2:2;<br />}AA;<br />void main()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AA aa;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char cc[100];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memcpy(&amp;aa,cc,sizeof(AA));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; aa.b1 &lt;&lt;endl;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; aa.b2 &lt;&lt;endl;<br />}<br />答案是 -16和１<br />首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.<br />经过strcpy和memcpy后,aa的4个字节所存放的值是:<br />0,1,2,3的ASC码，即00110000,00110001,00110010,00110011<br />所以，最后一步：显示的是这４个字节的前５位，和之后的２位<br />分别为：10000,和01<br />因为int是有正负之分　　所以：答案是-16和１</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">求函数返回值，输入x=9999;&nbsp;<br />int func （ x ）<br />{&nbsp;<br />&nbsp;&nbsp;&nbsp; int countx = 0;&nbsp;<br />&nbsp;&nbsp;&nbsp; while ( x )&nbsp;<br />&nbsp;&nbsp;&nbsp; {&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; countx ++;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = x&amp;(x-1);&nbsp;<br />&nbsp;&nbsp;&nbsp; }&nbsp;<br />&nbsp;&nbsp;&nbsp; return countx;&nbsp;<br />}&nbsp;<br />结果呢？<br />知道了这是统计9999的二进制数值中有多少个1的函数，且有<br />9999＝9&#215;1024＋512＋256＋15</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">9&#215;1024中含有1的个数为2；<br />512中含有1的个数为1；<br />256中含有1的个数为1；<br />15中含有1的个数为4；<br />故共有1的个数为8，结果为8。<br />1000 - 1 = 0111，正好是原数取反。这就是原理。<br />用这种方法来求1的个数是很效率很高的。<br />不必去一个一个地移位。循环次数最少。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题<br />bool add (int a, int b,int *c)<br />{<br />*c=a+b;<br />return (a&gt;0 &amp;&amp; b&gt;0 &amp;&amp;(*c&lt;a || *c&lt;b) || (a&lt;0 &amp;&amp; b&lt;0 &amp;&amp;(*c&gt;a || *c&gt;b)));<br />}</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">分析：<br />struct bit&nbsp;<br />{&nbsp;&nbsp; int a:3;&nbsp;<br />&nbsp;&nbsp;&nbsp; int b:2;&nbsp;<br />&nbsp;&nbsp;&nbsp; int c:3;&nbsp;<br />};&nbsp;<br />int main()&nbsp;<br />{&nbsp;<br />bit s;&nbsp;<br />char *c=(char*)&amp;s;&nbsp;<br />&nbsp;&nbsp; cout&lt;&lt;sizeof(bit)&lt;&lt;endl;<br />*c=0x99;<br />&nbsp;&nbsp; cout &lt;&lt; s.a &lt;&lt;endl &lt;&lt;s.b&lt;&lt;endl&lt;&lt;s.c&lt;&lt;endl;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; int a=-1;<br />&nbsp;&nbsp; printf("%x",a);<br />return 0;&nbsp;<br />}&nbsp;<br />输出为什么是<br />4<br />1<br />-1<br />-4<br />ffffffff<br />因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100<br />当c为有符合数时, c = 100, 最高1为表示c为负数，负数在计算机用补码表示，所以c = -4;同理&nbsp;<br />b = -1;<br />当c为有符合数时, c = 100,即 c = 4,同理 b = 3</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">位域 ：&nbsp;&nbsp;&nbsp;<br />有些信息在存储时，并不需要占用一个完整的字节， 而只需占几个或一个二进制位。例如在存放一个开关量时，只有0和1 两种状态， 用一位二进位即可。为了节省存储空间，并使处理简便，Ｃ语言又提供了一种数据结构，称为&#8220;位域&#8221;或&#8220;位段&#8221;。所谓&#8220;位域&#8221;是把一个字节中的二进位划分为几个不同的区域， 并说明每个区域的位数。每个域有一个域名，允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿，其形式为：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />struct 位域结构名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />{ 位域列表 };&nbsp;&nbsp;&nbsp;&nbsp;<br />其中位域列表的形式为： 类型说明符 位域名：位域长度&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />struct bs&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;&nbsp;&nbsp;<br />int a:8;&nbsp;&nbsp;&nbsp;&nbsp;<br />int b:2;&nbsp;&nbsp;&nbsp;&nbsp;<br />int c:6;&nbsp;&nbsp;&nbsp;&nbsp;<br />};&nbsp;&nbsp;&nbsp;&nbsp;<br />位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明，同时定义说明或者直接说明这三种方式。例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />struct bs&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;&nbsp;&nbsp;<br />int a:8;&nbsp;&nbsp;&nbsp;&nbsp;<br />int b:2;&nbsp;&nbsp;&nbsp;&nbsp;<br />int c:6;&nbsp;&nbsp;&nbsp;&nbsp;<br />}data;&nbsp;&nbsp;&nbsp;&nbsp;<br />说明data为bs变量，共占两个字节。其中位域a占8位，位域b占2位，位域c占6位。对于位域的定义尚有以下几点说明：&nbsp;&nbsp;&nbsp;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">1. 一个位域必须存储在同一个字节中，不能跨两个字节。如一个字节所剩空间不够存放另一位域时，应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />struct bs&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned a:4&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned :0 /*空域*/&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned b:4 /*从下一单元开始存放*/&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned c:4&nbsp;&nbsp;&nbsp;&nbsp;<br />}&nbsp;&nbsp;&nbsp;&nbsp;<br />在这个位域定义中，a占第一字节的4位，后4位填0表示不使用，b从第二字节开始，占用4位，c占用4位。&nbsp;&nbsp;&nbsp;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">2. 由于位域不允许跨两个字节，因此位域的长度不能大于一个字节的长度，也就是说不能超过8位二进位。&nbsp;&nbsp;&nbsp;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">3. 位域可以无位域名，这时它只用来作填充或调整位置。无名的位域是不能使用的。例如：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />struct k&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;&nbsp;&nbsp;<br />int a:1&nbsp;&nbsp;&nbsp;&nbsp;<br />int :2 /*该2位不能使用*/&nbsp;&nbsp;&nbsp;&nbsp;<br />int b:3&nbsp;&nbsp;&nbsp;&nbsp;<br />int c:2&nbsp;&nbsp;&nbsp;&nbsp;<br />};&nbsp;&nbsp;&nbsp;&nbsp;<br />从以上分析可以看出，位域在本质上就是一种结构类型， 不过其成员是按二进位分配的。&nbsp;&nbsp;&nbsp;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">二、位域的使用位域的使用和结构成员的使用相同，其一般形式为： 位域变量名&#8226;位域名 位域允许用各种格式输出。&nbsp;&nbsp;&nbsp;&nbsp;<br />main(){&nbsp;&nbsp;&nbsp;&nbsp;<br />struct bs&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned a:1;&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned b:3;&nbsp;&nbsp;&nbsp;&nbsp;<br />unsigned c:4;&nbsp;&nbsp;&nbsp;&nbsp;<br />} bit,*pbit;&nbsp;&nbsp;&nbsp;&nbsp;<br />bit.a=1;&nbsp;&nbsp;&nbsp;&nbsp;<br />bit.b=7;&nbsp;&nbsp;&nbsp;&nbsp;<br />bit.c=15;&nbsp;&nbsp;&nbsp;&nbsp;<br />pri</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">改错：<br />＃i nclude &lt;stdio.h&gt;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">int main(void) {</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">&nbsp;&nbsp;&nbsp; int **p;<br />&nbsp;&nbsp;&nbsp; int arr[100];</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">&nbsp;&nbsp;&nbsp; p = &amp;arr;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">&nbsp;&nbsp;&nbsp; return 0;<br />}<br />解答：<br />搞错了,是指针类型不同,<br />int **p; //二级指针<br />&amp;arr; //得到的是指向第一维为100的数组的指针<br />＃i nclude &lt;stdio.h&gt;<br />int main(void) {<br />int **p, *q;<br />int arr[100];<br />q = arr;<br />p = &amp;q;<br />return 0;<br />}</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">下面这个程序执行后会有什么错误或者效果:<br />#define MAX 255<br />int main()<br />{<br />&nbsp;&nbsp; unsigned char A[MAX],i;//i被定义为unsigned char<br />&nbsp;&nbsp; for (i=0;i&lt;=MAX;i++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A[i]=i;<br />}<br />解答：死循环加数组越界访问（C/C++不进行数组越界检查）<br />MAX=255&nbsp;<br />数组A的下标范围为:0..MAX-1,这是其一..<br />其二.当i循环到255时,循环内执行:<br />A[255]=255;<br />这句本身没有问题..但是返回for (i=0;i&lt;=MAX;i++)语句时,<br />由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">struct name1{<br />&nbsp;&nbsp; char str;<br />&nbsp;&nbsp; short x;<br />&nbsp;&nbsp; int&nbsp;&nbsp; num;<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">struct name2{<br />&nbsp;&nbsp; char str;<br />&nbsp;&nbsp; int num;<br />&nbsp;&nbsp; short x;<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">sizeof(struct name1)=8,sizeof(struct name2)=12<br />在第二个结构中，为保证num按四个字节对齐，char后必须留出3字节的空间；同时为保证整个结构的自然对齐（这里是4字节对齐），在x后还要补齐2个字节，这样就是12字节。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">intel：<br />A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里（栈还是堆或者其他的）?<br />static的全局变量，表明这个变量仅在本模块中有意义，不会影响其他模块。<br />他们都放在数据区，但是编译器对他们的命名是不同的。<br />如果要使变量在其他模块也有意义的话，需要使用extern关键字。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">struct s1<br />{<br />int i: 8;<br />int j: 4;<br />int a: 3;<br />double b;<br />};</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">struct s2<br />{<br />int i: 8;<br />int j: 4;<br />double b;<br />int a:3;<br />};</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">printf("sizeof(s1)= %d\n", sizeof(s1));<br />printf("sizeof(s2)= %d\n", sizeof(s2));<br />result: 16, 24<br />第一个struct s1<br />{<br />int i: 8;<br />int j: 4;<br />int a: 3;<br />double b;<br />};<br />理论上是这样的，首先是i在相对0的位置，占8位一个字节，然后，j就在相对一个字节的位置，由于一个位置的字节数是4位的倍数，因此不用对齐，就放在那里了，然后是a，要在3位的倍数关系的位置上，因此要移一位，在15位的位置上放下，目前总共是18位，折算过来是2字节2位的样子，由于double是8字节的，因此要在相对0要是8个字节的位置上放下，因此从18位开始到8个字节之间的位置被忽略，直接放在8字节的位置了，因此，总共是16字节。</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">第二个最后会对照是不是结构体内最大数据的倍数，不是的话，会补成是最大数据的倍数</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">上面是基本问题，接下来是编程问题：</span></p><p>&nbsp;</p><p><br /><span style="color: #4822dd; ">本人很弱，这几个题也搞不定，特来求救：<br />1）读文件file1.txt的内容（例如）：<br />12<br />34<br />56<br />输出到file2.txt：<br />56<br />34<br />12<br />（逆序）<br />2）输出和为一个给定整数的所有组合<br />例如n=5<br />5=1+4；5=2+3（相加的数不能重复）<br />则输出<br />1，4；2，3。<br />望高手赐教！！</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">第一题,注意可增长数组的应用.<br />＃i nclude &lt;stdio.h&gt;<br />＃i nclude &lt;stdlib.h&gt;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">int main(void)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int MAX = 10;<br />int *a = (int *)malloc(MAX * sizeof(int));<br />int *b;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />FILE *fp1;<br />FILE *fp2;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">fp1 = fopen("a.txt","r");<br />if(fp1 == NULL)<br />{printf("error1");<br />&nbsp;&nbsp;&nbsp; exit(-1);<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">&nbsp;&nbsp;&nbsp; fp2 = fopen("b.txt","w");<br />if(fp2 == NULL)<br />{printf("error2");<br />&nbsp;&nbsp;&nbsp; exit(-1);<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">int i = 0;<br />&nbsp;&nbsp;&nbsp; int j = 0;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">while(fscanf(fp1,"%d",&amp;a[i]) != EOF)<br />{<br />i++;<br />j++;<br />if(i &gt;= MAX)<br />{<br />MAX = 2 * MAX;<br />b = (int*)realloc(a,MAX * sizeof(int));<br />if(b == NULL)<br />{<br />printf("error3");<br />exit(-1);<br />}<br />a = b;<br />}<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">for(;--j &gt;= 0;)<br />&nbsp;&nbsp; fprintf(fp2,"%d\n",a[j]);</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">fclose(fp1);<br />fclose(fp2);</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">return 0;<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">第二题.<br />＃i nclude &lt;stdio.h&gt;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">int main(void)<br />{<br />unsigned long int i,j,k;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">printf("please input the number\n");<br />scanf("%d",&amp;i);<br />&nbsp;&nbsp;&nbsp; if( i % 2 == 0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j = i / 2;<br />else<br />j = i / 2 + 1;</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">printf("The result is \n");<br />&nbsp;&nbsp;&nbsp; for(k = 0; k &lt; j; k++)<br />&nbsp;&nbsp;&nbsp;&nbsp; printf("%d = %d + %d\n",i,k,i - k);<br />return 0;<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">＃i nclude &lt;stdio.h&gt;<br />void main()<br />{<br />unsigned long int a,i=1;<br />scanf("%d",&amp;a);<br />if(a%2==0)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp; for(i=1;i&lt;a/2;i++)<br />&nbsp;&nbsp;&nbsp;&nbsp; printf("%d",a,a-i);<br />}<br />else<br />for(i=1;i&lt;=a/2;i++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf(" %d, %d",i,a-i);<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">兄弟,这样的题目若是做不出来实在是有些不应该, 给你一个递规反向输出字符串的例子,可谓是反序的经典例程.</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">void inverse(char *p)<br />{<br />&nbsp;&nbsp;&nbsp; if( *p = = '\0' )&nbsp;<br />return;<br />&nbsp;&nbsp;&nbsp; inverse( p+1 );<br />&nbsp;&nbsp;&nbsp; printf( "%c", *p );<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">int main(int argc, char *argv[])<br />{<br />&nbsp;&nbsp;&nbsp; inverse("abc\0");</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">&nbsp;&nbsp;&nbsp; return 0;<br />}</span></p><p>&nbsp;</p><p><span style="color: #4822dd; ">借签了楼上的&#8220;递规反向输出&#8221;<br />＃i nclude &lt;stdio.h&gt;<br />void test(FILE *fread, FILE *fwrite)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[1024] = {0};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!fgets(buf, sizeof(buf), fread))<br />}</span></p><p><span style="color: #3300ff; font-family: 楷体_GB2312; font-size: medium; "><br /></span></p><p><span style="color: #0000ff; font-family: 楷体_GB2312; font-size: medium;"><br /></span></p></div><div id="MySignature" style="margin-top: 10px; color: #333333; font-family: Verdana, Arial, sans-serif, 'Lucida Grande'; font-size: 13px; line-height: 19px; text-align: left; background-color: #d6d3d6; "><p style="margin-bottom:0pt; margin-top:0pt; "><a href="http://www.lianzhiwei.com/"><span style=" color:#0000ff; text-decoration:underline ;font-family:'宋体'; ">奶茶加盟</span></a><a href="http://www.lianzhiwei.com/"><span style=" color:#0000ff; text-decoration:underline ;font-family:'宋体'; ">http://www.lianzhiwei.com/</span></a><span style=" font-size:10.5000pt; font-family:'宋体'; ">奶茶店加盟</span></p></div><img src ="http://www.cppblog.com/lauer3912/aggbug/170159.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-05 14:54 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/05/170159.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SDL入门教程（六）：SDL读取其它格式的图片</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/04/169996.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Wed, 04 Apr 2012 00:25:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/04/169996.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/169996.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/04/169996.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/169996.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/169996.html</trackback:ping><description><![CDATA[<a href="http://www.cppblog.com/lf426/archive/2008/03/19/44831.html">http://www.cppblog.com/lf426/archive/2008/03/19/44831.html</a>&nbsp;<br /><br /><div style="box-sizing: border-box; font-size: 14.7px; font-weight: bold; margin-bottom: 10px; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; line-height: 20px; background-color: #ffffff; "><a id="viewpost1_TitleUrl" href="http://www.cppblog.com/lf426/archive/2008/03/19/44831.html" style="box-sizing: border-box; text-decoration: none; color: #3468a4; ">SDL入门教程（六）：SDL读取其它格式的图片</a></div><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">作者：龙飞</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">1：扩充库（Extension Libraries）</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SDL本身所支持的，仅仅是读取bmp格式的图片。要使用其它格式的图片，我们需要使用SDL的扩充库。在下面地址，我们可以下载到相关文件</span><a href="http://www.libsdl.org/projects/SDL_image/release/SDL_image-devel-1.2.6-VC8.zip" style="box-sizing: border-box; color: #3468a4; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; "><u style="box-sizing: border-box; ">SDL_image-devel-1.2.6-VC8.zip</u></a><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">。</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><a href="http://www.libsdl.org/projects/SDL_image/" style="box-sizing: border-box; color: #3468a4; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">http://www.libsdl.org/projects/SDL_image/</a><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 与SDL本身的设置一样，将include下的*.h文件拷贝到：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">C:\MinGW\include\SDL （MinGW）</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">C:\Program Files\Microsoft Visual Studio 9.0\VC\include\SDL （VC2008）</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将*.lib文件拷贝到：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">C:\MinGW\lib （MinGW）</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">C:\Program Files\Microsoft Visual Studio 9.0\VC\lib （VC2008）</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将*.dll文件拷贝到：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">C:\WINDOWS\system32</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在编译的时候，gcc注意增加共同编译的库文件-lSDL_image，比如，我设置了一个批处理文件g++img.bat内容如下：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><div style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; border-right-color: #cccccc; border-right-width: 1px; border-right-style: solid; padding-right: 5px; border-top-color: #cccccc; border-top-width: 1px; border-top-style: solid; padding-left: 4px; padding-bottom: 4px; border-left-color: #cccccc; border-left-width: 1px; border-left-style: solid; width: 1035px; word-break: break-all; padding-top: 4px; border-bottom-color: #cccccc; border-bottom-width: 1px; border-bottom-style: solid; background-color: #eeeeee; "><span style="box-sizing: border-box; color: #000000; ">g++&nbsp;-o&nbsp;MySDL.exe&nbsp;main.cpp&nbsp;-lmingw32&nbsp;-lSDLmain&nbsp;-lSDL&nbsp;-lSDL_image&nbsp;-mwindows</span></div><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在VC2008中，需要在projec属性中，Configuration Properties -- Linker -- Input -- Additional Dependencies 下增加SDL_image.lib。</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在程序的头文件中，需要增加：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><div style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; border-right-color: #cccccc; border-right-width: 1px; border-right-style: solid; padding-right: 5px; border-top-color: #cccccc; border-top-width: 1px; border-top-style: solid; padding-left: 4px; padding-bottom: 4px; border-left-color: #cccccc; border-left-width: 1px; border-left-style: solid; width: 1035px; word-break: break-all; padding-top: 4px; border-bottom-color: #cccccc; border-bottom-width: 1px; border-bottom-style: solid; background-color: #eeeeee; "><span style="box-sizing: border-box; color: #000000; ">#<span style="box-sizing: border-box; color: #0000ff; ">include</span>&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">"</span><span style="box-sizing: border-box; color: #000000; ">SDL/SDL_image.h</span><span style="box-sizing: border-box; color: #000000; ">"</span></div><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">2：更加通用的Display Surface构造函数</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们现在可以回头过来修改我们在</span><a title="SDL入门教程（五）：6、对C++异常机制的思考，代码重写" href="http://www.cppblog.com/lf426/archive/2008/02/22/43095.html" style="box-sizing: border-box; color: #3468a4; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">SDL入门教程（五）：6、对C++异常机制的思考，代码重写</a><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">中的Display Surface类的构造函数，使其能够更加通用的读取其它格式的图片。</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><div style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; border-right-color: #cccccc; border-right-width: 1px; border-right-style: solid; padding-right: 5px; border-top-color: #cccccc; border-top-width: 1px; border-top-style: solid; padding-left: 4px; padding-bottom: 4px; border-left-color: #cccccc; border-left-width: 1px; border-left-style: solid; width: 1035px; word-break: break-all; padding-top: 4px; border-bottom-color: #cccccc; border-bottom-width: 1px; border-bottom-style: solid; background-color: #eeeeee; "><span style="box-sizing: border-box; color: #000000; ">DisplaySurface::DisplaySurface(std::</span><span style="box-sizing: border-box; color: #0000ff; ">string</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;file_name,&nbsp;</span><span style="box-sizing: border-box; color: #0000ff; ">const</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;ScreenSurface</span><span style="box-sizing: border-box; color: #000000; ">&amp;</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;screen):<br style="box-sizing: border-box; " />fileName(file_name)<br style="box-sizing: border-box; " />{<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;SDL_Surface</span><span style="box-sizing: border-box; color: #000000; ">*</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;pSurfaceTemp&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">=</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;IMG_Load(file_name.c_str());<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="box-sizing: border-box; color: #0000ff; ">if</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;(&nbsp;pSurfaceTemp&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">==</span>&nbsp;<span style="box-sizing: border-box; color: #000000; ">0</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;)<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="box-sizing: border-box; color: #0000ff; ">throw</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;ErrorInfo(SDL_GetError());<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;pSurface&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">=</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;SDL_DisplayFormat(pSurfaceTemp);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="box-sizing: border-box; color: #0000ff; ">if</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;(&nbsp;pSurface&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">==</span>&nbsp;<span style="box-sizing: border-box; color: #000000; ">0</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;)<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="box-sizing: border-box; color: #0000ff; ">throw</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;ErrorInfo(SDL_GetError());<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;SDL_FreeSurface(pSurfaceTemp);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;pScreen&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">=</span><span style="box-sizing: border-box; color: #000000; ">&nbsp;screen.point();<br style="box-sizing: border-box; " />}</span></div><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IMG_Load()可以读取多种格式的图片文件，包括BMP, PNM, XPM, LBM, PCX, GIF, JPEG, TGA和PNG。</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">3：将图片修改为适合显示的格式</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><div style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; border-right-color: #cccccc; border-right-width: 1px; border-right-style: solid; padding-right: 5px; border-top-color: #cccccc; border-top-width: 1px; border-top-style: solid; padding-left: 4px; padding-bottom: 4px; border-left-color: #cccccc; border-left-width: 1px; border-left-style: solid; width: 1035px; word-break: break-all; padding-top: 4px; border-bottom-color: #cccccc; border-bottom-width: 1px; border-bottom-style: solid; background-color: #eeeeee; "><span style="box-sizing: border-box; color: #000000; ">SDL_Surface&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">*</span><span style="box-sizing: border-box; color: #000000; ">SDL_DisplayFormat(SDL_Surface&nbsp;</span><span style="box-sizing: border-box; color: #000000; ">*</span><span style="box-sizing: border-box; color: #000000; ">surface);</span></div><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上面的程序中，我们使用到了函数SDL_DisplayFormat()。在之前的教程中，我一直没有用到这个函数，是因为我还没有发现用SDL_LoadBMP()的时候会出现格式兼容性的问题&#8212;&#8212;即使是图片位深与显示不一致。但是使用IMG_Load()的时候，小小的bug出现了。所以，这里我必须使用SDL_DisplayFormat()，将读取的图片文件转换为适合显示的格式。</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 13px; line-height: 20px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果转换失败，或者内存溢出，这个函数将返回空指针。</span>&nbsp;<img src ="http://www.cppblog.com/lauer3912/aggbug/169996.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-04 08:25 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/04/169996.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Configure，Makefile.am, Makefile.in, Makefile文件之间关系</title><link>http://www.cppblog.com/lauer3912/archive/2012/04/03/169966.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 03 Apr 2012 14:20:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/04/03/169966.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/169966.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/04/03/169966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/169966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/169966.html</trackback:ping><description><![CDATA[<div>Configure，Makefile.am, Makefile.in, Makefile文件之间关系</div> <div>2009-08-12 12:14</div> <table style="width: 100%; table-layout: fixed"> <tbody> <tr> <td> <div id="blog_text"><span style="line-height: 18px; "> <div style="position: static; filter: none; line-height: 20px; word-wrap: break-word; visibility: visible !important; color: #333333; font-size: 14px; overflow-x: hidden; overflow-y: hidden; border-image: initial; "> <p style="line-height: normal"><img border="0" src="http://hiphotos.baidu.com/litaosmile/pic/item/55a6d229122935d798250aa4.jpg" small="0"  alt="" /></p> <p style="line-height: normal">1.autoscan (autoconf):  扫描源代码以搜寻普通的可移植性问题，比如检查编译器，库，头文件等，生成文件configure.scan,它是configure.ac的一个雏形。</p> <p style="line-height: normal">    your source files --&gt; [autoscan*] --&gt;  [configure.scan] --&gt; configure.ac</p>2.aclocal  (automake):根据已经安装的宏，用户定义宏和acinclude.m4文件中的宏将configure.ac文件所需要的宏集中定义到文件  aclocal.m4中。aclocal是一个perl 脚本程序，它的定义是：&#8220;aclocal - create aclocal.m4 by scanning  configure.ac&#8221; <pre style="line-height: normal">user input files   optional input     process          output files<br />================   ==============     =======          ============<br /><br />                    acinclude.m4 - - - - -.<br />                                          V<br />                                      .-------,<br />configure.ac ------------------------&gt;|aclocal|<br />                 {user macro files} -&gt;|       |------&gt; aclocal.m4<br />                                      `-------'<br />3.autoheader(autoconf): 根据configure.ac中的某些宏，比如cpp宏定义，运行m4，声称config.h.in<br /><br />user input files    optional input     process          output files<br />================    ==============     =======          ============<br /><br />                    aclocal.m4 - - - - - - - .<br />                                             |<br />                                             V<br />                                     .----------,<br />configure.ac -----------------------&gt;|autoheader|----&gt; autoconfig.h.in<br />                                     `----------'</pre> <p style="line-height: normal">4.automake:  automake将Makefile.am中定义的结构建立Makefile.in，然后configure脚本将生成的Makefile.in文件转换  为Makefile。如果在configure.ac中定义了一些特殊的宏，比如AC_PROG_LIBTOOL，它会调用libtoolize，否则它  会自己产生config.guess和config.sub</p><pre style="line-height: normal">user input files   optional input   processes          output files<br />================   ==============   =========          ============<br /><br />                                     .--------,<br />                                     |        | - - -&gt; COPYING<br />                                     |        | - - -&gt; INSTALL<br />                                     |        |------&gt; install-sh<br />                                     |        |------&gt; missing<br />                                     |automake|------&gt; mkinstalldirs<br />configure.ac -----------------------&gt;|        |<br />Makefile.am  -----------------------&gt;|        |------&gt; Makefile.in<br />                                     |        |------&gt; stamp-h.in<br />                                 .---+        | - - -&gt; config.guess<br />                                 |   |        | - - -&gt; config.sub<br />                                 |   `------+-'<br />                                 |          | - - - -&gt; config.guess<br />                                 |libtoolize| - - - -&gt; config.sub<br />                                 |          |--------&gt; ltmain.sh<br />                                 |          |--------&gt; ltconfig<br />                                 `----------'</pre> <p style="line-height: normal">5.autoconf:将configure.ac中的宏展开，生成configure脚本。这个过程可能要用到aclocal.m4中定义的宏。</p><pre style="line-height: normal">user input files   optional input   processes          output files<br />================   ==============   =========          ============<br /><br />aclocal.m4 ,autoconfig.h.in - - - - - - -.<br />                                         V<br />                                     .--------,<br />configure.ac -----------------------&gt;|autoconf|------&gt; configure</pre><pre style="line-height: normal"> </pre><pre style="line-height: normal">6. ./configure的过程</pre><pre style="line-height: normal"><br />                                           .-------------&gt; [config.cache]<br />     configure* --------------------------+-------------&gt; config.log<br />                                          |<br />              [config.h.in] -.            v            .--&gt; [autoconfig.h]<br />                             +-------&gt; config.status* -+                   <br />              Makefile.in ---'                         `--&gt;   Makefile</pre><pre style="line-height: normal"> </pre><pre style="line-height: normal">7. make过程</pre><pre style="line-height: normal"> </pre><pre style="line-height: normal">[autoconfig.h] -.<br />                     +--&gt; make* ---&gt;  程序<br />        Makefile   ---'</pre><pre style="line-height: normal"> </pre><pre style="line-height: normal">.---------,<br />                   config.site - - -&gt;|         |<br />                  config.cache - - -&gt;|<strong><u>configure</u></strong>| - - -&gt; config.cache<br />                                     |         +-,<br />                                     `-+-------' |<br />                                       |         |----&gt; config.status<br />                   config.h.in -------&gt;|config-  |----&gt; config.h<br />                   Makefile.in -------&gt;|  .status|----&gt; Makefile<br />                                       |         |----&gt; stamp-h<br />                                       |         +--,<br />                                     .-+         |  |<br />                                     | `------+--'  |<br />                   ltmain.sh -------&gt;|ltconfig|-------&gt; libtool<br />                                     |        |     |<br />                                     `-+------'     |<br />                                       |config.guess|<br />                                       | config.sub |<br />                                       `------------'<p> </p><pre>.--------,<br />                   Makefile ------&gt;|        |<br />                   config.h ------&gt;|  <strong><u>make</u></strong>  |<br />{project sources} ----------------&gt;|        |--------&gt; {project targets}<br />                                 .-+        +--,<br />                                 | `--------'  |<br />                                 |   libtool   |<br />                                 |   missing   |<br />                                 |  install-sh |<br />                                 |mkinstalldirs|<br />                                 `-------------'</pre> </pre></div></span>实例：<br />在/hello/目录下创建一个hello.c文件，并编译运行它：  <p>#cd /hello/</p> <p>(1) 编写源文件hello.c：</p> <p>#include&lt;stdio.h&gt; <br />int main(int argc, char**  argv)<br />{<br />printf("Hello, GNU!n");<br />return 0;<br />}</p> <p>[litao@vm0000131 hello]$ ll<br />total 4<br />-rw-rw-r-- 1 litao litao 68 Aug 12  12:02 hello.c</p> <p>一、autoscan</p> <p>[litao@vm0000131 hello]$ autoscan<br />autom4te:  configure.ac: no such file or directory<br />autoscan: /usr/bin/autom4te failed  with exit status: 1<br />[litao@vm0000131 hello]$ ll<br />total 8<br />-rw-rw-r-- 1  litao litao   0 Aug 12 12:03 autoscan.log<br />-rw-rw-r-- 1 litao litao 457 Aug 12  12:03 configure.scan<br />-rw-rw-r-- 1 litao litao  68 Aug 12 12:02 hello.c</p> <p>已经生成了configure.scan，autoscan.log文件</p> <p>将configure.scan 修改为 configure.in，最后修改的内容如下：</p> <p>[litao@vm0000131  hello]$ mv configure.scan configure.in    <br />[litao@vm0000131 hello]$ vim configure.in  <br /></p> <p>#                                               -*- Autoconf  -*-<br /># Process this file with autoconf to produce a configure  script.<br /><br />AC_PREREQ(2.59)<br />AC_INIT(FULL-PACKAGE-NAME, VERSION,  BUG-REPORT-ADDRESS)<br />AC_CONFIG_SRCDIR([hello.c])<br />#AC_CONFIG_HEADER([config.h])<br />AM_INIT_AUTOMAKE(hello,  1.0)<br /># Checks for programs.<br />AC_PROG_CC<br /><br /># Checks for  libraries.<br /><br /># Checks for header files.<br /><br /># Checks for typedefs,  structures, and compiler characteristics.<br /><br /># Checks for library  functions.<br />AC_OUTPUT(Makefile)</p> <p>二、acloacl<br /></p> <p>[litao@vm0000131 hello]$ aclocal <br /></p> <p>生成 aclocal.m4 和 autom4te.cache  (生成aclocal.m4的过程中涉及到configure.in)</p> <p>[litao@vm0000131 hello]$ ll<br />total  44<br />-rw-rw-r-- 1 litao litao 31120 Aug 12 12:08 aclocal.m4<br />drwxr-xr-x 2  litao litao  4096 Aug 12 12:08 autom4te.cache<br />-rw-rw-r-- 1 litao litao     0  Aug 12 12:03 autoscan.log<br />-rw-rw-r-- 1 litao litao   496 Aug 12 12:08  configure.in<br />-rw-rw-r-- 1 litao litao    68 Aug 12 12:02  hello.c</p> <p>三、antoconf<br /></p>[litao@vm0000131 hello]$ autoconf<br />生成 configure (根据 configure.in, 和  aclocal.m4)<br />[litao@vm0000131 hello]$ ll<br />total  168<br />-rw-rw-r-- 1 litao litao  31120 Aug 12 12:08 aclocal.m4<br />drwxr-xr-x 2  litao litao   4096 Aug 12 12:11 autom4te.cache<br />-rw-rw-r-- 1 litao litao       0 Aug 12 12:03 autoscan.log<br />-rwxrwxr-x 1 litao litao 122297 Aug 12 12:11  configure<br />-rw-rw-r-- 1 litao litao    496 Aug 12 12:08  configure.in<br />-rw-rw-r-- 1 litao litao     68 Aug 12 12:02  hello.c<br /><br />四、编写Makefile.am：  <p>AUTOMAKE_OPTIONS= foreign<br />bin_PROGRAMS= hello<br />hello_SOURCES=  hello.c</p>五、automake  <p>生成 Makefile.in， depcomp， install-sh， 和 missing (根据 Makefile.am, 和  aclocal.m4)</p> <p>[litao@vm0000131 hello]$ automake<br />configure.in:  required file `./install-sh' not found<br />configure.in: required file  `./missing' not found<br />Makefile.am: required file `./depcomp' not  found<br />[litao@vm0000131 hello]$ automake  --add-missing<br />configure.in: installing `./install-sh'<br />configure.in:  installing `./missing'<br />Makefile.am: installing  `./depcomp'<br />[litao@vm0000131 hello]$ ll<br />total 192<br />-rw-rw-r-- 1 litao  litao  31120 Aug 12 12:08 aclocal.m4<br />drwxr-xr-x 2 litao litao   4096 Aug 12  12:14 autom4te.cache<br />-rw-rw-r-- 1 litao litao      0 Aug 12 12:03  autoscan.log<br />-rwxrwxr-x 1 litao litao 122297 Aug 12 12:11  configure<br />-rw-rw-r-- 1 litao litao    496 Aug 12 12:08  configure.in<br />lrwxrwxrwx 1 litao litao     31 Aug 12 12:16 depcomp -&gt;  /usr/share/automake-1.9/depcomp<br />-rw-rw-r-- 1 litao litao     68 Aug 12 12:02  hello.c<br />lrwxrwxrwx 1 litao litao     34 Aug 12 12:16 install-sh -&gt;  /usr/share/automake-1.9/install-sh<br />-rw-rw-r-- 1 litao litao     69 Aug 12  12:15 Makefile.am<br />-rw-rw-r-- 1 litao litao  16561 Aug 12 12:16  Makefile.in<br />lrwxrwxrwx 1 litao litao     31 Aug 12 12:16 missing -&gt;  /usr/share/automake-1.9/missing</p> <p>六、configure<br />生成 Makefile， config.log， 和 config.status</p> <p><br /></p></div></td></tr></tbody></table><div id="in_reader"><table width="100%"><tbody><tr><td><br /></td><td><br /></td><td valign="top" align="center" style="text-align: -webkit-auto;"><span style="font-size: 14px; line-height: 21px;"><br /></span></td> <td valign="top" align="center"><a href="http://hi.baidu.com/%E7%AB%B9%E6%9E%97%E8%8B%B1%E5%AE%A2" target="_blank" pid="9ea3d6f1c1d6d3a2bfcd0508">竹林英客</a></td> <td valign="top" align="center"><a href="http://hi.baidu.com/zxjlwt" target="_blank" pid="99bb7a786a6c7774d201">zxjlwt</a></td> <td valign="top" align="center"><a href="http://hi.baidu.com/luckyltq" target="_blank" pid="ceec6a617a656c74715b02">jazeltq</a></td></tr></tbody></table></div><img src ="http://www.cppblog.com/lauer3912/aggbug/169966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-04-03 22:20 <a href="http://www.cppblog.com/lauer3912/archive/2012/04/03/169966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CL.exe的全部命令开关(摘) - 酱坛子 - C++博客 </title><link>http://www.cppblog.com/lauer3912/archive/2012/03/30/169568.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Fri, 30 Mar 2012 12:46:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/03/30/169568.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/169568.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/03/30/169568.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/169568.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/169568.html</trackback:ping><description><![CDATA[<div>导读： <br /> <br /><p>/C:在预处理输出中保留注释语句<br />/c:只编译，不连接，相当于在"Build"菜单下选择了"Compile"<br />/D:定义常量和宏，与源程序里的#define 有相同效果<br />/E:预处理C、C＋＋源文件，将源文件中所有的预编译指令及宏展开，将注释去掉，然后将预处理器的输出拷贝至标准输出设备输出，并且在每个文件的开头和末尾加入#line<br />/EH:指定编译器用何种异常处理模型<br />/EP:同/E,只是去掉了#line<br />/F:设置程序的堆栈大小<br />/FA:设置生成何种列表文件（汇编、汇编与机器码、汇编与源码、汇编与机器码以及源码）<br />/Fa:指定用/FA设置的列表文件的存放路径及（或）文件名<br />/FD:生成文件的相互依赖信息<br />/Fd:设置程序数据库文件（PDB）的存放路径及（或）文件名<br />/Fe:设置最终可执行文件的存放路径及（或）文件名<br />/FI:预处理指定的头文件，与源文件中的＃include有相同效果<br />/Fm:创建map文件<br />/Fo:设置编译后Obj文件的存放路径及（或）文件名<br />/Fp:设置预编译文件（pch）的存放路径及（或）文件名<br />/FR:生成浏览信息（sbr）文件<br />/Fr:同/FR,不同之处在于/Fr不包括局部变量信息<br />/G3:为80386处理器优化代码生成<br />/G4:为80486处理器优化代码生成<br />/G5:为Pentium处理器优化代码生成<br />/G6:为Pentium Pro处理器优化代码生成<br />/GA:为Windows应用程序作优化<br />/GB:为Pentium处理器优化代码生成，使用80386、80486、Pentium、Pentium Pro的混合指令集，是代码生成的默认选项（程序属性选项中Processor对应Blend）<br />/GD:为Windows动态库（dll）作优化，此开关在VC6中没有实现<br />/Gd:指定使用__cdecl的函数调用规则<br />/Ge:激活堆栈检测<br />/GF:消除程序中的重复的字符串，并将她放到只读的缓冲区中<br />/Gf:消除程序中的重复字符串<br />/Gh:在每个函数的开头调用钩子（hook）函数--penter<br />/Gi:允许渐进编译<br />/Gm:允许最小化rebuild<br />/GR:允许运行时类型信息(Run-Time Type Infomation)<br />/Gr:指定使用__fastcall的函数调用规则<br />/Gs:控制堆栈检测所用内存大小<br />/GT:支持用__declspec(thread)分配的数据的fier-safety<br />/GX:允许同步异常处理，与/EHsc开关等价<br />/Gy:允许编译器将每一个函数封装成COMDATs的形式，供连接器调用<br />/GZ:允许在Debug build 的时候捕捉Release build的错误<br />/Gz:指定使用__stdcall的函数调用规则<br />/H:限制外部名字的长度<br />/HELP:列出编译器的所有的命令开关<br />/I:指定头文件的搜索路径<br />/J:将char的缺省类型从signed char改成unsigned char<br />/LD:创建一个动态连接库<br />/LDd:创建一个Debug版本的动态链接库<br />/link:将指定的选项传给连接器<br />/MD:选择多线程、DLL版本的C Run－Time库<br />/MDd:选择多线程、DLL、Debug版本的C Run－Time库<br />/ML:选择单线程版本的C Run&#8212;Time库<br />/MLd:选择单线程、Debug版本的C Run&#8212;Time库<br />/MT:选择多线程版本的C Run-Time库<br />/MTd:选择多线程、Debug版本的C Run&#8212;Time库<br />/nologo:不显示程序的版权信息<br />/O1:优化使产生的可执行代码最小<br />/O2:优化使产生的可执行代码速度最快<br />/Oa:指示编译器程序里没有使用别名，可以提高程序的执行速度<br />/Ob:控制内联（inline）函数的展开<br />/Od:禁止代码优化<br />/Og:使用全局优化<br />/Oi:用内部函数去代替程序里的函数调用，可以使程序运行的更快，但程序的长度变长<br />/Op:提高浮点数比较运算的一致性<br />/Os:产生尽可能小的可执行代码<br />/Ot:产生尽可能块的可执行代码<br />/Ow:指示编译器在函数体内部没有使用别名<br />/Ox:组合了几个优化开关，达到尽可能多的优化<br />/Oy:阻止调用堆栈里创建帧指针<br />/Q1f:对核心级的设备驱动程序生成单独的调试信息<br />/QI0f:对Pentium 0x0f错误指令作修正<br />/Qifdiv:对Pentium FDIV错误指令作修正<br />/P:将预处理输出写到指定文件里，文件的后缀名为I<br />/TC:将命令行上的所有文件都当作C源程序编译，不管后缀名是否为.c<br />/Tc:将指定的文件当作C源程序编译，不管后缀名是否为.c<br />/TP:将命令行上的所有文件都当作C＋＋源程序编译，不管后缀名是否为.cpp<br />/Tp:将指定文件当作C＋＋源程序编译，不管后缀名是否为.cpp<br />/U:去掉一个指定的前面定义的符号或常量<br />/u:去掉所有前面定义的符号或常量<br />/V:在编译的obj文件里嵌入版本号<br />/vd:禁止/允许构造函数置换<br />/vmb:选择指针的表示方法，使用这个开关，在声明指向某个类的成员的指针之前，必须先定义这个类<br />/vmg:选择指针的表示方法，使用这个开关，在声明指向某个类的成员的指针之前，不必先定义这个类，但要首先指定这个类是使用何种继承方法<br />/vmm:设置指针的表示方法为Single Inheritance and Multiple Inheritance<br />/vms:设置指针的表示方法为Single Inheritance<br />/vmv:设置指针的表示方法为Any class<br />/W:设置警告等级<br />/w:禁止所有警告<br />/X:阻止编译器搜索标准的include 目录<br />/Yc:创建预编译头文件（pch）<br />/Yd:在所有的obj文件里写上完全的调试信息<br />/Yu:在build过程中使用指定的预编译头文件<br />/YX:指示编译器若预编译头文件存在，则使用它，若不存在，则创建一个<br />/Z7:生成MSC7.0兼容的调试信息<br />/Za:禁止语言扩展(Microsoft Extensions to C)<br />/Zd:调试信息只包含外部和全局的符号信息以及行号信息<br />/Ze:允许语言扩展(Microsoft Extensions to C)<br />/Zg:为源文件里面定义的每个函数生成函数原型<br />/ZI:生成程序库文件（Pdb）并支持Edit and Continue调试特性<br />/Zi:生成程序库文件（pdb），包含类型信息和符号调试信息<br />/ZL:从obj文件里去掉缺省的库文件名<br />/Zm:设置编译器的内存分配xianzhi<br />/Zn:禁止浏览信息文件里面的封装<br />/Zp:设置结构成员在内存里面的封装格式<br />/Zs:快速检查语法错误<br />－－－－－－－－－－－－－－－－－－－－－－－－－－<br />vc所支持的文件类型</p> <br /><p>DSW:全称是Developer Studio Workspace，最高级别的配置文件，记录了整个工作空间的配置信息，她是一个纯文本的文件，在vc创建新项目的时候自动生成<br />DSP:全称是Developer Studio Project，也是一个配置文件，不过她记录的是一个项目的所有配置信息，纯文本文件<br />OPT：与DSW、DSP配合使用的配置文件，她记录了与机器硬件有关的信息，同一个项目在不同的机器上的opt文件内容是不同的<br />CLW：记录了跟ClassWizard相关的信息，如果丢失了clw文件，那么在Class View面板里就没有类信息<br />PLG：实际上是一个超文本文件，可以用Internet Explorer打开，记录了Build的过程，是一个日志型文件<br />RC：资源描述文件，记录了所有的资源信息，在资源编辑器里作的修改，实际上都是对RC文件的修改<br />RC2：附加的资源描述文件，不能直接资源编辑器修改，只能手工添加，可以用来添加额外的资源<br />RES：经过资源编辑器编译之后的资源文件，以二进制方式存放<br />SBR：编译器生成的浏览信息文件，在代码导航的时候非常有用，她需要在编译时指定/FR或者/Fr开关<br />BSC：BSCMAKE.EXE将所有的SBR文件作为输入，经过处理之后输出一个BSC文件，在代码导航的时候实际用到的是BSC文件<br />ILK：当选定渐增型编译连接时，连接器自动生成ILK文件，记录连接信息<br />PDB：全称是Program DataBase，即程序数据库文件，用来记录调试信息，是一个相当重要的文件，没有他，程序无法正常调试<br />LIB：如果项目输出是Dll的话，一般会输出一个跟项目同名的Lib文件，记录输出的函数信息<br />EXP：同Lib，是跟Dll一起生成的输出文件<br />PCH：全称是PreCompiled Header，就是预先编译好的头文件，在编译时指定/Yu开关时编译器自动生成</p><br /><br />本文转自 <br /><a href="http://www.cppblog.com/sunraiing9/archive/2007/11/26/37323.html">http://www.cppblog.com/sunraiing9/archive/2007/11/26/37323.html</a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/169568.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-03-30 20:46 <a href="http://www.cppblog.com/lauer3912/archive/2012/03/30/169568.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows平台下的调试技术 - 小夜曲的孤伤 - 博客大巴 </title><link>http://www.cppblog.com/lauer3912/archive/2012/03/30/169567.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Fri, 30 Mar 2012 12:45:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2012/03/30/169567.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/169567.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2012/03/30/169567.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/169567.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/169567.html</trackback:ping><description><![CDATA[<div>导读： <br /><br /> <br /><p style="line-height: 180%"><a href="http://creativecommons.org/licenses/by/3.0/deed.zh" target="_blank">版权声明</a>：转载时请以超链接形式标明文章原始出处和作者信息及<a href="http://bangzhuzhongxin.blogbus.com/logs/11205960.html" target="_blank">本声明</a><br /><a href="http://chenshine.blogbus.com/logs/4414354.html">http://chenshine.blogbus.com/logs/4414354.html</a><br /><br /></p> <br /><div style="padding-right: 10px; padding-left: 10px; padding-bottom: 10px; padding-top: 10px">刚 进入计算机相关专业领域时，大家最先用过的调试器大多会是Turbo C。它虽然古老但用过的人却很多，然而严格的讲，Turbo  C是一个集成开发环境，虽然拥有独立的编译器，链接器，却没有独立的调试器，这和Visual  Studio一样。如果你做过DOS，早期Windows下的汇编，也许你会对Debug，CodeView等调试工具熟悉，但这些工具太老 了，Debug甚至不能调试32位程序，介绍它们与这篇文章的主旨不符，如果你对它们感兴趣，可以去查阅相关资料。本文主要是介绍与调试技术相关的理论知 识以及常用调试器的使用，Windows设备驱动程序与内核的调试等。具体的讲解方法是理论结合实践，并且是站在给新手看的角度，循序渐进的，用一个一个 调试会话向你展示每个重要命令的使用。</div> <br /><hr style="color: blue" /> <br />目录<br /><br />1。调试器<br />2。调试信息<br />3。用户模式程序的调试<br />4。驱动程序与内核的调试<br /><br /><span style="color: #0033ff">1 调试器</span><br /><br /><span style="color: #0033ff">1。1 概览</span><br /><br />调 试器，与编译器，链接器一样，都属于基础软件，它们在制作上都有很大的难度，但尽管如此，现实中还是有不少专业级的调试器，微软官方的就有 cdb，ntsd，WinDbg，kd等，还有SoftIce，OllyDbg等来自于其它公司的优秀调试器。本文不可能对这几个调试器一一介绍，一个是 限于篇幅，另一个是上面列举的这几个调试器无论是哪一个都需要你花很长的时间去完全掌握（在市面上有很多书籍甚至专门讲解某一个调试器的使用，比如 SoftIce）。虽然本文不会讲解SoftIce的详细使用，但我还是要对它进行简短的介绍，因为它太有名了，甚至比Windows出生的早。<br /><br /><span style="color: #0033ff">1。2 SoftIce</span><br /><br />SoftIce 是NuMega公司生产的调试器，产于80年代后期，直到今天为止，这个软件已经变革过好几次了，因为处理器的体系结构在更新，操作系统也在更新，所以调 试器也必须相应的更新。它之所以有名，那是与历史有关的，在Intel推出386 Cpu的时候，NuMega立即让SoftIce支持了386  Cpu的新特性，同时吸引了大量黑客的使用，使它在黑客界产生了一定的地位(功能强大的调试器可以对软件的保护机制进行破解，如突破序列号之类的)。在 Windows推出时，所有的调试器都不适用这种新的系统软件体系结构了，唯一能用的就是微软自己生产的调试器，却很拙劣，这时NuMega又对 SoftIce进行了变革，不仅让它可以在新的系统上很好的工作，甚至还可以调试Windows的内核，这是当时是不敢想象的。也正是因为它很好的性能， 卓越的功能，它成为了黑客们的宠儿，并且培养了几代的黑客。读完本文后，你自己应该有能力去探索它，或许你也可以在这几款调试器里找到适合自己的。<br /><br style="color: #0033ff" /><span style="color: #0033ff">1。3 微软的调试工具</span><br /><br />本 文主要介绍的是微软官方的调试器，并且MS微软也最积极，调试工具包一直在更新中。在微软的调试器里，大家可能最为熟悉Visual Studio  Debugger，就是你在Visual C++里使用的那个，它并不是一个单独可运行的程序，而是内嵌在Visual  Studio中的，它的功能相对于上面几个调试器来说要弱很多，这里并不会对它进行介绍，如果你想全方面的了解它的话，你可以去参考MSDN，那里专门有 几章讲解它，是一份很好的文档化的资源(而且还是中文的)。其它的微软调试工具cdb，ntsd，WinDbg，kd都在微软的一个安装包里，被称作<a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx" target="_blank">Debugging Tools for Windows</a>(10 多M的大小，请通过这个链接下载并安装，一会儿就要用到)。这些调试器在下文中会分别介绍，这里先做一个简单的区别，cdb与ntsd几乎是一样的程序， 唯一的不同是cdb是一个CUI程序，即Console程序，而ntsd是GUI程序，但ntsd并没有产生窗口，而是又分配了一个Console窗口， 这个Console窗口就相当于是cdb。它与真正的cdb执行完全一样的功能(官方如是说，然而实际上还有一些个不同)。在命令行中启动它们时下面两句 命令有一样的效果(C:/Progs/Debug是调试工具包的安装位置)：<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Progs/Debug/&gt;start cdb<br />C:/Progs/Debug/&gt;ntsd<br /></pre><br />cdb 与ntsd是用来调试用户模式应用程序的。kd调试器也是一个命令行程序，不过正如其名kernel  debugger所描述的一样，它是内核调试器的，是驱动程序开发者，系统Hacker的最爱。WinDbg是一个称职的GUI程序，它有菜单，有工具 栏，还有多个子窗口，可以分别显示源代码，调用栈，命令等，它既可以调试ring 0程序，也可以调试ring  3程序，其实它只是一个壳而已，当调试ring 3级程序时它实际上是用cdb/ntsd，而当调试ring  0级程序时是用kd。WinDbg的到来吸引了很多的人使用，你也将会发现，它确实是一款优秀的调试器。<br /><br />2 调试信息<br /><br />调试器之所以能够工作，完全是依赖于编译和链接程序时所生成的调试信息，当然调试信息是具有一定的格式的。<br /><br /><span style="color: #0033ff">2。1 格式</span><br /><br />微 软的调试信息格式经过了几代变化，最终形成了Program  DataBase这种格式，并且这种格式还在进行版本上的更新，VS.Net所用的新的Program DataBase版本与Visual C++  6.0所用的老的版本是不兼容的，并且你也可以用编译器和链接器明确指定你想要生成的调试信息格式，这一点下文中有阐述。<br /><br /><span style="color: #0033ff">2。2 内容</span><br /><br />关 于调试信息我们还必须知道两件事，一是调试信息包括哪些内容，二是调试信息储存在什么地方。其实调试信息所应该包括的内容正是调试信息格式变化的原因，从 COFF格式，到CodeView格式，到Program DataBase格式，调试信息变得越来越丰富了，并且是只多不少。Program  DataBase格式的调试信息中主要包括了所有全局函数，static  函数，全局变量，static变量，局部变量，函数形参的名字及其位置，源代码与可执行文件中指令的映射信息，每个函数与变量的类型，以及FPO信息，编 辑和继续信息。编辑与继续信息主要用于在Visual Studio中调试时，可以在调试的同时编辑源代码，并在接下来的调试中得到体现。Program  DataBase格式的调试信息包含了这么多的内容，所以用这种调试信息来调试程序时，你将能够得到更多，更准确，更深入的反馈。<br /><br /><span style="color: #0033ff">2。3 存储位置</span><br /><br />调 试信息的存储位置是与其格式相关的，Program  DataBase格式的调试信息存储在一个单独的文件里，扩展名为pdb。像以前的CodeView格式的调试信息即可存储在单独的文件里，又可存储在编 译时所生成的obj文件中。知道了这些知识后，我们就可以正确地生成调试信息了。在后面的内核调试中我们还要继续谈到它。<br /><br /><span style="color: #0033ff">3 用户模式程序的调试</span><br /><br />根 据上面的讲述，我们可以用cdb或WinDbg来进行ring  3程序的调试，这里先讲解cdb。cdb允许你启动某个被调试程序(以下称debugee)的一个新的实例来进行调试，即先创建cdb，然后cdb再把你 所指定的程序创建为一个新进程进而对其调试，也允许debugee在已经运行的情况下被cdb attach上。cdb还可以对Crash  Dump(程序崩溃时的内存Copy，下文将会说明)进行调试，只需要加上-z选项，后面再加上Crash  Dump的文件名即可。这几种调试方式下面将会一一讲述。<br /><br />3。1 调试前的准备<br /><br />第 2节中对调试信息进行了理论上的说明，接下来我们来看看在实际中应该如何操作。首先我们的程序必须要经过编译，链接，并且在编译和链接时还要指定一些选项 以正确地生成调试信息。这里所使用的编译器是cl.exe，链接器是link.exe，都是微软官方的，Visual  Studio就是用的这两个(CTRL+F5就是顺序调用cl和link的快捷键)，如果你安装了Visual C++或Visual  Studio，就会有它们，另外一种选择是安装SDK，也能够得到它们。本文所用的cl.exe和link.exe是Visual C++  6.0的版本。若要生成调试信息，编译时我们需要加上的选项应是/Zi，而链接时则要加上/debug。在下面的调试中，我们将用C语言来写程序，所以你 有必要知道用C语言写出来的程序与用汇编写出来的有什么不同。首先，每个程序都有一个入口函数，它的地址需要在链接时指定，并被链接器放到最终可执行文件 的头部，通常用汇编语言写的程序，有选择的，你可以在源代码中指定入口函数，而用C语言写的程序则需要在链接的时候来指定入口函数，说到这你可能不以为 然，&#8220;C语言写的程序的入口函数不就是main吗？&#8220;。实际上，控制台C程序的入口函数默认情况下是C运行时的启动函数：mainCRTStartup。 然后由这个函数调用你写的main函数，所以可执行文件的头部存放的入口地址是mainCRTStartup的地址，而不是你写的main函数地址。 mainCRTStartup主要做了一些为了正确执行C/C++程序的初始化工作。它已经由微软写好了，由链接器自动链接到可执行文件中。如果你在程序 中不使用C语言的库以及一些ANSI规定的全局变量，只是单纯地使用C语言这种语法，那么你也可以不链接mainCRTStartup，直接指定你自己写 的某个函数为入口函数，这也是我们在下文中所使用的方法，具体的做法是在链接时加入如下选项：/subsystem:console  /entry:你的入口函数名称。这个入口函数应该是不带参数的。现在我们来总结一下上面所讲的内容，假定你的源程序名为exam.c，你想指定的入口函 数为main，那么应该如下生成可执行程序：<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;cl /Zi exam.c /link /debug /subsystem:console /entry:main</pre>另 外，就算你不链接mainCRTStartup(它会调用很多的Win32  API)，也不在源程序中调用任何的系统函数。那么系统还是会把一些动态链接库，如kernel32.dll，Ntdll.dll等动态链接到你的程序所 对应的进程里，即把它们映射到你的程序对应的进程地址空间里。这是因为在你所指定的入口函数运行之前，还会有一系列的 Kernel32.dll，Ntdll.dll中的函数要运行。即在用户空间中你指定的入口函数，例如上面的main，根本不是第一个运行的函数。那么那 些函数是做什么的呢，通过大量的反汇编和调试能够推断出它们是做一些进程，线程在用户空间的初始化，设置一些异常桢等。在下面的调试中我们将会用一些手段 来研究它们。这些函数是操作系统的一部分，因些我们必须从官方网站下载它的符号文件，当然不下载也行，那么你将面临的会是一大堆的警告。说到下载，没有比 这更简单的了，你不需要预先的下载，只需要添加一个环境变量_NT_SYMBOL_PATH即可，而真正的下载工作由调试器来做，这个环境变量的值与已存 在的PATH环境变量类似，是由分号分隔的一系列的路径组成。这些路径应该包括你的调试信息文件(pdb文件)所在地，如前面的C:/Pro/。如果要下 载系统文件如Kernel32.dll，Ntdll.dll的pdb文件，你仅仅需要再加一个这样的路径：SRV*D:/Symbols*http: //msdl.microsoft.com/download/symbols，其中D:/Symbols是可更换的，你可以换成任何一个其它的路径，这 个D:/Symbls是用来存放从后面的URL路径所下载下来的系统调试信息文件的。其实你也可以预先下载系统调试信息文件到一个路径里，然后在 _NT_SYMBOL_PATH里指定那个目录，但这样一来有两个缺点，一是你必须得进行版本的匹配，做这件事简直太乏味了，二是你一次需要把整个操作系 统的调试信息文件都下载下来，可能会需要1G的空间。而通过前面设置环境变量的方式，调试器会根据需要只下载这次调试会话所需要的调试信息文件，并且它会 自动给你匹配版本。由于我们将要编写的源代码都在C:/Pro/文件夹中，生成的pdb文件也在C:/Pro/中，所以我们的 _NT_SYMBOL_PATH环境变量应该如下设置，假设你希望系统pdb文件下载到D:/Symbols：<br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;set _NT_SYMBOL_PATH=SRV*D:/Symbols*http://msdl.microsoft.com/download/symbols;C:/Pro/<br /></pre>最后，我们需要在命令行中启动cdb调试器，但当前目录通常是源代码文件夹C:/Pro/，为了避免如下冗余的键入：<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;<span style="color: #ff0000">C:/Progs/Debug/</span>cdb example1.exe</pre>应该为cdb，ntsd，WinDbg设置PATH环境变量：<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;set PATH=%PATH%;C:/Progs/Debug/</pre>这里的C:/Progs/Debug是Debugging Tools for Windows的安装目录。以后就可以这样来调试了：<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;cdb example1.exe</pre><br /><span style="color: #0033ff">3。2 cdb启动新实例的调试</span><br /><br /><span style="color: #0033ff">3。2。1 编写一源程序，启动cdb</span><br /><br />首先我编写了下面的C程序，先用这个程序来介绍一些基本的命令，并且来验证一下调试信息中是否确切包含了上面所说的那些内容:<br /><br /><span style="color: #0033ff">[example1.c]</span><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0"><span style="color: #0033ff">int</span> 		gVar;<br /><span style="color: #0033ff">static</span> 	<span style="color: #0033ff">int</span>	sgVar;<br /><span style="color: #0033ff">int</span> 		Inc(<span style="color: #0033ff">int</span> Param);<br /><span style="color: #0033ff">static</span>	<span style="color: #0033ff">int</span>	sDec(<span style="color: #0033ff">int</span> sParam);<br /><span style="color: #0033ff">void</span> main(<span style="color: #0033ff">void</span>)<br />{<br />	<span style="color: #0033ff">int</span> lVar;<br />	<span style="color: #0033ff">static</span> <span style="color: #0033ff">int</span> slVar;<br />	lVar = 3;<br />	slVar = 4;<br />	gVar = Inc(lVar);<br />	sgVar = sDec(slVar);<br />}<br /><span style="color: #0033ff">int</span> Inc(<span style="color: #0033ff">int</span> Param)<br />{<br />	<span style="color: #0033ff">return</span> (Param+1);<br />}<br /><span style="color: #0033ff">int</span> sDec(<span style="color: #0033ff">int</span> sParam)<br />{<br />	<span style="color: #0033ff">return</span> (sParam-1);<br />}<br /></pre>对这个程序用上面所讲的方法编译链接：<br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 0px; border-left: #b78c67 1px solid; width: 99%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;cl /Zi example1.c /link /debug /subsystem:console /entry:main</pre>接下来启动cdb调试器：<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 1px; border-left: #b78c67 1px solid; width: 99%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">C:/Pro/&gt;cdb example1.exe<br /><br />Microsoft (R) Windows Debugger <br />Copyright (c) Microsoft Corporation. All rights reserved.<br /><br />CommandLine: example1.exe<br />Symbol search path is: SRV*D:/Symbols*http://msdl.microsoft.com/download/symbols<br />Executable search path is:<br />ModLoad: 00400000 00406000   example1.exe<br />ModLoad: 7c920000 7c9b4000   ntdll.dll<br />ModLoad: 7c800000 7c91c000   C:/WINDOWS/system32/kernel32.dll<br />(c94.c24): Break instruction exception - code 80000003 (first chance)<br />eax=00251eb4 ebx=7ffd4000 ecx=00000001 edx=00000002 esi=00251f48 edi=00251eb4<br />eip=7c921230 esp=0012fb20 ebp=0012fc94 iopl=0         nv up ei pl nz na po nc<br />cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202<br />ntdll!DbgBreakPoint:<br />7c921230 cc              int     3<br />0:000&gt;<br /></pre>cdb 输出了此时主线程的上下文信息(这个例子中也只有这一个线程)以及程序断点信息后便会进入一个新的提示符：0:000&gt;。以后我们会一直工作在这种 类型的提示符上，下面在这个提示符上输入一个命令来加载所有的调试信息文件，此时可能会慢一些，因为要下载系统DLL的pdb文件，所以要确保你能上网。<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 15px; border-left: #b78c67 1px solid; width: 90%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">0:000&gt;.reload /f</pre><br />看到这个以"."号做为前缀的命令，可能你会觉得怪怪的，但实际上还有用"!"号做前缀的呢，用"."号做前缀的命令表示元命令，而用"!&#8220;号做前缀的命令表示扩展命令，这里只做一个简单的区分即可。<br /><br />其 实这时我们所要调试的程序已经运行起来了，不过停在了某处，主线程处于冻结状态。这一点和Linux的Gnu调试器GDB不一样，对于GDB调试器，你先 要设置一个断点，然后再键入运行命令(如果自己不手动设置一个断点，那么程序将会一直运行直到结束，你根本没有调试的机会。)，这时程序才处于运行状态。 没有运行和运行之后处于冻结状态是两个完全不同的概念。那么我们这个example1.exe停在了什么地方呢。下面我将介绍一个很重要的命令，用它我们 可以来研究这方面的问题。<br /><br /><span style="color: #0033ff">3。2。2 查看堆栈及用户空间的初始化</span><br /><br />用kb命令可以来查看堆栈，它显示栈上一些重要的信息。<br /><br /><pre style="border-right: #b78c67 1px solid; padding-right: 8px; border-top: #b78c67 1px solid; margin-top: 10px; padding-left: 8px; padding-bottom: 3px; margin-left: 5px; border-left: #b78c67 1px solid; width: 99%; padding-top: 5px; border-bottom: #b78c67 1px solid; font-family: 'Courier New',Fixedsys; background-color: #edeef0">0:000&gt;kb<br />ChildEBP RetAddr  Args to Child<br />0012fb1c 7c95edc0 7ffdf000 7ffd4000 00000000 ntdll!DbgBreakPoint<br />0012fc94 7c941639 0012fd30 7c920000 0012fce0 ntdll!LdrpInitializeProcess+0xffa<br />0012fd1c 7c92eac7 0012fd30 7c920000 00000000 ntdll!_LdrpInitialize+0x183<br />00000000 00000000 00000000 00000000 00000000 ntdll!KiUserApcDispatcher+0x7<br /></pre>这个命令所列出来的信息后面还要详细介绍，这里先关注一下函数的调用关系。从上面的列表可以看到有四个函数，这四个函数都是ntdll模块里的，从下至上函数依次被调用。要注意这是当前线程的用户栈里所有的东西，就四个函数，<span style="font-family: Courier New">KiUserApcDispatcher</span>是第一个，上面已经提到过，在你指定的入口函数执行之前还有很多的函数被调用，<span style="font-family: Courier New">KiUserApcDispatcher</span>是第一个被调用的，接下来它再调用<span style="font-family: Courier New">_LdrpInitialize</span>，<span style="font-family: Courier New">_LdrpInitialize</span>调用<span style="font-family: Courier New">LdrpInitializeProcess</span>，再调用<span style="font-family: Courier New">DbgBreakPoint</span>。至于是谁调用的<span style="font-family: Courier New">KiUserApcDispatcher</span>，我现在只能简单的告诉你是操作系统调度例程调度的结果。深入地探讨它就离开本文的主题了。现在我们可以肯定的是程序停在了<span style="font-family: Courier New">DbgBreakPoint</span>里，因为它是栈上最后一个函数。从cdb调试器的输出可以看到example1.exe停在了<span style="font-family: Courier New">DbgBreakPoint</span>函数里的<span style="font-family: Courier New">int 3</span>语句上，<span style="font-family: Courier New">int 3</span>是一个异常，它将会通知操作系统挂起这个线程，并且通知调试器，这是操作系统对调试的一个支持。其实<span style="font-family: Courier New">DbgBreakPoint</span>函数只有一条语句，那就是<span style="font-family: Courier New">int 3</span>。敏感点的人可能会想到，这样一来，所有的程序，无论是否被调试，在运行的时候最初都会执行<span style="font-family: Courier New">DbgBreakPoint</span>函数了，这也太傻了吧？情况并非如此，当我们键入cdb example1.exe时，cdb在启动example1.exe的时候会加一个特殊的标记，在这种情况下<span style="font-family: Courier New">LdrpInitializeProcess</span>才会调用<span style="font-family: Courier New">DbgBreakPoint</span>，这又是操作系统对调试的一个支持。<br /><br /><br />本文转自 <br /><a href="http://chenshine.blogbus.com/logs/4414354.html">http://chenshine.blogbus.com/logs/4414354.html</a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/169567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2012-03-30 20:45 <a href="http://www.cppblog.com/lauer3912/archive/2012/03/30/169567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Breakpad 完全解析（二） —— Windows前台实现篇</title><link>http://www.cppblog.com/lauer3912/archive/2011/11/07/159785.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Mon, 07 Nov 2011 13:36:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/11/07/159785.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/159785.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/11/07/159785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/159785.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/159785.html</trackback:ping><description><![CDATA[<div><h2>Google Breakpad 完全解析（二） &#8212;&#8212; Windows前台实现篇</h2> 2011年02月7日 &#8212; Asp J   <div><h3>Table of contents for Google Breakpad 完全解析</h3><ol><li><a href="http://bigasp.com/archives/450" title="Google Breakpad 完全解析（一） &#8212;&#8212; Windows入门篇">Google Breakpad 完全解析（一） &#8212;&#8212; Windows入门篇</a></li><li>Google Breakpad 完全解析（二） &#8212;&#8212; Windows前台实现篇</li></ol></div> <p>原创文章，转载请标明出处：Soul Apogee (<a href="http://bigasp.com/" target="_blank">http://bigasp.com</a>)，谢谢。</p> <p>好，看完了<a href="http://bigasp.com/archives/450" target="_blank">如何使用breakpad</a>，我们现在看看breakpad在Windows下到底是如何实现的呢？</p> <h3><strong>代码结构</strong></h3> <p>在我们来看breakpad是如何实现其强大的功能之前，我们先来看一下他的代码结构吧。</p> <p>Google breakpad的源代码都在src的目录下，他分为如下几个文件夹：<br /> client：这下面包含了前台应用程序中捕捉dump的部分代码，里面按照平台分成各个子文件夹<br /> common：前台后台都会用到的部分基础代码，字符串转换，内存读写，md5神马的<br /> google_breakpad：breakpad中公共的头文件<br /> processor：用于在后台处理崩溃的核心代码<br /> testing：测试工程<br /> third_party：第三方库<br /> tools：一些小工具，用于处理dump文件和符号表</p> <p>我们先来看Windows下前台实现的部分，也就是client文件夹下的代码。</p> <h3><strong>breakpad的崩溃捕获机制</strong></h3> <p>在Windows下捕获崩溃，大家很容易会想到那个捕获结构化异常的Api：<a target="blank" href="http://www.google.com/search?ie=UTF-8&amp;q=SetUnhandledExceptionFilter">SetUnhandledExceptionFilter</a>。</p> <p>breakpad中也使用了这个Api来实现的崩溃捕获，另外，breakpad还捕获了另外两种C++运行库提供的崩溃，一种是使用<a target="blank" href="http://www.google.com/search?ie=UTF-8&amp;q=_set_purecall_handler">_set_purecall_handler</a>捕获纯虚函数调用产生的崩溃，还有一种是使用<a target="blank" href="http://www.google.com/search?ie=UTF-8&amp;q=_set_invalid_parameter_handler">_set_invalid_parameter_handler</a>捕获错误的参数调用产生的崩溃。</p> <div><div id="highlighter_32943"  cpp"=""><div><a href="http://bigasp.com/archives/458#" command_help=""  help"="">?</a></div><table cellpadding="0" cellspacing="0" border="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div><div number10="" index9=""  alt1"="">10</div></td><td><div><div number1="" index0=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code> <code plain"="">(handler_types &amp; HANDLER_EXCEPTION)</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">previous_filter_ = SetUnhandledExceptionFilter(HandleException);</code></div><div number3="" index2=""  alt2"="">&nbsp;</div><div number4="" index3=""  alt1"=""><code preprocessor"="">#if _MSC_VER &gt;= 1400&nbsp;&nbsp;// MSVC 2005/8</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code> <code plain"="">(handler_types &amp; HANDLER_INVALID_PARAMETER)</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);</code></div><div number7="" index6=""  alt2"=""><code preprocessor"="">#endif&nbsp;&nbsp;// _MSC_VER &gt;= 1400</code></div><div number8="" index7=""  alt1"="">&nbsp;</div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code> <code plain"="">(handler_types &amp; HANDLER_PURECALL)</code></div><div number10="" index9=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);</code></div></div></td></tr></tbody></table></div></div> <p>另外由于C++运行库提供的崩溃回调中，并不会提供当前的线程现场和崩溃信息，所以breakpad会自己生成好这些信息，然后请求生成dump。<br /> 这里值得一说的是，在非异常崩溃处理中，breakpad获取线程现场使用的函数是RtlCaptureContext而不是GetThreadContext。<br /> RtlCaptureContext只能捕获当前线程的现场，而GetThreadContext可以捕获任意线程的现场，只要有这个线程的句柄即可。<br /> 但是GetThreadContext有两个不好的地方：不能获取当前线程的现场；获取现场前必须先用SuspendThread暂停目标线程。<br /> 而RtlCaptureContext虽然只能获取当前线程的现场，但是调用他时可以不用暂停线程的运行。<br /> 对于breakpad来说，崩溃发生后越早获取现场就越好，所以breakpad使用RtlCaptureContext函数作为他的线程获取函数。</p> <h3><strong>breakpad中的C/S结构</strong></h3> <p>由于breakpad是在进程外抓取dump，所以breakpad需要实现一个C/S结构来处理崩溃进程抓取dump的请求。</p> <p><strong>1. breakpad跨进程通信的实现<br /> </strong>breakpad中使用了命名管道来实现IPC。</p> <p>在客户端，初始化ExceptionHandler的时候，如果指定了PipeName，也就表示此时需要使用进程外的dump抓 取，ExceptionHandler，会建立一个&nbsp;CrashGenerationClient的对象，由这个对象连接服务端，将自己注册到服务端上 去。<br /> 大家可以参看exception_handler.cc中的ExceptionHandler::Initialize函数。</p> <p>在服务端，初始化CrashGenerationServer的时候，就会建立一个命名管道，并等待客户端来连接。一旦有客户端连接上来，服务端会 为每一个客户端生成一个ClientInfo的对象，之后用这个对象来管理所有的客户端，一旦有崩溃发生，服务端都会从这个对象中取出dump所需要的信 息。<br /> 大家可以参看crash_generation_server.cc中的CrashGenerationServer::HandleReadDoneState函数。</p> <p><strong>2. breakpad捕获崩溃生成dump的流程<br /> </strong>breakpad进程外生成dump的流程大概如下：<br /> <strong>google-breakpad-out-of-process-dump:</strong><br /><a href="http://bigasp.com/wp-content/plugins/download-monitor/download.php?id=138" target="_blank"><img src="http://bigasp.com/wp-content/uploads/downloads/thumbnails/2011/02/google-breakpad-out-of-process-dump.jpg" alt="google-breakpad-out-of-process-dump" style="max-width:500px;" /></a><br /> 这段流程的代码就是crash_generation_client.cc和crash_generation_server.cc。</p> <p>有两个简单的问题，这里说明一下，高手们就请直接忽略吧，咩哈哈：<br /> <strong>在服务端如何为客户端生成事件句柄？</strong><br /> 使用DuplicateHandle，即可把任意一个内核对象的句柄复制到其他进程，并且可以指定产生的句柄的权限。</p> <p><strong>如何异步的等待一个事件？<br /> </strong>使用RegisterWaitForSingleObject，即可异步的等待一个事件，当事件发生的时候，就可以回调到一个指定的回 调函数中，但是要注意的是，RegisterWaitForSingleObject会在一个新的线程中来等待这个事件，此处很容易产生多线程的调用，需 要注意线程问题。</p> <p><strong>3. 服务端关键数据结构：ClientInfo<br /> </strong>ClientInfo是服务端中最重要的数据结构，服务端通过它来管理所有的客户端。客户端注册时，会保存或生成里面所有的信息，在客户端请求生成dump的时候，服务端就会通过ClientInfo获取所有客户端的信息。ClientInfo中保存了如下信息：</p> <ul><li>客户端进程pid和句柄</li><li>生成Minidump的类型</li><li>自定义的客户端信息</li><li>客户端崩溃的线程ID</li><li>客户端崩溃的信息</li><li>客户端请求崩溃所使用的事件句柄</li></ul> <p>这里有一个问题：在客户端发生崩溃时，服务器如何通过ClientInfo获取到客户端的崩溃信息呢？</p> <p>客户端中有几个用于保存崩溃信息的变量，在注册时，客户端会将这几个变量的地址发送至服务端，服务端将其保存在ClientInfo中，然后当崩溃 发生的时候，服务端就可以通过ReadProcessMemory读取客户端中的信息，从而生成dump。这样做就避免了每次发生崩溃，都要通过Pipe 将崩溃信息传递到服务端中去了。</p> <p>这些变量分别是：崩溃的线程ID，EXCEPTION_POINTERS和MDRawAssertionInfo。<br /> EXCEPTION_POINTERS和MDRawAssertionInfo的区别在于，异常崩溃的信息会被写入EXCEPTION_POINTERS，非异常崩溃（非法参数和纯虚函数调用）的信息会被写入MDRawAssertionInfo中。</p> <h3><strong>dump文件的上传</strong></h3> <p>在breakpad的工程中，有一个工程叫做：crash_report_sender，里面是一个上传崩溃文件的类，他的实现很简单，他使用Windows Internet Api来完成dump文件的上传。<br /> 在使用crash_report_sender时，可以为其指定一个checkpoint_file。</p> <div><div id="highlighter_216810"  cpp"=""><div><a href="http://bigasp.com/archives/458#" command_help=""  help"="">?</a></div><table cellpadding="0" cellspacing="0" border="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div></td><td><div><div number1="" index0=""  alt2"=""><code keyword=""  bold"="">explicit</code> <code plain"="">CrashReportSender(</code><code keyword=""  bold"="">const</code> <code plain"="">wstring &amp;checkpoint_file);</code></div></div></td></tr></tbody></table></div></div> <p>这个文件只有一个作用，就是用来保存上次上传崩溃的时间和今天上传过的崩溃的次数。通过这个文件，我们就可以来设置每日上传的崩溃的最大数量。</p> <div><div id="highlighter_535960"  cpp"=""><div><a href="http://bigasp.com/archives/458#" command_help=""  help"="">?</a></div><table cellpadding="0" cellspacing="0" border="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div><div number13="" index12=""  alt2"="">13</div><div number14="" index13=""  alt1"="">14</div><div number15="" index14=""  alt2"="">15</div><div number16="" index15=""  alt1"="">16</div><div number17="" index16=""  alt2"="">17</div><div number18="" index17=""  alt1"="">18</div><div number19="" index18=""  alt2"="">19</div><div number20="" index19=""  alt1"="">20</div><div number21="" index20=""  alt2"="">21</div><div number22="" index21=""  alt1"="">22</div><div number23="" index22=""  alt2"="">23</div><div number24="" index23=""  alt1"="">24</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">CrashReportSender::CrashReportSender(</code><code keyword=""  bold"="">const</code> <code plain"="">wstring &amp;checkpoint_file)</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">: checkpoint_file_(checkpoint_file),</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">max_reports_per_day_(-1),</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">last_sent_date_(-1),</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">reports_sent_(0) {</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;</code><code color1=""  bold"="">FILE</code> <code plain"="">*fd;</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code> <code plain"="">(OpenCheckpointFile(L</code><code string"="">"r"</code><code plain"="">, &amp;fd) == 0) {</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">ReadCheckpoint(fd);</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code functions=""  bold"="">fclose</code><code plain"="">(fd);</code></div><div number10="" index9=""  alt1"=""><code spaces"="">&nbsp;&nbsp;</code><code plain"="">}</code></div><div number11="" index10=""  alt2"=""><code plain"="">}</code></div><div number12="" index11=""  alt1"="">&nbsp;</div><div number13="" index12=""  alt2"=""><code plain"="">ReportResult CrashReportSender::SendCrashReport(</code></div><div number14="" index13=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">const</code> <code plain"="">wstring &amp;url, </code><code keyword=""  bold"="">const</code> <code plain"="">map&lt;wstring, wstring&gt; &amp;parameters,</code></div><div number15="" index14=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">const</code> <code plain"="">wstring &amp;dump_file_name, wstring *report_code) {</code></div><div number16="" index15=""  alt1"=""><code spaces"="">&nbsp;&nbsp;</code><code color1=""  bold"="">int</code> <code plain"="">today = GetCurrentDate();</code></div><div number17="" index16=""  alt2"=""><code spaces"="">&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code> <code plain"="">(today == last_sent_date_ &amp;&amp;</code></div><div number18="" index17=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">max_reports_per_day_ != -1 &amp;&amp;</code></div><div number19="" index18=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">reports_sent_ &gt;= max_reports_per_day_) {</code></div><div number20="" index19=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">return</code> <code plain"="">RESULT_THROTTLED;</code></div><div number21="" index20=""  alt2"=""><code spaces"="">&nbsp;&nbsp;</code><code plain"="">}</code></div><div number22="" index21=""  alt1"="">&nbsp;</div><div number23="" index22=""  alt2"=""><code spaces"="">&nbsp;&nbsp;</code><code comments"="">// 上传文件部分代码，省略</code></div><div number24="" index23=""  alt1"=""><code plain"="">}</code></div></div></td></tr></tbody></table></div></div> <p>调整每日上传崩溃的最大数量的函数是set_max_reports_per_day。</p> <p>需要注意的是：在上传dump文件的时候，crash_report_sender并不会对dump文件进行分析，而是直接上传整个dump文件， 如果你需要上传的dump文件非常大的话，可以考虑把崩溃分析处理的逻辑放入前台，通过去重或者直接上传分析结果，减少上传的文件大小。</p> <h3><strong>breakpad存在的问题</strong></h3> <h3><span style="font-weight: normal; font-size: 13px;">进程外生成dump有很多好处，其中最大的好处就是不会被崩溃进程影响，这样dump的过程就不容易出错，但是这样也有一定的弊端。</span></h3> <p><strong>1. 部分崩溃无法抓取<br /> </strong>在一些极端的崩溃，如堆栈溢出之类的崩溃，进程外抓取dump有时候会失败。</p> <p><strong>2. 无法抓取死锁或者其他原因导致的进程僵死<br /> </strong>breakpad现在没有检测进程死锁的代码，也没有在服务端控制客户端请求dump的代码，所以现在breakpad无法抓取死锁等进程僵死的问题。不过因为breakpad的定位是处理崩溃，如果有这种需要的童鞋，可以自行修改breakpad的代码，添加这些功能。</p> <p><strong>3. 对服务端有依赖<br /> </strong>如果指定了在使用进程外抓取dump，breakpad对服务端就有依赖。主要体现在抓取dump时，如果服务端不存在，客户端将无法正常抓取dump，甚至有时会出现阻塞。</p> <p>当然对于这些问题，随着breakpad的发展肯定会越来越完善。如果，你遇到了了这些问题，而又绕过不了，那就改代码，并且提交给breakpad吧，开源项目就是这么发展的。</p> <p>好，到此breakpad的Windows实现就已经说完了，如果有神马问题，还请多多指教。谢谢大家。</p><p style="margin-bottom:0pt; margin-top:0pt; "><a href="http://www.0531jsk.com/"><span style=" color:#0000ff; text-decoration:underline ;font-family:'宋体'; ">北京德胜门中医院</span></a><a href="http://www.0531jsk.com/"><span style=" color:#0000ff; text-decoration:underline ;font-family:'宋体'; ">http://www.0531jsk.com/</span></a><span style=" font-size:10.5000pt; font-family:'宋体'; ">德胜门中医院</span></p></div><img src ="http://www.cppblog.com/lauer3912/aggbug/159785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-11-07 21:36 <a href="http://www.cppblog.com/lauer3912/archive/2011/11/07/159785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Breakpad 完全解析（一） —— Windows入门篇</title><link>http://www.cppblog.com/lauer3912/archive/2011/11/07/159784.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Mon, 07 Nov 2011 13:34:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/11/07/159784.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/159784.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/11/07/159784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/159784.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/159784.html</trackback:ping><description><![CDATA[<div><h2>Google Breakpad 完全解析（一） &#8212;&#8212; Windows入门篇</h2> 2011年01月23日 &#8212; Asp J   <div><h3>Table of contents for Google Breakpad 完全解析</h3><ol><li>Google Breakpad 完全解析（一） &#8212;&#8212; Windows入门篇</li><li><a href="http://bigasp.com/archives/458" title="Google Breakpad 完全解析（二） &#8212;&#8212; Windows前台实现篇">Google Breakpad 完全解析（二） &#8212;&#8212; Windows前台实现篇</a></li></ol></div> <p>原创文章，转载请标明出处：Soul Apogee (<a href="http://bigasp.com/" target="_blank">http://bigasp.com</a>)，谢谢。  </p> <p><a title="Google Breakpad" href="http://code.google.com/p/google-breakpad/" target="_blank">Google breakpad</a>是 一个非常实用的跨平台的崩溃转储和分析模块，他支持Windows，Linux和Mac和Solaris。由于他本身跨平台，所以很大的减少我们在平台移 植时的工作，毕竟崩溃转储，每个平台下都不同，使用起来很难统一，而Google  breakpad就帮我们做到了这一点，不管是哪个平台下的崩溃，都能够进行统一的分析。现在很多工程都在使用他：最著名的几个如 Chrome，Firefox，Picasa和Google  Earth。另外他的License是BSD的，也就是说，我们即便是在商业软件中使用，也是合法的，哈哈，这么好的东西，我们能放过么？现在就让我们来 看看这个神奇的软件吧。</p> <h3><strong>原理简介</strong></h3> <p>breakpad抓取dump的方式和一般我们抓取dump的方式不一样。在breakpad的wiki上有一幅图可以很好的概括他的原理。</p> <p><img title="breakpad" src="http://google-breakpad.googlecode.com/svn/wiki/breakpad.png" alt="" height="464" width="425" /></p> <p>breakpad把应用程序分成三个部分，代码，breakpad客户端和调试信息。</p> <p>1. 在build system中，通过symbol dumper用平台相关的调试信息生成平台无关的symbol文件。这样做的好处很明显，一旦平台无关了，所有平台的崩溃就可以做统一的分析了。<br /> 2. breakpad采取进程外转储和分析崩溃的方式，他使用C/S结构，客户端用来捕获当前进程中发生的崩溃，并通知服务端崩溃发生。服务端用来响应客户端，抓取dump文件。这样做的目的是为了减少崩溃进程对dump的影响。<br /> 3. Dump生成后转发到崩溃分析器中，这个部分可以在本地也可以在服务器上，他对Dump文件进行解析，生成可读的堆栈信息。</p> <p>这就是breakpad处理dump大概的流程。</p> <p>对于原理的介绍google写的已经相当好了。更多的详细信息，可以直接移步到<a href="http://code.google.com/p/google-breakpad/w/list" target="_blank">breakpad的wiki</a>。</p> <h3><strong>安装和编译</strong></h3> <p>breakpad的编译比较曲折，所以在此记录一下。</p> <p>编译breakpad，请确认你的机器上装有以下的软件：<br /> 1. <a href="http://www.python.org/download/releases/2.4.3/" target="_blank">python 2.4.3</a><a href="http://www.python.org/download/releases/2.4.3/" target="_blank"><br /> </a>请不要使用python3，会报错。另外python2中推荐这个版本，使用新的版本在编译其他google的工程时有时会报错</p> <p>2. <a href="http://www.google.com/search?q=windows+sdk+7" target="_blank">Windows SDK 7</a><a href="http://www.google.com/search?q=windows+sdk+7" target="_blank"><br /> </a>如果没有这个，编译会报错。另外这个是在线安装，时间很久，最好并行做其他的事情。</p> <p>3. VS2005的补丁<br /> KB918559<br /> KB926601<br /> KB935225<br /> KB943969<br /> KB947315</p> <p>已经安装了以上软件的童鞋，就可以开始进行下面的工作鸟</p> <p>1. 使用svn把代码<a href="http://code.google.com/p/google-breakpad/source/checkout" target="_blank">checkout</a>下来</p> <div><div id="highlighter_301422"  shell"=""><div><a href="http://bigasp.com/archives/450#" command_help=""  help"="">?</a></div><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"=""># Non-members may check out a read-only working copy anonymously over HTTP.</code></div><div number2="" index1=""  alt1"=""><code plain"="">svn checkout http:</code><code plain"="">//google-breakpad</code><code plain"="">.googlecode.com</code><code plain"="">/svn/trunk/</code> <code plain"="">google-breakpad-</code><code functions"="">read</code><code plain"="">-only</code></div></div></td></tr></tbody></table></div></div> <p>2. 设置Windows SDK 7<br /> 装过其他版本Windows SDK的童鞋，记得一定要进行这一步，SDK的安装程序，并不会帮你设置VS。<br /> 运行开始菜单-&gt;程序-&gt;Microsoft Windows SDK v7.0-&gt;Visual Studio  Registration-&gt;Windows SDK Configuration Tool，选择v7.0，点击Make Current。</p> <p>3. 为python设置环境变量<br /> 由于breakpad使用python来生成Windows下的工程文件，所以需要将python所在目录，设置到环境变量PATH中去。</p> <p>4. 生成Windows工程文件</p> <div><div id="highlighter_825083"  shell"=""><div><a href="http://bigasp.com/archives/450#" command_help=""  help"="">?</a></div><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div></td><td><div><div number1="" index0=""  alt2"=""><code functions"="">cd</code> <code string"="">"源码目录/src/tools/gyp"</code></div><div number2="" index1=""  alt1"="">&nbsp;</div><div number3="" index2=""  alt2"=""><code comments"=""># 注意，此处不能使用全路径，不然会出错</code></div><div number4="" index3=""  alt1"=""><code plain"="">gyp.bat </code><code string"="">"../../client/windows/breakpad_client.gyp"</code></div></div></td></tr></tbody></table></div></div> <p>此时，在src/client/windows下就可以看到生成好的breakpad_client.sln了。运行吧！</p> <p>5. Hello World!<br /> 编译build all，现在一般是不会报错了，如果报错，请检查是不是漏了什么步骤，特别是补丁。<br /> 编译完成之后，运行crash_generation_app吧，这是他的测试程序，dump的默认位置保存在C:Dumps下，请注意先建立好目录，不然会无法使用。<br /> 启动测试程序之后，此时还不能抓取dump，因为这个是breakpad中的服务器端，需要再启动一个测试程序，在第二个测试程序中，我们就可以试验Client菜单中的各种崩溃了。这些崩溃都会被抓住转存到C:Dumps目录下。</p> <h3><strong>如何使用breakpad</strong></h3> <p> </p> <p>在Windows下<a href="http://code.google.com/p/google-breakpad/wiki/WindowsClientIntegration" target="_blank">使用breakpad的方法</a>很简单，只需要创建一个ExceptionHandler的类即可，大家可以在crash_generation_app这个工程中找到示例代码，也可以直接<a href="http://code.google.com/p/google-breakpad/wiki/WindowsClientIntegration" target="_blank">移步</a>Wiki，上面说的也很详细。</p> <p>1.进程内抓取Dump文件</p> <p>进程内抓取Dump文件是最简单的breakpad的用法。使用方法很简单：</p> <div><div id="highlighter_394770"  cpp"=""><div><a href="http://bigasp.com/archives/450#" command_help=""  help"="">?</a></div><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div><div number13="" index12=""  alt2"="">13</div><div number14="" index13=""  alt1"="">14</div><div number15="" index14=""  alt2"="">15</div><div number16="" index15=""  alt1"="">16</div><div number17="" index16=""  alt2"="">17</div><div number18="" index17=""  alt1"="">18</div><div number19="" index18=""  alt2"="">19</div><div number20="" index19=""  alt1"="">20</div><div number21="" index20=""  alt2"="">21</div></td><td><div><div number1="" index0=""  alt2"=""><code keyword=""  bold"="">const</code> <code plain"="">std::wstring s_strCrashDir = L</code><code string"="">"c:\dumps"</code><code plain"="">;</code></div><div number2="" index1=""  alt1"="">&nbsp;</div><div number3="" index2=""  alt2"=""><code color1=""  bold"="">bool</code></div><div number4="" index3=""  alt1"=""><code plain"="">InitBreakpad()</code></div><div number5="" index4=""  alt2"=""><code plain"="">{</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">google_breakpad::ExceptionHandler *pCrashHandler =</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">new</code> <code plain"="">google_breakpad::ExceptionHandler(s_strCrashDir,</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onExceptionFilter,</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onMinidumpDumped,</code></div><div number10="" index9=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number11="" index10=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">google_breakpad::ExceptionHandler::HANDLER_ALL,</code></div><div number12="" index11=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">MiniDumpNormal,</code></div><div number13="" index12=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number14="" index13=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL);</code></div><div number15="" index14=""  alt2"="">&nbsp;</div><div number16="" index15=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code><code plain"="">(pCrashHandler == NULL) {</code></div><div number17="" index16=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">return</code> <code keyword=""  bold"="">false</code><code plain"="">;</code></div><div number18="" index17=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number19="" index18=""  alt2"="">&nbsp;</div><div number20="" index19=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">return</code> <code keyword=""  bold"="">true</code><code plain"="">;</code></div><div number21="" index20=""  alt2"=""><code plain"="">}</code></div></div></td></tr></tbody></table></div></div> <p>2.进程外抓取Dump文件</p> <p>使用进程外抓取Dump时，需要指定服务端和客户端，在服务端中需要创建CrashGenerationServer的实例，而在客户端中则只需要创建ExceptionHandler即可。此外，如果服务端自己需要抓进程内的Dump，请将pipe的参数置为NULL。</p> <div><div id="highlighter_709395"  cpp"=""><div><a href="http://bigasp.com/archives/450#" command_help=""  help"="">?</a></div><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div><div number13="" index12=""  alt2"="">13</div><div number14="" index13=""  alt1"="">14</div><div number15="" index14=""  alt2"="">15</div><div number16="" index15=""  alt1"="">16</div><div number17="" index16=""  alt2"="">17</div><div number18="" index17=""  alt1"="">18</div><div number19="" index18=""  alt2"="">19</div><div number20="" index19=""  alt1"="">20</div><div number21="" index20=""  alt2"="">21</div><div number22="" index21=""  alt1"="">22</div><div number23="" index22=""  alt2"="">23</div><div number24="" index23=""  alt1"="">24</div><div number25="" index24=""  alt2"="">25</div><div number26="" index25=""  alt1"="">26</div><div number27="" index26=""  alt2"="">27</div><div number28="" index27=""  alt1"="">28</div><div number29="" index28=""  alt2"="">29</div><div number30="" index29=""  alt1"="">30</div><div number31="" index30=""  alt2"="">31</div><div number32="" index31=""  alt1"="">32</div><div number33="" index32=""  alt2"="">33</div><div number34="" index33=""  alt1"="">34</div><div number35="" index34=""  alt2"="">35</div><div number36="" index35=""  alt1"="">36</div><div number37="" index36=""  alt2"="">37</div><div number38="" index37=""  alt1"="">38</div><div number39="" index38=""  alt2"="">39</div><div number40="" index39=""  alt1"="">40</div><div number41="" index40=""  alt2"="">41</div><div number42="" index41=""  alt1"="">42</div><div number43="" index42=""  alt2"="">43</div><div number44="" index43=""  alt1"="">44</div></td><td><div><div number1="" index0=""  alt2"=""><code keyword=""  bold"="">const</code> <code color1=""  bold"="">wchar_t</code> <code plain"="">s_pPipeName[] = L</code><code string"="">"\\.\pipe\breakpad\crash_handler_server"</code><code plain"="">;</code></div><div number2="" index1=""  alt1"=""><code keyword=""  bold"="">const</code> <code plain"="">std::wstring s_strCrashDir = L</code><code string"="">"c:\dumps"</code><code plain"="">;</code></div><div number3="" index2=""  alt2"="">&nbsp;</div><div number4="" index3=""  alt1"=""><code color1=""  bold"="">bool</code></div><div number5="" index4=""  alt2"=""><code plain"="">InitBreakpad()</code></div><div number6="" index5=""  alt1"=""><code plain"="">{</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">google_breakpad::CrashGenerationServer *pCrashServer =</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">new</code> <code plain"="">google_breakpad::CrashGenerationServer(s_pPipeName,</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number10="" index9=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onClientConnected,</code></div><div number11="" index10=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number12="" index11=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onClientDumpRequest,</code></div><div number13="" index12=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number14="" index13=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onClientExited,</code></div><div number15="" index14=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number16="" index15=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">true</code><code plain"="">,</code></div><div number17="" index16=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&amp;s_strCrashDir);</code></div><div number18="" index17=""  alt1"="">&nbsp;</div><div number19="" index18=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code><code plain"="">(pCrashServer == NULL) {</code></div><div number20="" index19=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">return</code> <code keyword=""  bold"="">false</code><code plain"="">;</code></div><div number21="" index20=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number22="" index21=""  alt1"="">&nbsp;</div><div number23="" index22=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">// 如果已经服务端已经启动了，此处启动会失败</code></div><div number24="" index23=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code><code plain"="">(!pCrashServer-&gt;Start()) {</code></div><div number25="" index24=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">delete</code> <code plain"="">pCrashServer;</code></div><div number26="" index25=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">pCrashServer = NULL;</code></div><div number27="" index26=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number28="" index27=""  alt1"="">&nbsp;</div><div number29="" index28=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">google_breakpad::ExceptionHandler *pCrashHandler =</code></div><div number30="" index29=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">new</code> <code plain"="">google_breakpad::ExceptionHandler(s_strCrashDir,</code></div><div number31="" index30=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onExceptionFilter,</code></div><div number32="" index31=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">onMinidumpDumped,</code></div><div number33="" index32=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL,</code></div><div number34="" index33=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">google_breakpad::ExceptionHandler::HANDLER_ALL,</code></div><div number35="" index34=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">MiniDumpNormal,</code></div><div number36="" index35=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">(pCrashServer == NULL) ? s_pPipeName : NULL, </code><code comments"="">// 如果是服务端，则直接使用进程内dump</code></div><div number37="" index36=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">NULL);</code></div><div number38="" index37=""  alt1"="">&nbsp;</div><div number39="" index38=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">if</code><code plain"="">(pCrashHandler == NULL) {</code></div><div number40="" index39=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">return</code> <code keyword=""  bold"="">false</code><code plain"="">;</code></div><div number41="" index40=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number42="" index41=""  alt1"="">&nbsp;</div><div number43="" index42=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword=""  bold"="">return</code> <code keyword=""  bold"="">true</code><code plain"="">;</code></div><div number44="" index43=""  alt1"=""><code plain"="">}</code></div></div></td></tr></tbody></table></div></div> <p>使用breakpad的时候，有两个地方需要注意：<br /> 1. 记得把breakpad的solution下的几个工程，包含到你开发的工程中，或者直接包含他们的lib。<br /> common：基础功能，包含一个对GUID的封装和http上传的类。<br /> exception_handler：用来捕获崩溃的类。<br /> crash_generation_server：breakpad的服务端，用来在产生崩溃时抓取dump。<br /> crash_generation_client：breakpad的客户端，用来捕获当前进程的崩溃。</p> <p>2. 在初始化breakpad之前，记得先创建好dump文件的目录，不然breakpad服务端将不能正常的写dump，这会导致breakpad客户端在崩溃时无限等待服务端dump写完的消息，最后失去响应。</p></div><img src ="http://www.cppblog.com/lauer3912/aggbug/159784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-11-07 21:34 <a href="http://www.cppblog.com/lauer3912/archive/2011/11/07/159784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试Release发布版程序的Crash错误 （转）</title><link>http://www.cppblog.com/lauer3912/archive/2011/11/07/159781.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Mon, 07 Nov 2011 13:15:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/11/07/159781.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/159781.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/11/07/159781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/159781.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/159781.html</trackback:ping><description><![CDATA[<div><h1><a id="viewpost1_TitleUrl" href="../../Walker/articles/146153.html">调试Release发布版程序的Crash错误 （转）</a></h1> 	 		<div> 			<h2><a id="viewpost1_TitleUrl" href="../../woaidongmao/archive/2011/05/10/146092.html">调试Release发布版程序的Crash错误</a> </h2> <div> <p><a title="http://blog.sina.com.cn/s/blog_48f93b530100fsln.html" href="http://blog.sina.com.cn/s/blog_48f93b530100fsln.html">http://blog.sina.com.cn/s/blog_48f93b530100fsln.html</a></p> <p>&nbsp;</p> <p>在<span>Windows平台下用C++开发应用程序，最不想见到的情况恐怕就是程序崩溃，而要想解决引起问题的bug，最困难的应该就是调试release版本了。因为release版本来就少了很多调试信息，更何况一般都是发布出去由用户使用，crash的现场很难保留和重现。本文将给出几个解决方案，完成对release版应用程序crash错误的调试。（本文只讨论Windows平台MSVC环境下的调试，对于其他平台和开发环境没有关注，请大家自己借鉴和尝试。）</span></p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp; <wbr><strong>方案一：崩溃地址</strong> <span><strong><span>+ MAP</span></strong></span><strong>文件</strong></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span>这种方案只能对<span><span>VC7</span>以前的版本开发的程序使用。<span>&nbsp;<wbr></span></span></p>  <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>1</strong></span><strong>、崩溃地址</strong></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>所谓崩溃地址就是引起程序崩溃的内存地址，在<span>WinXP</span>下应用程序<span>crash</span>的对话框如下图：</span></p> <p align="center"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fsln&amp;url=http://s5.sinaimg.cn/orignal/48f93b53g79aad1fff694&amp;690" target="_blank"><span><span><img title="clip_image001" alt="clip_image001" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image001_0ad42579-f1c9-44ae-b2f8-b50b8a737e0d.jpg" height="181" width="424" border="0" /></span></span></a></p> <p align="center"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fsln&amp;url=http://s7.sinaimg.cn/orignal/48f93b53g79aad2c60546&amp;690" target="_blank"><span><span><img title="clip_image002" alt="clip_image002" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image002_cb3f00fa-aa22-4301-a42c-92c12dff2ea4.jpg" height="120" width="494" border="0" /></span></span></a></p> <p align="center"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fsln&amp;url=http://s2.sinaimg.cn/orignal/48f93b53g79aad34a5521&amp;690" target="_blank"><span><span><img title="clip_image003" alt="clip_image003" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image003_fea81ac9-41ea-42be-a24f-d0fe99dafa80.jpg" height="380" width="494" border="0" /></span></span></a></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><span>上面第<span>2</span>张图中画红线的值为<span>crash</span>的代码偏移地址，第<span>3</span>张图为即<span>crash</span>绝对地址；一般引起<span>crash</span>的原因多为内存操作错误，我们用这两个地址和<span>MAP</span>文件就能定位出错的代码行。</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>2</strong></span><strong>、<span><span>MAP</span>文件</span></strong></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> MAP</span>文件是记录应用程序信息的文件（文本文件），里面大概包含了程序的全局符号、源码模块名、源码文件和行号等信息，而这些信息能够帮助我们定位出错的代码行。</p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span>怎样生成<span><span>MAP</span>文件呢？以<span>VC6</span>为例，在 <span>Project Settings -&gt; C/C++ <wbr>-&gt; Debug info</span>中，选择 <span>Line Numbers Only </span>；在 <span>Project Settings -&gt; Link </span>中，选择 <span>Generate mapfile</span>项，并在<span>Project Options </span>里面输入 </span><span>/MAPINFO:LINES</span> 和 <span><span>/MAPINFO:EXPORTS</span>，重新编译程序就会生成<span>.map</span>文件。</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span>以上设置对应的编译链接选项分别分：</p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><strong><span>/Zi</span></strong> &#8212; 表示生成<span><span>pdb</span>调试信息；</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><strong><span>/MAP[:filename]</span></strong> &#8212; 表示生成<span><span>map</span>文件名；</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><strong><span>/MAPINFO:EXPORTS <wbr></span></strong>&#8212; 表示生成的<span><span>map</span>文件中加入<span>exported functions</span>（生成<span>DLL</span>文件时）；</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><strong><span>/MAPINFO:LINES <wbr></span></strong>&#8212; 表示生成的<span><span>map</span>文件中加入代码行信息。</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span>由于<span><span>/MAPINFO:LINES</span>选项在<span>VC8</span>以后的版本中不再支持，因此通过<span>MAP</span>文件中的信息和<span>crash</span>地址定位出错代码行就比较困难了，所以这种方案只能在<span>VC7</span>及以前的版本中使用。</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>一个<span>MAP</span>文件片段示例如下：<span>&nbsp;<wbr></span></span></p>  <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fsln&amp;url=http://s4.sinaimg.cn/orignal/48f93b53g79aae50a0e23&amp;690" target="_blank"><span><span><img title="clip_image004" alt="clip_image004" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image004_fbf07de5-1b63-4473-917f-f6695904c9be.jpg" height="229" width="494" border="0" /></span>&nbsp;<wbr></span></a>&nbsp;<wbr></span></p>  <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fsln&amp;url=http://s1.sinaimg.cn/orignal/48f93b53g79aae6db2060&amp;690" target="_blank"><span><span><img title="clip_image005" alt="clip_image005" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image005_93f97fcb-0900-4f57-baf2-29a04f821fa2.jpg" height="227" width="494" border="0" /></span></span></a></span></p>  <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><span>图中<span>Rva+Base</span>列的地址为该行函数对应的函数绝对地址，<span>Address</span>列中冒号后面的地址为函数相对偏移地址。<span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></span></span></p>  <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>3</strong></span><strong>、定位<span><span>crash</span>代码</span></strong></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span>有了上面的介绍，定位<span><span>crash</span>代码就很简单了。用下面的公式来进行定位：</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span><strong>崩溃行偏移 <span><span>= </span>崩溃地址 <span>- </span>崩溃函数绝对地址 <span>+ </span>函数相对偏移</span></strong></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> </span>我们首先根据崩溃地址（绝对地址），按照找到第<span><span>2</span>张图中<span>Rva+Base</span>列的地址找到发生崩溃的函数（即崩溃地址大于该函数行的<span>Rva+Base</span>地址且小于下个函数的地址），然后找到该行对应的函数相对偏移地址，带入公式中，就得到了崩溃行偏移，该值表示崩溃行的代码相对于代码所在函数的偏移量。用该值去与第<span>3</span>张图中对应函数冒号后面的偏移量去比较，最接近的值前面的那个十进制数即为代码所在函数中的行号。</span></p> <p><span>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ok</span>，到此我们已经成功找到了崩溃的代码行，只不过这种方法还是比较费力，并且限制比较多，我们看看下面的方案。</p> <p>上篇给出的方案一还要补充几句。通过<span>&#8220;crash地址 + MAP文件&#8221;来定位出错代码位置虽然需要经过比较复杂的地址计算，但却是最简单实现的方式。如果仅仅想通过崩溃地址定位出错的函数，就更加方便了。我在网上找到一个解析MAP文件的小工具，可以非常清晰的列出每个函数的地址，并且可以将分析表格导出为Excel文件。工具下载地址：<a href="http://e.ys168.com/?tinyfun"><span>http://e.ys168.com/?tinyfun</span></a></span>，工具目录下VCMapper.exe。</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 另外上篇主要参考两篇文章：</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://www.vckbase.com/document/viewdoc/?id=908"><span>http://www.vckbase.com/document/viewdoc/?id=908</span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://www.vckbase.com/document/viewdoc/?id=1473"><span>http://www.vckbase.com/document/viewdoc/?id=1473</span></a></p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>方案二：崩溃地址<span> + MAP文件 + COD文件</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 由于<span>VC8以后的版本都不再支持MAP文件中产生代码行信息，因此我们寻找另一种定位方式：COD文件。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>1</span></strong><strong>、<span>COD文件</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> COD文件是一个包含了汇编码、二进制机器码和源代码对应信息的文件，每一个<span>cpp都对应一个COD文件。通过这个文件，我们可以非常方便地进行定位。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 在<span>VC6中生成COD文件的设置方式为：Project Settings -&gt; C/C++，在 Category 中选 Listing Files，在 Listing file type 组合框中选 Assembly，Machine code，and source。在VC8中生成COD文件的设置方式为：Project Properties -&gt; C/C++ -&gt; Output Files -&gt; Assembler Output 项，选择 Assembly，Machine code，and Source(/Facs)。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>2</span></strong><strong>、定位崩溃行</strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 下面通过举例进行说明。现在我有一个基于对话框的<span>MFC应用程序CrashTest，在CCrashTestDlg::OnInitDialog函数中写入导致crash的代码语句（第99行），源文件如下：</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fv7y&amp;url=http://s16.sinaimg.cn/orignal/48f93b53g79bbc36cd95f&amp;690" target="_blank"><span><span><img title="clip_image006" alt="clip_image006" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image006_887560ee-8b72-42ea-a623-220dcb47ac1f.jpg" height="169" width="360" border="0" /></span></span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 根据崩溃地址（<span>0x004012A3）以及MAP文件（定位片段图片如下），定位crash函数为OnInitDialog；并且我们可以很容易地计算出崩溃地址相对于崩溃函数的偏移量为 0x004012A3 - 0x004011E0 = 0xC3。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fv7y&amp;url=http://s11.sinaimg.cn/orignal/48f93b53g79bbc5f052da&amp;690" target="_blank"><span><span><img title="clip_image007" alt="clip_image007" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image007_dc9962ce-f969-4c7f-aa0b-e973cac321ce.jpg" height="36" width="494" border="0" /></span></span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 再来看看<span>CrashTestDlg.cod文件，我们根据文件中源码信息找到OnInitDialog函数信息片段：</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fv7y&amp;url=http://s4.sinaimg.cn/orignal/48f93b53g79bc3c02d3f3&amp;690" target="_blank"><span><span><img title="clip_image008" alt="clip_image008" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image008_00ac91bc-99ca-4d4f-86cd-b0d1d23bb10a.jpg" height="231" width="494" border="0" /></span></span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 可以看到图片中第一行为<span>OnInitDialog函数汇编代码的起始行；找到&#8220;int * p = NULL;&#8221;这一句源码，其前面的98表示这行代码在源文件中的行号，下面的000c1表示相对于函数开始位置的偏移量，后面的&#8220;33 c0&#8221;为机器码，&#8220;xor eax，eax&#8221;为汇编码。那么我们根据前面算出来的偏移量0xC3，找到对应出错的语句为99行：&#8220;*p = 5;&#8221;。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 总结一下定位步骤：</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 1) 根据公式 <strong><span>崩溃语句在函数中偏移地址<span> = 崩溃地址 - 崩溃函数地址</span></span></strong> 计算出偏移量X；</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 2) 根据公式 <strong><span>崩溃语句在<span>COD文件中地址 = 崩溃函数在COD文件中地址 + <wbr>X</span></span></strong> 计算出地址Y。其中崩溃函数在COD文件中地址为COD文件中函数起始括号&#8220;{&#8221;后面表明的地址，一般情况下为0x0000；</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 3) 根据<span>Y在COD文件中找到对应代码行。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ok，方案二介绍完了。这种方法最大的好处是没有<span>VC开发环境版本限制，而且COD文件里面包含的信息更加丰富，不但可以帮助我们定位crash，还能帮我们分析很多东西。当然，这也导致编译生成了很多信息文件。</span></p> <p>根据前面两篇博文，我们要定位崩溃行代码，必须要自己根据相关信息文件进行计算。如果需要处理的量比较大，恐怕会很费力气。有没有更简单快速的办法呢？</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 最直接的想法就是写一个小工具，根据规则和信息进行自动定位，不过开发起来也是要费一番功夫的。令人开心的是，我们可以找到类似的工具，而且是开源免费的！程序员的世界也许很多时候都是这么单纯而乐于分享！</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>方案三：崩溃地址<span> + PDB文件 + CrashFinder</span></strong></p> <p>&nbsp;<wbr><wbr>&nbsp;<wbr><wbr>&nbsp;<wbr><wbr> CrashFinder是一个开源工具，作者是<span>John Robbin，大家可以去他的blog上去找关于CrashFinder的信息。我们这里以CrashFinder2.5版本为例介绍，相关文章链接为：<a href="http://www.wintellect.com/CS/blogs/jrobbins/archive/2006/04/19/crashfinder-returns.aspx"><span>http://www.wintellect.com/CS/blogs/jrobbins/archive/2006/04/19/crashfinder-returns.aspx</span></a></span></p> <p>&nbsp;<wbr><wbr>&nbsp;<wbr><wbr>&nbsp;<wbr> <strong><span>1</span></strong><strong>、<span>PDB文件</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PDB（<span>Program Database）文件中包含了exe程序所有的调试相关信息，具体可以查阅MSDN。当编译选项设置为/Zi，链接选项设置为/DEBUG，/OPT:REF时，就会生成工程的.pdb文件。具体到VC2005中，就是 Project Propertise -&gt; C/C++ -&gt; General -&gt; Debug Information Format 项设置为 Program Database（/Zi），Linker -&gt; Debugging -&gt; Generate Debug Info 项设置为 Yes（/Debug），Linker -&gt; Optimization -&gt; References <wbr>项设置为 Eliminate <wbr>Unreferenced Data（/OPT:REF）。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 只要设置以上选项，<span>release版本也能生成PDB文件。当然，对应的应用程序也会稍大。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>2</span></strong><strong>、<span>CrashFinder</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> CrashFinder能够运行需要两个条件：一是系统必须要有<span>dbghelp.dll文件；二是PDB文件必须与exe文件在一个路径下。对于dbghelp.dll，一般在系统system32路径下都有，如果没有下载一个放到这个目录下就可以了。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 先看一下<span>CrashFinder的界面。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p> <p align="center"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fxvm&amp;url=http://s3.sinaimg.cn/orignal/48f93b53g7a37be0ea632&amp;690" target="_blank"><span><span><img title="clip_image009" alt="clip_image009" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image009_60e666ee-6f31-4132-929c-3ef20c5a9fde.jpg" height="327" width="494" border="0" /></span></span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 用起来也非常简单。首先选择<span>File-&gt;New或点击工具栏新建按钮，选择要调试的exe文件打开，会发现exe及所依赖的dll文件信息都已经加载进来。在下半部分的编辑框中输入崩溃地址（16进制），点右边的&#8220;Find&#8221;按钮，就会在下面显示崩溃的源文件路径、名称以及崩溃所在行号了，如下图所示。</span></p> <p align="center"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100fxvm&amp;url=http://s10.sinaimg.cn/orignal/48f93b53g7a37da3b3c69&amp;690" target="_blank"><span><span><img title="clip_image010" alt="clip_image010" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image010_4b25ce3c-1bea-4818-be58-230d6cba8a6a.jpg" height="370" width="494" border="0" /></span></span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 用<span>CrashFinder进行crash定位真的非常方便。但是我在使用过程中发现了一个bug，每次启动程序后，直接新建的话加载进来的exe模块都显示叉，提示找不到debug symbols。但是用打开按钮随便打开一个文件失败后，再新建就能成功。猜测可能是直接新建，定位PDB文件时的路径不对引起的。有源码，但是懒的看了呵呵，大家感兴趣可以试一下。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 好了，方案三就介绍到这里，后面还有更加强大的方案<span> : )</span></p> <p>前面几个方案都是直接定位<span>crash的代码位置，但是在比较大型的程序中，只知道这个信息还是远远不够的，我们希望知道更多关于调用函数顺序及变量值等信息，也就是crash时调用堆栈信息。</span></p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>方案四：<span>SetUnhandledExceptionFil<wbr>ter + StackWalker</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 这个方案需要自己动手往工程里添加代码了。要实现上面的想法，需要做两件事情：<span>1、需要在crash时有机会对程序堆栈进行处理；2、对堆栈信息进行收集。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>1</span></strong><strong>、<span>SetUnhandleExceptionFilt<wbr>er函数</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> Windows平台下的<span>C++程序异常通常可分为两种：结构化异常（Structured Exception，可以理解为与操作系统相关的异常）和C++异常。对于结构化异常处理（SEH），可以找到很多资料，在此不细说。对于crash错误，一般由未被正常捕获的异常引起，Windows操作系统提供了一个API函数可以在程序crash之前有机会处理这些异常，就是SetUnhandleExceptionFilt<wbr>er函数。（C++也有一个类似函数set_terminate可以处理未被捕获的C++异常。）</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> SetUnhandleExceptionFilt<wbr>er函数声明如下：</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFil<wbr>ter(<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> LPTOP_LEVEL_EXCEPTION_FILTER <em>lpTopLevelExceptionFilte<wbr>r</em><br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 其中<span> LPTOP_LEVEL_EXCEPTION_FILTER 定义如下：</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in struct _EXCEPTION_POINTERS *ExceptionInfo<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 简单来说，<span>SetUnhandleExceptionFilt<wbr>er允许我们设置一个自己的函数作为全局SEH过滤函数，当程序crash前会调用我们的函数进行处理。我们可以利用的是 _EXCEPTION_POINTERS 结构类型的变量ExceptionInfo，它包含了对异常的描述以及发生异常的线程状态，过滤函数可以通过返回不同的值来让系统继续运行或退出应用程序。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 关于<span> SetUnhandleExceptionFilt<wbr>er 函数的具体用法和示例请参考MSDN。</span></p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>2</span></strong><strong>、<span>StackWalker</span></strong><br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 现在我们已经有机会可以在<span>crash之前对程序状态信息进行处理了，只需要生成并保存堆栈信息就大功告成了。Windows的dbghelp.dll库提供了一个函数可以得到当前堆栈信息：StackWalk64（在Win2K以前版本中为StackWalk）。该函数声明如下：</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> BOOL WINAPI StackWalk64(<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> DWORD <em>MachineType</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> HANDLE <em>hProcess</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> HANDLE <em>hThread</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in_out <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> LPSTACKFRAME64 <em>StackFrame</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in_out <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PVOID <em>ContextRecord</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PREAD_PROCESS_MEMORY_ROUTINE64 <em>ReadMemoryRoutine</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PFUNCTION_TABLE_ACCESS_ROUTINE64 <em>FunctionTableAccessRouti<wbr>ne</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PGET_MODULE_BASE_ROUTINE64 <em>GetModuleBaseRoutine</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PTRANSLATE_ADDRESS_ROUTINE64 <em>TranslateAddress</em><br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 该函数的具体用法可以参考<span>MSDN。在这里推荐一个牛人写好的StackWalker，可以直接拿来用，开源的。StackWalker提供了一个基类，给出了几个简单的接口，可以方便地生成堆栈信息，并且支持一系列VC版本，非常好用。我们可以自己写一个子类，并重载虚函数OnOutput，就可以将堆栈信息输出为特定格式了。StackWalker的地址为：<a href="http://www.codeproject.com/KB/threads/StackWalker.aspx"><span>http://www.codeproject.com/KB/threads/StackWalker.aspx</span></a></span>。</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 不过对于<span>Release版本来说，StackWalk64函数获得的堆栈信息有可能不完整。如果异常是由MFC的模块抛出，那么获得的堆栈可能缺少前面调用模块信息。另外，StackWalk64需要最新的dbghelp.dll文件支持才能工作；要正确输出crash的函数名和行号，需要要pdb文件支持。以上不足有可能影响输出信息的完整性和效果，而对于发布在外的程序，要带上pdb文件几乎不可能，因此这个方案还是有缺憾的，比较适用于本地的release版本调试。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 下一篇我们将介绍一个更加完善的解决方案</p> <p>当我们把自己的<span>release版本程序发布出去以后，一般都是在用户的机器上运行。这种情况下，对于第四种方案，因为需要pdb文件才能够正确生成堆栈调用的函数行号及代码行号，因此方案四只适用于本地release版的调试，否则只能生成不完整的堆栈信息。对于前三种方案，其实只需要用户告知崩溃地址，然后在本地查找crash地址就可以了，但是定位crash的过程非常不方便，如果crash的情况比较多，前三种方案都不合适。而且，前三种方案均不能生成堆栈调用信息，对于debug的作用有限。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 下面我们就来看一个更加完善的解决方案。</p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>方案五：<span>SetUnhandledExceptionFil<wbr><wbr>ter + Minidump</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> SetUnhandleExceptionFilt<wbr>er函数我们已经介绍过了，本方案的思路还是要利用我们自己的异常处理函数，来生成<span>minidump文件。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>1</span></strong><strong>、<span>Minidump概念</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> minidump（小存储器转储）可以理解为一个<span>dump文件，里面记录了能够帮助调试crash的最小有用信息。实际上，如果你在 系统属性 -&gt; 高级 -&gt; 启动和故障恢复 -&gt; 设置 -&gt; 写入调试信息 中选择&#8220;小内存转储(64 KB)&#8221;的话，当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件，这个文件就是minidump文件，只不过这个是内核态的minidump。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>我们要生成的是用户态的<span>minidump，文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性，dump文件是压缩过的。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>2</span></strong><strong>、生成<span>minidump文件</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 生成<span>minidump文件的API函数是MiniDumpWriteDump，该函数需要dbghelp.lib支持，其原型如下:</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> BOOL WINAPI MiniDumpWriteDump(<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> HANDLE <em>hProcess</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> DWORD <em>ProcessId</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> HANDLE <em>hFile</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> MINIDUMP_TYPE <em>DumpType</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PMINIDUMP_EXCEPTION_INFORMATION <em>ExceptionParam</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PMINIDUMP_USER_STREAM_INFORMATION <em>UserStreamParam</em>,<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> __in <wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PMINIDUMP_CALLBACK_INFORMATION <em>CallbackParam</em><br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 在我们的异常处理函数中加入以下代码：</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> HANDLE hFile = ::CreateFile( _T("E:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> if( hFile != INVALID_HANDLE_VALUE)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> {<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> MINIDUMP_EXCEPTION_INFORMATION einfo;<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> einfo.ThreadId = ::GetCurrentThreadId();<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> einfo.ExceptionPointers = pExInfo;<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> einfo.ClientPointers = FALSE;</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, &amp;einfo, NULL, NULL);<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ::CloseHandle(hFile);<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 其中，<span>pExInfo变量为异常处理函数PEXCEPTION_POINTERS类型的参数。具体请参考MSDN。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>3</span></strong><strong>、调试<span>minidump</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>调试<span>dump文件首先需要pdb文件，因此我们build程序时需要设置 Debug Infomation Format 为 &#8220;Program Database（/Zi）&#8221;。其次，我们还要确保所用的dump文件与源代码、exe、pdb文件版本是一致的，这要求我们必须维护好程序版本信息。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 调试<span>minidump最方便的环境就是VS了，我们只要将.dmp、.exe、.pdb文件放在一个路径下，保证源代码文件的路径与编译时的路径一致就可以了，剩下的就是VS帮我们完成。双击.dmp文件或者在文件打开工程中选择&#8220;dump files&#8221;，加载dump文件，然后按F5运行就能直接恢复crash时的现场了，你可以定位crash的代码，可以查看调用堆栈，可以查看线程和模块信息...一切都跟你设置断点调试一样，太强大了！看个截图吧。</span></p> <p><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=48f93b530100g282&amp;url=http://s16.sinaimg.cn/orignal/48f93b53g7b0e4eff189f&amp;690" target="_blank"><span><span><img title="clip_image012" alt="clip_image012" src="../../images/cppblog_com/woaidongmao/WindowsLiveWriter/ReleaseCrash_A881/clip_image012_3df8e4ef-d0e8-49d3-a9af-47f58cc713c6.jpg" height="469" width="616" border="0" /></span></span></a></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 需要注意的是，对于<span>release版的程序来说，很多代码是经过编译器优化过的，因此定位的时候可能会有所偏差，大家可以考虑设置选项去掉代码优化。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 其他可以调试<span>minidump的工具还有WinDbg等，大家可以查阅相关资料。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 本文主要参考了这篇文章：<span><a href="http://vicchina.51.net/research/other/seh/minidumps/intro.htm"><span>http://vicchina.51.net/research/other/seh/minidumps/intro.htm</span></a></span>。</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 下一篇，我们将给出一个调试<span>release发布程序的完美解决方案，适合用户量较大的应用发布程序的调试。</span></p> <p>上一篇我们已经给出了方案，能够非常方便的通过<span>dump文件对crash错误进行调试和定位；从整个流程上看还差最后一步，即怎样拿到crash时产生的dump文件。如果可以让用户把文件发送过来自然不错，但对于类似免费共享软件等在互联网上发布的程序呢？我们的用户是不确定的，而且用户量有可能非常大，即使我们能想办法联系到用户，总不能挨个去收集crash信息吧。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 我们需要一种方案，能够提供<span>crash信息汇报功能。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 我们可以架设一台服务器专门进行信息收集，只要客户端在<span>crash时正确汇报即可，但是相应的维护成本和开发难度也不可忽视。有没有更简单的方法呢？还记得我的博文&#8220;<a href="http://blog.sina.com.cn/s/blog_48f93b530100esmg.html" target="_blank"><span><span>为程序添加自动发送Email</span><span>功能</span></span></a>&#8221;</span>吗？这就是简单有效的方法！</p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong>方案六：<span>minidump + email</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 我们只需要在异常处理时，先生成<span>minidump信息文件，再用email方式将文件发送到指定邮箱就行了。剩下的就是我们每天查看邮箱，提取dump文件进行调试了。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>1</span></strong><strong>、<span>Email功能</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 首先我们来看一下<span>email发送都需要哪些相关信息。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> a、发送端邮箱帐户；</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> b、接收端邮箱帐户；</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> c、<span>email标题，一般应有软件名称及版本信息；</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> d、<span>email正文，一般应有简单的crash信息提示，以区别不同原因造成的crash；</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>e、<span>email附件，当然就是我们的dump文件了，还可以加上软件生成的log文件等。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 当然，对于标题应该尽量多加一些信息区别引起<span>crash的原因，比如将crash的地址信息加到标题中；因为当每天有成百上千的crash汇报上来，重复的crash占大多数，把时间都花在区分它们身上有点太浪费。由此看来，前面方案中提到的StackWalker还是有些用处的，我们可以用它来生成一些crash的文字描述信息，写到标题或正文中去。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dump文件的大小是否适合作为邮件的附件呢？实际上<span>minidump产生的文件一般在几K到几十K之间，作为email的附件没有任何问题。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 关于发送<span>email相关技术细节，已经在&#8220;<a href="http://blog.sina.com.cn/s/blog_48f93b530100esmg.html" target="_blank"><span><span>为程序添加自动发送Email</span><span>功能</span></span></a>&#8221;</span>文中介绍了，大家可以参考。其实，对接受邮箱中邮件的处理还是很费时费力的，大家可以考虑写一些脚本将处理流程自动化，提高效率。</p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <strong><span>2</span></strong><strong>、<span>google breakpad</span></strong></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> google breakpad是一个开源的跨平台<span>crash report系统，光从开源和跨平台这两个特点上来看，它就足以称的上是一个完善而有效的工具了。其实，breakpad在整个crash report层次上给出了一个系统级的解决方案，也就是说它几乎能适应各种软件、各种平台的应用要求。</span></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> breakpad的整体思路跟上面介绍的方案是相似的，只不过最后提交<span>dump文件的方式更加完善。大家有兴趣可以去它的官方网址查阅相关资料：<a href="http://code.google.com/p/google-breakpad/"><span>http://code.google.com/p/google-breakpad/</span></a></span>。</p> <p>&nbsp;<wbr></p> <p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ok，关于调试<span>release发布程序的crash错误系列文章就写完了。这几篇文章给出的方案由简单到复杂，由简陋到完善，对crash调试有了一个比较全面的总结。当然，其中涉及到的概念和技术还很多，需要我们去不断学习和领悟，也希望大家能够互相交流。</span></p> </div>  		</div></div><img src ="http://www.cppblog.com/lauer3912/aggbug/159781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-11-07 21:15 <a href="http://www.cppblog.com/lauer3912/archive/2011/11/07/159781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Test Primer ：开始使用Google C++ 测试框架</title><link>http://www.cppblog.com/lauer3912/archive/2011/09/16/155965.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Fri, 16 Sep 2011 13:59:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/09/16/155965.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/155965.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/09/16/155965.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/155965.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/155965.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://ray-leex.iteye.com/blog/212024Google C++ Testing Framework Primer&nbsp;翻译：Ray Li&nbsp;(ray.leex@gmail.com)&nbsp;修改日期：2008年7月6日原文参见：http://code.google.com/p/googletest/wiki/GoogleTestPrimer&nbsp...&nbsp;&nbsp;<a href='http://www.cppblog.com/lauer3912/archive/2011/09/16/155965.html'>阅读全文</a><img src ="http://www.cppblog.com/lauer3912/aggbug/155965.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-09-16 21:59 <a href="http://www.cppblog.com/lauer3912/archive/2011/09/16/155965.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC编译Swig例子注意</title><link>http://www.cppblog.com/lauer3912/archive/2011/09/02/154978.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Fri, 02 Sep 2011 15:58:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/09/02/154978.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/154978.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/09/02/154978.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/154978.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/154978.html</trackback:ping><description><![CDATA[<div><div>使用VC编译程序示例源码的时候，碰到一些变量，这些变量需要说明一下。</div><div><strong>$(PYTHON_INCLUDE)</strong></div><div><strong>$(PYTHON_LIB)</strong></div><div></div><div>一般，在WIndows或者Linux上设置PYTHON_INCLUDE、PYTHON_LIB的变量就可以。如Windows的环境变量设置</div><div><strong>PYTHON_INCLUDE=C:\Python27\include</strong></div><div><strong>PYTHON_LIB=C:\Python27\libs\python27.lib</strong></div></div><img src ="http://www.cppblog.com/lauer3912/aggbug/154978.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-09-02 23:58 <a href="http://www.cppblog.com/lauer3912/archive/2011/09/02/154978.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从dll文件或者def文件生成lib文件</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/18/153698.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Wed, 17 Aug 2011 16:02:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/18/153698.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/153698.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/18/153698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/153698.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/153698.html</trackback:ping><description><![CDATA[<a href="http://www.cnblogs.com/mxly/archive/2011/04/01/2002438.html">http://www.cnblogs.com/mxly/archive/2011/04/01/2002438.html<br /><span style="color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; font-size: 14px; line-height: 21px; background-color: #faf7ef; "><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">1、dll导出def文件。使用vs2005开发工具中自带的命令dumpbin，如下图所示</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a href="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011741484118.png" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #6466b3; text-decoration: underline; "><img title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011741533307.png" width="570" height="449" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; border-bottom-style: initial; border-bottom-color: initial; border-left-style: initial; border-left-color: initial; display: inline; border-top-style: initial; border-top-color: initial; border-right-style: initial; border-right-color: initial; " /></a></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">具体命令如下</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a href="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011741568898.png" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #6466b3; text-decoration: underline; "><img title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011741576225.png" width="577" height="74" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; border-bottom-style: initial; border-bottom-color: initial; border-left-style: initial; border-left-color: initial; display: inline; border-top-style: initial; border-top-color: initial; border-right-style: initial; border-right-color: initial; " /></a></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">这样就能在指定目录生成def文件了</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">2、def文件生成lib文件。使用vs2005开发工具中自带的命令lib，如下图所示</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a href="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011742022349.png" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #6466b3; text-decoration: underline; "><img title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011742081722.png" width="581" height="420" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; border-bottom-style: initial; border-bottom-color: initial; border-left-style: initial; border-left-color: initial; display: inline; border-top-style: initial; border-top-color: initial; border-right-style: initial; border-right-color: initial; " /></a></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">具体命令如下</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a href="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011742106540.png" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #4c4f8b; text-decoration: underline; "><img title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/mxly/201104/201104011742113900.png" width="582" height="137" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; border-bottom-style: initial; border-bottom-color: initial; border-left-style: initial; border-left-color: initial; display: inline; border-top-style: initial; border-top-color: initial; border-right-style: initial; border-right-color: initial; " /></a></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">这样就能在指定目录生成lib文件了</p></span></a><img src ="http://www.cppblog.com/lauer3912/aggbug/153698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-18 00:02 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/18/153698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC调试器高级应用----高级断点篇</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/12/153240.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Fri, 12 Aug 2011 15:37:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/12/153240.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/153240.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/12/153240.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/153240.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/153240.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="color: #333333; font-family: Arial; background-color: #ffffff; "><strong><span lang="EN-US" style="font-size: 12pt; color: #000099; line-height: 24px; font-family: 宋体; ">VC</span></strong><strong><span style="font-size: 12pt; color: #000099; line-height: 24px; font-family: 宋体; ">调试器高级应用<span lang="EN-US">----</span>高级断点篇<br /></span></strong></span><span class="Apple-style-span" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; "><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">VC</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">调试器高级应用<span lang="EN-US">----</span>高级断点篇</span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">一<span lang="EN-US">.</span>高级断点语法<span lang="EN-US">&nbsp;&nbsp;<br />&nbsp;<br /></span>高级断点语法由两部分组成<span lang="EN-US">:1.</span>上下文部分<span lang="EN-US">.2.</span>位置<span lang="EN-US">,</span>表达式<span lang="EN-US">,</span>变量或<span lang="EN-US">Windows</span>消息条件<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">用函数<span lang="EN-US">,</span>源文件和二进制模块来指定上下文<span lang="EN-US">,</span>上下文的表示方法<span lang="EN-US">:&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">{[</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">函数<span lang="EN-US">],[</span>源文件<span lang="EN-US">],[</span>二进制模块<span lang="EN-US">]}&nbsp;&nbsp;&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">必须指定唯一的<span lang="EN-US">,</span>足够的上下文信息才能获取断点位置<span lang="EN-US">.</span>如在<span lang="EN-US">TEST.CPP</span>的<span lang="EN-US">20</span>行设一位置断点<span lang="EN-US">,</span>语法为<span lang="EN-US">:{,TEST.CPP,}.20,</span>如<span lang="EN-US">A.DLL</span>或<span lang="EN-US">B.DLL</span>都使用了该行<span lang="EN-US">,</span>又只想在<span lang="EN-US">B.DLL</span>的调用中触发<span lang="EN-US">,</span>则必须使用<span lang="EN-US">:{,TEST.CPP,B.DLL}.20.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">VC</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">调试器中可直接输入上下文语法<span lang="EN-US">:Breakpoints</span>对话框的<span lang="EN-US">Location</span>选项卡<span lang="EN-US">BreakAt</span>编辑框中<span lang="EN-US">.</span>更容易的方法是使用<span lang="EN-US">BreatAt</span>框右的箭头打开菜单<span lang="EN-US">,</span>选择<span lang="EN-US">Advanced</span>项<span lang="EN-US">,</span>然后在<span lang="EN-US">Context</span>框中输入断点的相应信息<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">如想在一个绝对地址上中断<span lang="EN-US">,</span>直接在<span lang="EN-US">BreakAt</span>框中输入地址就行<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">二<span lang="EN-US">.</span>任何函数上快速中断<span lang="EN-US">&nbsp;&nbsp;<br />&nbsp;<br /></span>将函数名输入<span lang="EN-US">BreadAt</span>框中<span lang="EN-US">.</span>如果是<span lang="EN-US">C++</span>代码<span lang="EN-US">,</span>同时还需要类限定符<span lang="EN-US">.</span>支持重载了的函数<span lang="EN-US">,</span>调试器会列出所有满足条件的函数供选择<span lang="EN-US">,</span>如输入时提供足够的信息<span lang="EN-US">,</span>完全可略过选择过程<span lang="EN-US">.</span>如输入<span lang="EN-US">:"CString::operator=(const&nbsp; char&nbsp; *)"</span>可唯一确定要中断的函数<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br /></span>三<span lang="EN-US">.</span>在系统或<span lang="EN-US">DLL</span>输出的函数中设置断点<span lang="EN-US">&nbsp;&nbsp;<br />&nbsp;<br /></span>在程序中从<span lang="EN-US">DLL</span>输入的函数中设置一个断点可能是毫无作用的<span lang="EN-US">,</span>调试器需要知道在何处可以找到该函数上下文信息<span lang="EN-US">,</span>同时<span lang="EN-US">,</span>函数名取决于是否加载了<span lang="EN-US">DLL</span>的符号<span lang="EN-US">.</span>只有在<span lang="EN-US">W2K</span>以上版本中才能在系统<span lang="EN-US">DLL</span>中设置断点<span lang="EN-US">--</span>原因在于其它系统没有提供边写入边复制保护的功能<span lang="EN-US">,</span>若一定要启用这种方法<span lang="EN-US">,</span>必须要有<span lang="EN-US">COFF(Common&nbsp; Object&nbsp; File&nbsp; Format),</span>并在调试器中输出启动的装载<span lang="EN-US">----</span>在<span lang="EN-US">Options</span>对话框的<span lang="EN-US">Debug</span>页<span lang="EN-US">,</span>将<span lang="EN-US">Load&nbsp; COFF&nbsp; &amp;&nbsp; Exports</span>选中<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">VC</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">调试器用分级的符号信息法<span lang="EN-US">,</span>完整的符号的级别高于不太完整的<span lang="EN-US">.PDB(Program&nbsp; Database)</span>文件具有所有可能的源码行<span lang="EN-US">,</span>函数<span lang="EN-US">,</span>变量和类型信息<span lang="EN-US">,</span>优先级便高于<span lang="EN-US">COFF/DBG</span>文件<span lang="EN-US">,</span>后者只有公用函数符号<span lang="EN-US">,</span>而<span lang="EN-US">COFF/DBG</span>文件高于输出名称<span lang="EN-US">,</span>输入的名称是一种伪符号<span lang="EN-US">.&nbsp;&nbsp;<br /></span>调试时<span lang="EN-US">,</span>如<span lang="EN-US">DEBUG</span>窗口输出<span lang="EN-US">:</span>装载<span lang="EN-US">DLL</span>的符号<span lang="EN-US">,</span>则说明符号已被装入<span lang="EN-US">;</span>否则说明没有装载<span lang="EN-US">DLL</span>的符号<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">没有装入符号时<span lang="EN-US">,</span>使用的位置字符串是<span lang="EN-US">DLL</span>输出的名称<span lang="EN-US">,</span>可能用<span lang="EN-US">DUMPBIN</span>程序查看这个名称<span lang="EN-US">:DUMPBIN&nbsp; /EXPORTS&nbsp; DLLname.</span>例<span lang="EN-US">:</span>在<span lang="EN-US">LoadLibraryA</span>中设置中断<span lang="EN-US">:"{,,Kernel32.dll}LoadLibraryA".&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">如装入了符号<span lang="EN-US">,</span>则要根据输出函数和调用协议来计算函数名<span lang="EN-US">.</span>如上例<span lang="EN-US">,LoadLibraryA</span>使用<span lang="EN-US">__stdcall</span>调用协议<span lang="EN-US">,</span>据该协议<span lang="EN-US">,</span>函数名以下划线为前缀<span lang="EN-US">,</span>所跟有进栈的字节数为后缀的<span lang="EN-US">@</span>号<span lang="EN-US">.</span>一般说来<span lang="EN-US">,</span>参数个数<span lang="EN-US">*4,</span>就是参数占用栈空间的总字节数<span lang="EN-US">,LoadLibary</span>的名称便是<span lang="EN-US">:_LoadLibraryA@4,</span>故最后的语法是<span lang="EN-US">:</span>或<span lang="EN-US">"{,,Kernel32.dll}_LoadLibraryA@4"&nbsp;&nbsp;<br />&nbsp;<br /></span>附<span lang="EN-US">:</span>常用的调用协议<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp; 1</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">、<span lang="EN-US">__stdcall</span>调用约定相当于<span lang="EN-US">16</span>位动态库中经常使用的<span lang="EN-US">PASCAL</span>调用约定。在<span lang="EN-US">32</span>位的<span lang="EN-US">VC++5.0</span>中<span lang="EN-US">PASCAL</span>调用约定不再被支持（实际上它已被定义为<span lang="EN-US">__stdcall</span>。除了<span lang="EN-US">__pascal</span>外，<span lang="EN-US">__fortran</span>和<span lang="EN-US">__syscall</span>也不被支持），取而代之的是<span lang="EN-US">__stdcall</span>调用约定。两者实质上是一致的，即函数的参数自右向左通过栈传递，被调用的函数在返回前清理传送参数的内存栈，但不同的是函数名的修饰部分（关于函数名的修饰部分在后面将详细说明）。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _stdcall</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">是<span lang="EN-US">Pascal</span>程序的缺省调用方式，通常用于<span lang="EN-US">Win32&nbsp; Api</span>中，函数采用从右到左的压栈方式，自己在退出时清空堆栈。<span lang="EN-US">VC</span>将函数编译后会在函数名前面加上下划线前缀，在函数名后加上<span lang="EN-US">"@"</span>和参数的字节数。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">、<span lang="EN-US">C</span>调用约定（即用<span lang="EN-US">__cdecl</span>关键字说明）按从右至左的顺序压参数入栈，由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的（正因为如此，实现可变参数的函数只能使用该调用约定）。另外，在函数名修饰约定方面也有所不同。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _cdecl</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">是<span lang="EN-US">C</span>和<span lang="EN-US">C</span>＋＋程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码，所以产生的可执行文件大小会比调用<span lang="EN-US">_stdcall</span>函数的大。函数采用从右到左的压栈方式。<span lang="EN-US">VC</span>将函数编译后会在函数名前面加上下划线前缀。是<span lang="EN-US">MFC</span>缺省调用约定。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">3</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">、<span lang="EN-US">__fastcall</span>调用约定是<span lang="EN-US">&#8220;</span>人<span lang="EN-US">&#8221;</span>如其名，它的主要特点就是快，因为它是通过寄存器来传送参数的（实际上，它用<span lang="EN-US">ECX</span>和<span lang="EN-US">EDX</span>传送前两个双字（<span lang="EN-US">DWORD</span>）或更小的参数，剩下的参数仍旧自右向左压栈传送，被调用的函数在返回前清理传送参数的内存栈），在函数名修饰约定方面，它和前两者均不同。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _fastcall</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">方式的函数采用寄存器传递参数，<span lang="EN-US">VC</span>将函数编译后会在函数名前面加上<span lang="EN-US">"@"</span>前缀，在函数名后加上<span lang="EN-US">"@"</span>和参数的字节数。<span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">、<span lang="EN-US">thiscall</span>仅仅应用于<span lang="EN-US">&#8220;C++&#8221;</span>成员函数。<span lang="EN-US">this</span>指针存放于<span lang="EN-US">CX</span>寄存器，参数从右到左压。<span lang="EN-US">thiscall</span>不是关键词，因此不能被程序员指定。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">、<span lang="EN-US">naked&nbsp; call</span>采用<span lang="EN-US">1-4</span>的调用约定时，如果必要的话，进入函数时编译器会产生代码来保存<span lang="EN-US">ESI</span>，<span lang="EN-US">EDI</span>，<span lang="EN-US">EBX</span>，<span lang="EN-US">EBP</span>寄存器，退出函数时则产生代码恢复这些寄存器的内容。<span lang="EN-US">naked&nbsp; call</span>不产生这样的代码。<span lang="EN-US">naked&nbsp; call</span>不是类型修饰符，故必须和<span lang="EN-US">_declspec</span>共同使用。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">关键字<span lang="EN-US">&nbsp; __stdcall</span>、<span lang="EN-US">__cdecl</span>和<span lang="EN-US">__fastcall</span>可以直接加在要输出的函数前，也可以在编译环境的<span lang="EN-US">Setting...C/C++&nbsp; Code&nbsp; Generation</span>项选择。当加在输出函数前的关键字与编译环境中的选择不同时，直接加在输出函数前的关键字有效。它们对应的命令行参数分别为<span lang="EN-US">/Gz</span>、<span lang="EN-US">/Gd</span>和<span lang="EN-US">/Gr</span>。缺省状态为<span lang="EN-US">/Gd</span>，即<span lang="EN-US">__cdecl</span>。<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">要完全模仿<span lang="EN-US">PASCAL</span>调用约定首先必须使用<span lang="EN-US">__stdcall</span>调用约定，至于函数名修饰约定，可以通过其它方法模仿。还有一个值得一提的是<span lang="EN-US">WINAPI</span>宏，<span lang="EN-US">Windows.h</span>支持该宏，它可以将出函数翻译成适当的调用约定，在<span lang="EN-US">WIN32</span>中，它被定义为<span lang="EN-US">__stdcall</span>。使用<span lang="EN-US">WINAPI</span>宏可以创建自己的<span lang="EN-US">APIs</span>。<span lang="EN-US">&nbsp;&nbsp;<br />&nbsp;<br /></span>四<span lang="EN-US">.</span>位置断点修饰符<span lang="EN-US">&nbsp;&nbsp;<br />&nbsp;<br />1.</span>跳跃计数<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">功能是执行断点但不在断点处停止<span lang="EN-US">,</span>直到执行完了一个特定的次数为止<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">使用中首先设置一个标准的位置断点<span lang="EN-US">,</span>打开<span lang="EN-US">BreadPoint</span>对话框<span lang="EN-US">,</span>选中该断点<span lang="EN-US">,</span>单击<span lang="EN-US">Condition,</span>然后在弹出的对话框最下面的编辑控件中输入次数<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">只有当程序全速运行时<span lang="EN-US">,</span>未执行的循环次数才有用<span lang="EN-US">.</span>单步执行跨过断点时不会更新跳跃计数<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">例<span lang="EN-US">:</span>已知循环可能崩溃<span lang="EN-US">,</span>但不清楚在哪次循环时<span lang="EN-US">,</span>输入远远大于总循环次数的跳跃计数修饰符<span lang="EN-US">,</span>则在崩溃时可打开<span lang="EN-US">Breakpoint</span>框<span lang="EN-US">,</span>其中将列出还未执行的循环次数<span lang="EN-US">,</span>与总次数相减就可得已执行的次数<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br />2.</span>条件表达式<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">只有表达式为真时触发<span lang="EN-US">.Breakpoint</span>框<span lang="EN-US">Condition</span>按钮<span lang="EN-US">,</span>选第一个编辑框<span lang="EN-US">,</span>输入表达式即可<span lang="EN-US">.</span>规则<span lang="EN-US">:&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">.</span><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">只可使用<span lang="EN-US">C</span>类型比较运算符<span lang="EN-US">.&nbsp;&nbsp;<br />.</span>表达式中不能调用任何函数<span lang="EN-US">.&nbsp;&nbsp;<br />.</span>表达式中不能包含任何宏值<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">表达式为<span lang="EN-US">@TIB=Thread&nbsp; Infomation&nbsp; Block&nbsp; Linear&nbsp; Address,</span>则程序只在该特定线程中才会中断<span lang="EN-US">.</span>例<span lang="EN-US">:</span>线程<span lang="EN-US">@TIB</span>地址值为<span lang="EN-US">0E000,</span>则输入<span lang="EN-US">"@TIB==0xE000",</span>则在切换到该线程时中断<span lang="EN-US">.</span>对<span lang="EN-US">W98,</span>可用<span lang="EN-US">@FS=thread&nbsp; specific&nbsp; value.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">如在某特定错误后中断<span lang="EN-US">,</span>则可用<span lang="EN-US">@ERR,</span>如<span lang="EN-US">"@ERR=2"</span>表示在最后错误为<span lang="EN-US">ERROR_FILE_NOT_FOUND.</span>除<span lang="EN-US">@CLK</span>外<span lang="EN-US">,</span>所有可在<span lang="EN-US">WATCH</span>窗口中使用的伪寄存器均可用于条件表达式<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br /></span>条件表达式可与跳跃断点组合使用<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br />3.</span>变量更改<span lang="EN-US">&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">在变量更改时中断程序<span lang="EN-US">.</span>只有当位置断点执行时才能检查变量<span lang="EN-US">.</span>常用用调用栈高层的函数中发现出错<span lang="EN-US">,</span>需要深入调用栈<span lang="EN-US">,</span>压缩范围找出根源时<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">添加时在<span lang="EN-US">Breakpoint</span>框第一个编辑框中输入变量名<span lang="EN-US">(</span>可以是指针指向听对象<span lang="EN-US">:*p),</span>在第二个编辑框中输入要查看的项目数量<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br /></span>五<span lang="EN-US">.</span>全局表达式和条件断点<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br /></span>调试器可监控某一地址和该地址上的<span lang="EN-US">1,2</span>或<span lang="EN-US">4</span>字节的内容<span lang="EN-US">.</span>如可用硬件调试寄存器<span lang="EN-US">,</span>则不影响速度<span lang="EN-US">;</span>否则程序将单步执行<span lang="EN-US">ASM</span>指令并在每一步中检查条件<span lang="EN-US">,</span>这将严重影响程序运行速度<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">总共有<span lang="EN-US">4</span>个调试寄存器<span lang="EN-US">.</span>硬件调试寄存器不能处理超过<span lang="EN-US">1</span>个双字长的引用<span lang="EN-US">.</span>确保利用硬件调试寄存器的最好方法是使用表达式和数据更改位置的实际地址值<span lang="EN-US">.</span>例如<span lang="EN-US">:g_szGlobal</span>是全局数组指针<span lang="EN-US">,</span>地址为<span lang="EN-US">0x5000,</span>则在<span lang="EN-US">Breakpoint</span>对话框中<span lang="EN-US">DATA</span>选项卡中将表达式断点设为<span lang="EN-US">"*(char*))0x5000=='G'",</span>但如果写为<span lang="EN-US">"WO(0x5000)=='G',</span>则用不到硬件调试寄存器<span lang="EN-US">,</span>会单步执行每条指令<span lang="EN-US">.&nbsp;</span></span></p><p class="MsoNormal" align="left" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; line-height: 21px; text-align: left; "><span style="font-size: 12pt; color: black; line-height: 24px; font-family: 宋体; ">与全局表达式断点类似<span lang="EN-US">,</span>使用变量的<span lang="EN-US">16</span>进制地址给定长指针计算地址<span lang="EN-US">,</span>并将要查看的单元数设为<span lang="EN-US">1,</span>则全局变量断点可发挥最付佳功效<span lang="EN-US">.</span>如上例要在变量改动时中断<span lang="EN-US">,</span>则输入<span lang="EN-US">:"*(long*)0x5000".&nbsp;&nbsp;<br />&nbsp;<br /></span>六<span lang="EN-US">.WINDOWS</span>消息断点<span lang="EN-US">.&nbsp;&nbsp;<br />&nbsp;<br />Breakpoint</span>框的<span lang="EN-US">Message</span>页<span lang="EN-US">.</span>需要指定一个窗口过程<span lang="EN-US">,</span>注意<span lang="EN-US">:MFC</span>世界中<span lang="EN-US">AfxWndProc</span>是多数窗口的一个窗口过程<span lang="EN-US">,</span>所以总会在该断</span></p></span><img src ="http://www.cppblog.com/lauer3912/aggbug/153240.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-12 23:37 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/12/153240.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Qt的插件机制</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/10/152914.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 09 Aug 2011 23:34:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/10/152914.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/152914.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/10/152914.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/152914.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/152914.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://yanboo.ycool.com/post.2749491.html(来自Qt文档)Qt有两种与插件有关的API。一种用来扩展Qt本身的功能，如自定义数据库驱动，图像格式，文本编解码，自定义分格，等等，称为Higher-Level API。另一种用于应用程序的功能扩展，称为Lower-Level API。前一种是建立在后一种的基础之上的。这里讨论的是后一种，即用来扩展应用程序的Low...&nbsp;&nbsp;<a href='http://www.cppblog.com/lauer3912/archive/2011/08/10/152914.html'>阅读全文</a><img src ="http://www.cppblog.com/lauer3912/aggbug/152914.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-10 07:34 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/10/152914.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ const 用法</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/10/152913.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 09 Aug 2011 23:25:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/10/152913.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/152913.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/10/152913.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/152913.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/152913.html</trackback:ping><description><![CDATA[<div><a href="http://www.diybl.com/course/3_program/c++/cppjs/20091022/179910.html">http://www.diybl.com/course/3_program/c++/cppjs/20091022/179910.html<br /><br /><span class="Apple-style-span" style="color: #383838; font-family: Arial, Helvetica, sans-serif; line-height: 24px; -webkit-text-decorations-in-effect: none; "><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">1. const修饰普通变量和指针</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const修饰变量，一般有两种写法：</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const TYPE value;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">TYPE const value;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">这两种写法在本质上是一样的。它的含义是：const修饰的类型为TYPE的变量value是不可变的。</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">对于一个非指针的类型TYPE，无论怎么写，都是一个含义，即value只不可变。</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">例如：</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const int nValue；&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //nValue是const</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">int const nValue；&nbsp;&nbsp;&nbsp; // nValue是const</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">但是对于指针类型的TYPE，不同的写法会有不同情况，例如：</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">A. const char *pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">B. char * const pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">C. char const *pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">D. const char* const pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">对于前三种写法，我们可以换个方式，给其加上括号</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">A. const (char) *pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">B. (char*) const pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">C. (char) const *pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">这样就一目了然。根据对于const修饰非指针变量的规则，很明显，A=C.</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">- 对于A,C, const修饰的类型为char的变量*pContent为常量，因此，pContent的内容为常量不可变.</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">- 对于B, 其实还有一种写法： const (char*) pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">含义为：const修饰的类型为char*的变量pContent为常量，因此，pContent指针本身为常量不可变.</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">- 对于D, 其实是A和B的混合体，表示指针本身和指针内容两者皆为常量不可变</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">总结:</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">(1)&nbsp; 指针本身是常量不可变</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">(char*) const pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const (char*) pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">(2)&nbsp; 指针所指向的内容是常量不可变</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const (char) *pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">(char) const *pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">(3)&nbsp; 两者都不可变</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const char* const pContent;</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">还有其中区别方法：</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">沿着*号划一条线，</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">如果const位于*的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；</font></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">如果const位于*的右侧，const就是修饰指针本身，即指针本身是常量。&nbsp;</font><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />2. const修饰函数参数</font></p><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const修饰函数参数是它最广泛的一种用途，它表示函数体中不能修改参数的值(包括参数本身的值或者参数其中包含的值)。它可以很好&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />void function(const int Var); //传递过来的参数在函数内不可以改变(无意义，因为Var本身就是形参)</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">void function(const char* Var); //参数指针所指内容为常量不可变</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">void function(char* const Var); //参数指针本身为常量不可变(也无意义， 因为char* Var也是形参)</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">参数为引用，为了增加效率同时防止修改。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">修饰引用参数时：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">void function(const Class&amp; Var);//引用参数在函数内不可以改变</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">void function(const TYPE&amp; Var); //引用参数在函数内为常量不可变</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">3. const 修饰函数返回值</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const修饰函数返回值其实用的并不是很多，它的含义和const修饰普通变量以及指针的含义基本相同。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">(1) const int fun1() 这个其实无意义，因为参数返回本身就是赋值。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">(2) const int * fun2()</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">调用时 const int *pValue = fun2();</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">我们可以把fun2()看作成一个变量，那么就是我们上面所说的1.(1)的写法，即指针内容不可变。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">(3) int* const fun3()</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">调用时 int * const pValue = fun2();</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">我们可以把fun2()看作成一个变量，那么就是我们上面所说的1.(2)的写法，即指针本身不可变。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">4. const修饰类对象/对象指针/对象引用</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const修饰类对象表示该对象为常量对象，其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const修饰的对象，该对象的任何非const成员函数都不能被调用，因为任何非const成员函数会有修改成员变量的企图。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">例如：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">class AAA</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">{<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />&nbsp;&nbsp; void func1();</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">void func2() const;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">}</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const AAA aObj;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">aObj.func1(); &#215;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">aObj.func2(); 正确</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const AAA* aObj = new AAA();</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">aObj-&gt;func1(); &#215;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">aObj-&gt;func2(); 正确&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />5. const修饰成员变量</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const修饰类的成员函数，表示成员常量，不能被修改，同时它只能在初始化列表中赋值。&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />class A</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">{</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">&nbsp;&nbsp; &#8230;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">&nbsp;&nbsp; const int nValue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //成员常量不能被修改</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">&nbsp;&nbsp; &#8230;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">&nbsp;&nbsp; A(int x): nValue(x) {}; //只能在初始化列表中赋值</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">}&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />6. const修饰成员函数</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const修饰类的成员函数，则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />class A</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">{</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">&nbsp;&nbsp; &#8230;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">void function()const; //常成员函数, 它不改变对象的成员变量. 也不能调用类中任何非const成员函数。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">}</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">对于const类对象/指针/引用，只能调用类的const成员函数，因此，const修饰成员函数的最重要作用就是限制对于const对象的使用。&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />7. const常量与define宏定义的区别</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">(1) 编译器处理方式不同</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">define宏是在预处理阶段展开。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const常量是编译运行阶段使用。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">(2) 类型和安全检查不同</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">define宏没有类型，不做任何类型检查，仅仅是展开。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">const常量有具体的类型，在编译阶段会执行类型检查。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">(3) 存储方式不同</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; ">define宏仅仅是展开，有多少地方使用，就展开多少次，不会分配内存。</p></font><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 24px; color: #383838; font-size: 14px; "><font face="Verdana" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">const常量会在内存中分配(可以是堆中也可以是栈中)。</font></p></span><br /></a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/152913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-10 07:25 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/10/152913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DLL导出类的问题</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/10/152912.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 09 Aug 2011 23:23:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/10/152912.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/152912.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/10/152912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/152912.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/152912.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="color: #0c095a; font-family: 宋体; font-size: 24px; font-weight: bold; line-height: normal; white-space: nowrap; ">DLL导出类的问题<br /><br /></span><div><a href="http://www.diybl.com/course/3_program/c++/cppjs/200833/102641.html">http://www.diybl.com/course/3_program/c++/cppjs/200833/102641.html<br /><span class="Apple-style-span" style="color: #383838; font-family: Arial, Helvetica, sans-serif; line-height: 24px; -webkit-text-decorations-in-effect: none; ">DLL动态链接库是程序复用的重要方式，DLL可以导出函数，使函数被多个程序复用，DLL中的函数实现可以被修改而无需重新编译和连接使用该DLL的应用程序。作为一名面向对象的程序员，希望DLL可以导出类，以便在类的层次上实现复用。所幸的是，DLL确实也可以导出类。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />然而事实却没这么简单，导出类的DLL在维护和修改时有很多地方必需很小心，增加成员变量、修改导出类的基类等操作都可能导致意想不到的后果，也许<a class="qs_highlight1" id="hl_2" href="http://clk.qunsee.com/click/click.php?cpid=510&amp;ads_id=46&amp;pid=99000630&amp;cid=634&amp;url=http%3A//www.qunsee.com/sitepage.php&amp;k=%u7528%u6237&amp;s=http%3A//www.diybl.com/course/3_program/c++/cppsl/200819/96118.html&amp;rn=221948&amp;v=1&amp;ref=http%3A//www.diybl.com/course/3_program/c++/cppsl/200819/96118_2.html&amp;province=%u5E7F%u4E1C&amp;city=%u5E7F%u5DDE" target="_blank" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-size: 1em; ">用户</a>更新了最新版本的DLL库后，应用程序就再也不能<a class="qs_highlight1" id="hl_0" href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=227&amp;pid=99000630&amp;cid=634&amp;url=http%3A//www.chanet.com.cn/click.cgi%3Fa%3D59068%26d%3D21733%26u%3D%26e%3D&amp;k=%u5DE5%u4F5C&amp;s=http%3A//www.diybl.com/course/3_program/c++/cppsl/200819/96118.html&amp;rn=402195&amp;v=1&amp;ref=http%3A//www.diybl.com/course/3_program/c++/cppsl/200819/96118_2.html&amp;province=%u5E7F%u4E1C&amp;city=%u5E7F%u5DDE" target="_blank" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-size: 1em; ">工作</a>了。这就是著名的DLL Hell（DLL地狱）问题。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />DLL地狱问题是怎么产生的呢？看下面的例子，假设DLL有一个导出类ClassD1：<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />class ClassD<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />{<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public:</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />int GetInt();<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private:</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />int m_i;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />};<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />int ClassD::GetInt()<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />{<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_i;</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />}<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />应用程序使用现在的代码来使用这个类：<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />ClassD d;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />printf(&#8220;%d&#8221;, d.GetInt());<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />程序进行正正常，没有什么问题。后来DLL需要升级，对ClassD进行了修改，增加了一个成员变量，如下：<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />class ClassD // 修改后<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />{<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public:</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />int GetInt();<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private:</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int m_i2;</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />int m_i;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />};<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />把新的DLL编译连接完成后，复制到应用程序目录，这个倒楣的应用程序调用GetInt方法恐怕再也无法得正确的值了。事实上它还算幸运的，如果GetInt的实现改成如下这样，那么它马上就要出错退出了。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />int ClassD::GetInt() // 修改后<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />{<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_i++;</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />}<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />这样的事情，称它是个地狱（Hell）一点也不夸张。为什么会出错呢？我们要先从类实例的创建开始，看看使用一个类的工作过程。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />首先，程序语句&#8220;ClassD d；&#8221;为这个类申请一块内存。这块内存保存该类的所有成员变量，以及虚函数表。内存的大小由类的声明决定，在应用程序编译时就已经确定。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />然后，当调用&#8220;d.GetInt()&#8221;时，把申请的这一块内存做为this指针传给GetInt函数，GetInt函数从this指向的位置开始，加上m_i应有的偏移量，计算m_i所在的内存位置，并从该位置取数据返回。m_i相对this的偏移量是由m_i在类中定义的位置决定的，定义在前的成员变量在内存中也更靠前。这个偏移量在DLL编译时确定。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />当ClassD的定义改为修改后的状态时，有些东西变了。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />第一个变的是内存的大小。因为修改后的ClassD多了一个成员变量，所以内存也变大了。然而这一点应用程序并不知道。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />第二个变的是m_i的偏移地址。因为在m_i之前定义了一个m_i2，m_i的实现偏移地址实际已经靠后了。所以d.GetInt()访问的将是原来m_i后面的那个位置，而这个位置已经超出原来那块内存的后部范围了。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />很显然，在更换了DLL后，应用程序还按原来的大小申请了一块内存，而它调用的方法却访问了比这块内存更大的区域，出错再在所难免。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />同样的情形还会发生在以下这些种情况中：<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">1）&nbsp;</span>应用程序直接访问类的公有变量，而该公有变量在新DLL中定义的位置发生了变化；<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">2）&nbsp;</span>应用程序调用类的一个虚函数，而新的类中，该虚函数的前面又增加了一个虚函数；<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">3）&nbsp;</span>新类的后面增加了成员变量，并且新类的成员函数将访问、修改这些变量；<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">4）&nbsp;</span>修改了新类的基类，基类的大小发生了变化；<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />等等，总言而之，一不小心，你的程序就会掉进地狱。通过对这些引起出错的情况进行分析，会<a class="qs_highlight1" id="hl_3" href="http://clk.qunsee.com/click/click.php?cpid=12&amp;ads_id=230&amp;pid=99000630&amp;cid=634&amp;url=http%3A//www.chanet.com.cn/click.cgi%3Fa%3D59068%26d%3D21648%26u%3D%26e%3D&amp;k=%u53D1%u73B0&amp;s=http%3A//www.diybl.com/course/3_program/c++/cppsl/200819/96118_2.html&amp;rn=503704&amp;v=1&amp;ref=http%3A//www.diybl.com/course/3_program/c++/cppsl/200819/96118.html&amp;province=%u5E7F%u4E1C&amp;city=%u5E7F%u5DDE" target="_blank" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-size: 1em; ">发现</a>其实只有三点变化会引起出错，因为这三点是使用这个DLL的应用程序在编译时就需要确定的内容，它们分别是：<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">1）&nbsp;</span>类的大小；<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">2）&nbsp;</span>类成员的偏移地址；<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">3）&nbsp;</span>虚函数的顺序。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />要想做一个可升级的DLL，必需避免以上三个问题。所以以下三点用来使DLL远离地狱。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />1，不直接生成类的实例。对于类的大小，当我们定义一个类的实例，或使用new语句生成一个实例时，内存的大小是在编译时决定的。要使应用程序不依赖于类的大小，只有一个办法：应用程序不生成类的实例，使用DLL中的函数来生成。把导出类的构造函数定义为私有的(privated)，在导出类中提供静态(static)成员函数(如NewInstance())用来生成类的实例。因为NewInstance()函数在新的DLL中会被重新编译，所以总能返回大小正确的实例内存。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />2，不直接访问成员变量。应用程序直接访问类的成员变量时会用到该变量的偏移地址。所以避免偏移地址依赖的办法就是不要直接访问成员变量。把所有的成员变量的访问控制都定义为保护型(protected)以上的级别，并为需要访问的成员变量定义Get或Set方法。Get或Set方法在编译新DLL时会被重新编译，所以总能访问到正确的变量位置。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />3，忘了虚函数吧，就算有也不要让应用程序直接访问它。因为类的构造函数已经是私有(privated)的了，所以应用程序也不会去继承这个类，也不会实现自己的多态。如果导出类的父类中有虚函数，或设计需要（如类工场之类的框架），一定要把这些函数声明为保护的(protected)以上的级别，并为应用程序重新设计调用该虑函数的成员函数。这一点也类似于对成员变量的处理。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />如果导出的类能遵循以上三点，那么以后对DLL的升级将可以认为是安全的。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />如果对一个已经存在的导出类的DLL进行维护，同样也要注意：不要改动所有的成员变量，包括导出类的父类，无论定义的顺序还是数量；不要动所有的虚函数，无论顺序还是数量。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />总结起来，其实是一句话：导出类的DLL不要导出除了函数以外的任何内容。听起来是不是有点可笑呢！<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />事实上，建议你在发布导出类的DLL的时候，重新定义一个类的声明，这个声明可以不管原来的类里的成员变量之类的，只把接口函数列在类的声明里，如下面的例子：<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />class ClassInterface<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />{<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; privated:</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClassInterface();</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public:</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static ClassInterface * NewInstance();</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int GetXXX();</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void SetXXX();</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void Function();</span><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />};<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />使用该DLL的应用程序用上面的定义作为ClassInterface的头文件，便不会有任何可能导致的安全问题。<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /><br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />DLL地狱问是归根结底是因为DLL当初是作为函数级共享库设计的，并不能真正提供一个类所必需的信息。类层上的程序复用只有Java和C#生成的类文件才能做到。&nbsp;<br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " /></span><br /></a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/152912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-10 07:23 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/10/152912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用OllDbg中断在dll的入口</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/10/152911.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 09 Aug 2011 23:11:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/10/152911.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/152911.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/10/152911.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/152911.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/152911.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="font-family: Simsun; font-size: 12px; line-height: normal; background-color: #ffffff; ">用OllDbg中断在dll的入口<br /><br /><br /></span><div><a href="http://www.pediy.com/bbshtml/bbs7/pediy7-613.htm">http://www.pediy.com/bbshtml/bbs7/pediy7-613.htm<br /><br /><br /><span class="Apple-style-span" style="color: #000000; font-family: Simsun; line-height: normal; -webkit-text-decorations-in-effect: none; background-color: #ffffff; font-size: medium; "><p><font color="blue"><span class="pediy" style="font-size: 9pt; ">标 题:</span></font><span class="pediy" style="font-size: 9pt; "><span class="pediy" style="font-size: 9pt; "><span class="pediy" style="font-size: 9pt; ">&nbsp;Diy OllyDbg's Loaddll.exe<br /><font color="blue">发帖人:</font>jingulong<br /><font color="blue">时 间:&nbsp;</font><font color="#666686">2005-08-13 13:02&nbsp;</font><br /><font color="blue">原文链接:</font><font color="#999999"><a href="http://bbs.pediy.com/showthread.php?threadid=16140" style="color: #000099; text-decoration: none; "><font color="#666686">http://bbs.pediy.com/showthread.php?threadid=16140</font></a></font>&nbsp;<br /><font color="blue">详细信息:</font>&nbsp;</span></span></span><br /></p><blockquote><p class="pediy" style="font-size: 9pt; ">目的：用OllDbg中断在dll的入口<br />程序下载：http://bbs.pediy.com/showthread.php?s=&amp;threadid=16082&nbsp;<br /><br />一、编写plugin&nbsp;:<br />1.&nbsp;&nbsp;DllEntryPoint如图：<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap000.jpg" border="0" alt="" width="432" height="232" />&nbsp;<br />2．ODBG_Plugininit如图：新启一个线程，由此线程的函数WinMain创建一个（隐藏）窗口。<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap0001.jpg" border="0" alt="" width="497" height="145" />&nbsp;<br />3．窗口回调函数如图：<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap0002.jpg" border="0" alt="" width="454" height="175" />&nbsp;<br />至此，plugin设计完成，它所起的作用是：<br />1．&nbsp;&nbsp;当得到WM_USER消息时返回dll入口地址（在MyLdrpCallInitRoutine中）<br />2．&nbsp;&nbsp;当得到WM_USER＋1消息时在wParam指示的地址（就是你调试点dll入口点）设置临时断点（Tempbreakpoint）。<br /><br />二、&nbsp;&nbsp;在dll的加载进程中与plugin通讯。<br />&nbsp;&nbsp;&nbsp;&nbsp;为此，可以写一个加载程序（就好像DLL_Loader），我这里选择diy&nbsp;llyDbg配套的loaddll.exe，因为只有它可与OD&#8220;无缝对接&#8221;。用LordPE打开程序看看结构，当看到它的ExportTable时，感觉实在妙！下面是其截图：<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap003.jpg" border="0" alt="" width="331" height="123" />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;每个导出函数名称叫人看了都如此受用，特别是PatchArea！Oleh&nbsp;Yuschuk为我们考虑得实在周到。Thanks<br />Diy&nbsp;过程：<br />1．&nbsp;&nbsp;把ImportTable中的GetCommandLineA改成GetProcAddress<br />2．&nbsp;&nbsp;Patch&nbsp;<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap004.jpg" border="0" alt="" width="292" height="10" />&nbsp;<br />&nbsp;&nbsp;&nbsp;为：<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap0006.jpg" border="0" alt="" width="199" height="11" />&nbsp;<br />并在Patcharea（410298）处键入：<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap008.jpg" border="0" alt="" width="535" height="71" />&nbsp;<br />以完成原语句的功能。这里程序中原来没有的字符串（如&#8220;GetCommandLineA&#8221;）等在data区或rsrc区段空白处录入。<br />3．Patch<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap005.jpg_990.jpg" border="0" alt="" width="280" height="10" />&nbsp;<br />为&nbsp;call&nbsp;&nbsp;4102B5，并在4102B5开始写入如下代码：<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap009.jpg" border="0" alt="" width="565" height="369" />&nbsp;<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap010.jpg" border="0" alt="" width="655" height="424" />&nbsp;<br /><img src="http://www.pediy.com/bbshtml/bbs7/pediy7-613/snap011.jpg" border="0" alt="" width="594" height="227" />&nbsp;<br />以上代码完成的主要任务是hook&nbsp;dll&nbsp;entrypoint，当程序查到入口处是调试点dll&nbsp;oep&nbsp;时通知plugin设置断点，使OllyDbg中断在那里，这样我们可以少飞许多手脚。</p></blockquote></span><br /></a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/152911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-10 07:11 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/10/152911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dll中非导出函数的调用</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/10/152910.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 09 Aug 2011 23:08:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/10/152910.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/152910.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/10/152910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/152910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/152910.html</trackback:ping><description><![CDATA[<div><a href="http://hi.baidu.com/51634780/blog/item/6e99de041d682689e850cd2a.html">http://hi.baidu.com/51634780/blog/item/6e99de041d682689e850cd2a.html<br /><span class="Apple-style-span" style="color: #555b6e; font-family: Arial; font-size: 12px; line-height: 18px; -webkit-text-decorations-in-effect: none; background-color: #ffffff; "><table style="table-layout: fixed; width: 898px; "><tbody><tr><td style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; zoom: 1 !important; filter: none; font-size: 12px; line-height: 18px; "><div id="blog_text" class="cnt" style="font-family: Arial; word-wrap: break-word; word-break: normal; visibility: visible !important; zoom: 1 !important; filter: none; font-size: 12px; line-height: 18px; overflow-x: hidden; overflow-y: hidden; position: relative !important; "><p style="line-height: normal; ">dll中非导出函数的调用<br style="line-height: normal; " />这几天在学习pe，对输出表特别兴趣。程序对导出函数调用，最终是对导出<br style="line-height: normal; " />函数入口地址的调用，非导出函数的入口地址不在导出表里，所以其他程序</p><p style="line-height: normal; ">无法</p><p style="line-height: normal; ">调用非导出函数。<br style="line-height: normal; " />本人刚开始的想法是在内存里修改dll的导出表，使非导出函数变成导出函</p><p style="line-height: normal; ">数，</p><p style="line-height: normal; ">供自己的程序调用。后来想到可不可以直接调用非导出函数的入口地址呢？</p><p style="line-height: normal; ">感觉</p><p style="line-height: normal; ">应该可以，有了这个想法后就马上开始动手试验。</p><p style="line-height: normal; ">自己写了个简单的dll，其中有2个导出函数a1,b1，1个内部函数c1<br style="line-height: normal; " />先用call的方法调用导出函数：a1<br style="line-height: normal; " />invoke LoadLibrary,CTEXT('testdll.dll')<br style="line-height: normal; " />mov @var1,eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;模块句柄（也是模块的基址）存入@var1&nbsp;<br style="line-height: normal; " />invoke GetProcAddress,@var1,CTEXT('a1')<br style="line-height: normal; " />mov @lpProc,eax ;导出函数的入口地址存入@lpProc<br style="line-height: normal; " />push 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数参数3<br style="line-height: normal; " />push 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数参数2<br style="line-height: normal; " />push hWnd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数参数1<br style="line-height: normal; " />call @lpProc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数调用<br style="line-height: normal; " />一切正常。</p><p style="line-height: normal; ">再调用非导出函数试试，在调用非导出函数c1前，必须找到c1的相对虚拟<br style="line-height: normal; " />地址，<br style="line-height: normal; " />先用程序装入dll<br style="line-height: normal; " />invoke LoadLibrary,CTEXT('testdll.dll')<br style="line-height: normal; " />mov @var1,eax&nbsp;&nbsp;&nbsp; ;模块句柄，也是模块的基址<br style="line-height: normal; " />然后运行程序，用OD调试，找到c1的入口地址：1000100C<br style="line-height: normal; " />1000100C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ebp<br style="line-height: normal; " />1000100D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8BEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ebp,esp<br style="line-height: normal; " />1000100F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B45 08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,dword ptr ss:[ebp+8]<br style="line-height: normal; " />10001012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0345 0C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add eax,dword ptr ss:[ebp+C]<br style="line-height: normal; " />10001015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; leave<br style="line-height: normal; " />10001016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C2 0800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retn 8</p><p style="line-height: normal; ">通过 @var1获得模块的基址是10000000<br style="line-height: normal; " />那末c1的相对虚拟地址就是：1000100C－10000000＝100c<br style="line-height: normal; " />做好了这一步后，就可以在自己的程序里调用非导出函数了。<br style="line-height: normal; " />调用非导出函数：<br style="line-height: normal; " />invoke LoadLibrary,CTEXT('testdll.dll')<br style="line-height: normal; " />mov @var1,eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;模块句柄（也是模块的基址）存入@var1<br style="line-height: normal; " />add @var1,100ch&nbsp;&nbsp;&nbsp; ;得到c1的入口地址<br style="line-height: normal; " />push 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数参数2<br style="line-height: normal; " />push 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数参数1<br style="line-height: normal; " />call @var1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;函数调用<br style="line-height: normal; " />得到了想要的结果，一切ok!</p><p style="line-height: normal; ">用这种方法可以调用别人dll的非导出函数。</p></div></td></tr></tbody></table></span><br /></a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/152910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-10 07:08 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/10/152910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>load dll 简单方式 （收集）</title><link>http://www.cppblog.com/lauer3912/archive/2011/08/10/152909.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Tue, 09 Aug 2011 23:04:00 GMT</pubDate><guid>http://www.cppblog.com/lauer3912/archive/2011/08/10/152909.html</guid><wfw:comment>http://www.cppblog.com/lauer3912/comments/152909.html</wfw:comment><comments>http://www.cppblog.com/lauer3912/archive/2011/08/10/152909.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lauer3912/comments/commentRss/152909.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lauer3912/services/trackbacks/152909.html</trackback:ping><description><![CDATA[<div><a href="http://blog.csdn.net/aca_jingru/article/details/2524697">http://blog.csdn.net/aca_jingru/article/details/2524697<br /><br /><span class="Apple-style-span" style="color: #333333; font-family: Arial; line-height: 26px; -webkit-text-decorations-in-effect: none; background-color: #ffffff; "><div class="dp-highlighter bg_csharp" style="width: 687px; "><div class="bar"><div class="tools"><a href="http://blog.csdn.net/aca_jingru/article/details/2524697#" class="ViewSource" title="view plain" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); border-width: initial; border-color: initial; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">view plain</a></div></div><ol start="1" class="dp-c" style="border-width: initial; border-color: initial; "><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span style="border-width: initial; border-color: initial; ">本文转自codeprojcet&nbsp;&nbsp;&lt;a&nbsp;href=</span><span class="string" style="border-width: initial; border-color: initial; ">"http://www.codeproject.com/kb/dll/dllease.aspx"</span><span style="border-width: initial; border-color: initial; ">&gt;http://www.codeproject.com/KB/DLL/dllease.aspx&lt;/a&gt;&nbsp;&nbsp;&nbsp;</span></span></li></ol></div><p>load dll也就是load dll中的函数,一般是loadlibrary,GetProcAddress,每一步都要判断函数返回是否正确,比较繁琐,</p><p>该作者干脆做了个封装,将这些重复步骤封装到一个bool的函数中,这样只要在if语句中调用一下可以了,具体来看代码:这里用到了c语言的可变参数,对此俺也不是很了解</p><p>&nbsp;</p><div class="dp-highlighter bg_csharp" style="width: 687px; "><div class="bar"><div class="tools"><a href="http://blog.csdn.net/aca_jingru/article/details/2524697#" class="ViewSource" title="view plain" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); border-width: initial; border-color: initial; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">view plain</a></div></div><ol start="1" class="dp-c" style="border-width: initial; border-color: initial; "><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//GetProcAddresses</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Argument1:&nbsp;hLibrary&nbsp;-&nbsp;Handle&nbsp;for&nbsp;the&nbsp;Library&nbsp;Loaded</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Argument2:&nbsp;lpszLibrary&nbsp;-&nbsp;Library&nbsp;to&nbsp;Load</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Argument3:&nbsp;nCount&nbsp;-&nbsp;Number&nbsp;of&nbsp;functions&nbsp;to&nbsp;load</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//[Arguments&nbsp;Format]</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Argument4:&nbsp;Function&nbsp;Address&nbsp;-&nbsp;Function&nbsp;address&nbsp;we&nbsp;want&nbsp;to&nbsp;store</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Argument5:&nbsp;Function&nbsp;Name&nbsp;-&nbsp;&nbsp;Name&nbsp;of&nbsp;the&nbsp;function&nbsp;we&nbsp;want</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//[Repeat&nbsp;Format]</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Returns:&nbsp;FALSE&nbsp;if&nbsp;failure</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="comment" style="border-width: initial; border-color: initial; ">//Returns:&nbsp;TRUE&nbsp;if&nbsp;successful</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">BOOL&nbsp;GetProcAddresses(&nbsp;HINSTANCE&nbsp;*hLibrary,&nbsp;&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;LPCSTR&nbsp;lpszLibrary,&nbsp;INT&nbsp;nCount,&nbsp;...&nbsp;)&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">{&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;va;&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;va_start(&nbsp;va,&nbsp;nCount&nbsp;);&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">if</span><span style="border-width: initial; border-color: initial; ">&nbsp;(&nbsp;(&nbsp;*hLibrary&nbsp;=&nbsp;LoadLibrary(&nbsp;lpszLibrary&nbsp;)&nbsp;)&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!=&nbsp;NULL&nbsp;)&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FARPROC&nbsp;*&nbsp;lpfProcFunction&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPSTR&nbsp;lpszFuncName&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INT&nbsp;nIdxCount&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">while</span><span style="border-width: initial; border-color: initial; ">&nbsp;(&nbsp;nIdxCount&nbsp;&lt;&nbsp;nCount&nbsp;)&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpfProcFunction&nbsp;=&nbsp;va_arg(&nbsp;va,&nbsp;FARPROC*&nbsp;);&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpszFuncName&nbsp;=&nbsp;va_arg(&nbsp;va,&nbsp;LPSTR&nbsp;);&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">if</span><span style="border-width: initial; border-color: initial; ">&nbsp;(&nbsp;(&nbsp;*lpfProcFunction&nbsp;=&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetProcAddress(&nbsp;*hLibrary,&nbsp;&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpszFuncName&nbsp;)&nbsp;)&nbsp;==&nbsp;NULL&nbsp;)&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpfProcFunction&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">return</span><span style="border-width: initial; border-color: initial; ">&nbsp;FALSE;&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nIdxCount++;&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">else</span><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_end(&nbsp;va&nbsp;);&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">return</span><span style="border-width: initial; border-color: initial; ">&nbsp;FALSE;&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;va_end(&nbsp;va&nbsp;);&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">return</span><span style="border-width: initial; border-color: initial; ">&nbsp;TRUE;&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">}&nbsp;&nbsp;</span></li></ol></div><div class="dp-highlighter bg_csharp" style="width: 687px; "><div class="bar"><div class="tools"><a href="http://blog.csdn.net/aca_jingru/article/details/2524697#" class="ViewSource" title="view plain" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); border-width: initial; border-color: initial; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">view plain</a></div></div><ol start="1" class="dp-c" style="border-width: initial; border-color: initial; "><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span style="border-width: initial; border-color: initial; ">使用的例子:&nbsp;&nbsp;</span></span></li></ol></div><div class="dp-highlighter bg_csharp" style="width: 687px; "><div class="bar"><div class="tools"><a href="http://blog.csdn.net/aca_jingru/article/details/2524697#" class="ViewSource" title="view plain" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); border-width: initial; border-color: initial; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">view plain</a></div></div><ol start="1" class="dp-c" style="border-width: initial; border-color: initial; "><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span style="border-width: initial; border-color: initial; ">&lt;pre&nbsp;</span><span class="keyword" style="border-width: initial; border-color: initial; ">class</span><span style="border-width: initial; border-color: initial; ">=</span><span class="string" style="border-width: initial; border-color: initial; ">"csharp"</span><span style="border-width: initial; border-color: initial; ">&nbsp;name=</span><span class="string" style="border-width: initial; border-color: initial; ">"code"</span><span style="border-width: initial; border-color: initial; ">&gt;&lt;pre&nbsp;</span><span class="keyword" style="border-width: initial; border-color: initial; ">class</span><span style="border-width: initial; border-color: initial; ">=</span><span class="string" style="border-width: initial; border-color: initial; ">"csharp"</span><span style="border-width: initial; border-color: initial; ">&nbsp;name=</span><span class="string" style="border-width: initial; border-color: initial; ">"code"</span><span style="border-width: initial; border-color: initial; ">&gt;#include&nbsp;&lt;windows.h&gt;&lt;/windows.h&gt;&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">typedef&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">int</span><span style="border-width: initial; border-color: initial; ">&nbsp;(&nbsp;WINAPI&nbsp;*MESSAGEBOX&nbsp;)&nbsp;&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;HWND&nbsp;,&nbsp;LPCSTR,&nbsp;LPCSTR,&nbsp;DWORD&nbsp;);&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">typedef&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">int</span><span style="border-width: initial; border-color: initial; ">&nbsp;(&nbsp;WINAPI&nbsp;*MESSAGEBOXEX&nbsp;)&nbsp;&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;HWND&nbsp;,&nbsp;LPCSTR,&nbsp;LPCSTR,&nbsp;DWORD&nbsp;,&nbsp;WORD&nbsp;);&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span class="keyword" style="border-width: initial; border-color: initial; ">void</span><span style="border-width: initial; border-color: initial; ">&nbsp;main(</span><span class="keyword" style="border-width: initial; border-color: initial; ">void</span><span style="border-width: initial; border-color: initial; ">)&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">{&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;MESSAGEBOX&nbsp;lpfMsgBox&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;MESSAGEBOXEX&nbsp;lpfMsgBoxEx&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;HINSTANCE&nbsp;hLib;&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">if</span><span style="border-width: initial; border-color: initial; ">(GetProcAddresses(&nbsp;&amp;hLib,&nbsp;</span><span class="string" style="border-width: initial; border-color: initial; ">"User32.dll"</span><span style="border-width: initial; border-color: initial; ">,&nbsp;2,&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;lpfMsgBox,&nbsp;<span class="string" style="border-width: initial; border-color: initial; ">"MessageBoxA"</span><span style="border-width: initial; border-color: initial; ">,&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;lpfMsgBoxEx,&nbsp;<span class="string" style="border-width: initial; border-color: initial; ">"MessageBoxExA"</span><span style="border-width: initial; border-color: initial; ">&nbsp;)&nbsp;)&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpfMsgBox(&nbsp;0,&nbsp;<span class="string" style="border-width: initial; border-color: initial; ">"Test1"</span><span style="border-width: initial; border-color: initial; ">,&nbsp;</span><span class="string" style="border-width: initial; border-color: initial; ">"Test1"</span><span style="border-width: initial; border-color: initial; ">,&nbsp;MB_OK&nbsp;);&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpfMsgBoxEx(&nbsp;0,&nbsp;<span class="string" style="border-width: initial; border-color: initial; ">"Test2"</span><span style="border-width: initial; border-color: initial; ">,&nbsp;</span><span class="string" style="border-width: initial; border-color: initial; ">"Test2"</span><span style="border-width: initial; border-color: initial; ">,&nbsp;MB_OK,&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAKELANGID(&nbsp;LANG_ENGLISH,&nbsp;SUBLANG_ENGLISH_US&nbsp;)&nbsp;);&nbsp;&nbsp;</span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="border-width: initial; border-color: initial; ">if</span><span style="border-width: initial; border-color: initial; ">&nbsp;(&nbsp;hLib&nbsp;!=&nbsp;NULL&nbsp;)&nbsp;&nbsp;</span></span></li><li class="" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeLibrary(&nbsp;hLib&nbsp;);&nbsp;&nbsp;</span></li><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; ">}&nbsp;&nbsp;</span></li></ol></div><div class="dp-highlighter bg_csharp" style="width: 687px; "><div class="bar"><div class="tools"><a href="http://blog.csdn.net/aca_jingru/article/details/2524697#" class="ViewSource" title="view plain" style="background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); border-width: initial; border-color: initial; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: 0% 0%; background-repeat: no-repeat no-repeat; ">view plain</a></div></div><ol start="1" class="dp-c" style="border-width: initial; border-color: initial; "><li class="alt" style="border-width: initial; border-color: initial; line-height: 18px; "><span style="border-width: initial; border-color: initial; "><span style="border-width: initial; border-color: initial; ">是不是很好用呢&nbsp;囧 &nbsp;</span></span></li></ol></div></span><br /></a></div><img src ="http://www.cppblog.com/lauer3912/aggbug/152909.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lauer3912/" target="_blank">RTY</a> 2011-08-10 07:04 <a href="http://www.cppblog.com/lauer3912/archive/2011/08/10/152909.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>