??xml version="1.0" encoding="utf-8" standalone="yes"?>国产AⅤ精品一区二区三区久久,国产精品久久久久乳精品爆 ,合区精品久久久中文字幕一区http://www.shnenglu.com/lauer3912/category/17376.html没有理由不学?/description>zh-cnSat, 19 Jul 2014 05:07:17 GMTSat, 19 Jul 2014 05:07:17 GMT60Dynamic Library Design Guidelines (Xcode)http://www.shnenglu.com/lauer3912/archive/2012/09/13/190472.htmlRTYRTYThu, 13 Sep 2012 00:58:00 GMThttp://www.shnenglu.com/lauer3912/archive/2012/09/13/190472.htmlhttp://www.shnenglu.com/lauer3912/comments/190472.htmlhttp://www.shnenglu.com/lauer3912/archive/2012/09/13/190472.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/190472.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/190472.html阅读全文

RTY 2012-09-13 08:58 发表评论
]]>
常见问题Q如何在有线无线|络共存的情况下合理配置路由 常见问题Q如何在有线无线|络共存的情况下合理配置路由 常见问题Q如何在有线无线|络共存的情况下合理配置路由http://www.shnenglu.com/lauer3912/archive/2012/03/06/167240.htmlRTYRTYTue, 06 Mar 2012 05:25:00 GMThttp://www.shnenglu.com/lauer3912/archive/2012/03/06/167240.htmlhttp://www.shnenglu.com/lauer3912/comments/167240.htmlhttp://www.shnenglu.com/lauer3912/archive/2012/03/06/167240.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/167240.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/167240.htmlhttp://support1.lenovo.com.cn/lenovo/wsi/htmls/detail_12608716075461918.html
文章~号:24625
2006-11-28 9:46:54

在很多情况下会出现有U与无线双网l共存的情况Q此时就需要合理配|\由,否则|络讉K时就会出现؜乱,无法正常上网?br />举例而言Q公司存在tplink无线|络Qؓ192.168.1.*|段Q网关ؓ192.168.1.1Q有U网lؓ10.99.31.*|段Q网关ؓ10.99.31.2Q要实现讉K外网时用无U,内网使用有线Q则配置Ҏ为:
1Q运行CMD
2Qroute delete 0.0.0.0 mask 0.0.0.0 10.99.31.2
   删除所有网l连接都从网?0.99.31.2走这条\径;
3Qroute add 10.0.0.0 mask 255.0.0.0 10.99.31.2 metric 1
   增加内网q接走内|网兌\径;如果在该命o后加 Qp参数重新启动后命o有效Q无需每次写这条命令了Q只需要运?可以了?br />可以以上命令整合ؓ一个bat文gQ保存到所有程序项里面。在双网l都q接成功后,q行该bat文g可以了?br />关于MetricQ?br />metric是\q法用以确定到辄的地的最佌\径的计量标准,常用的metric值有:路径长度,可靠?延迟,带宽,负蝲,通信代h{?
metric值的作用很大,我们常用它来计算路由的优先,如两条到辄同网l的静态\?metric的优先U高;
因此Q我们可以通过合理讄metric值来辑ֈ三个及三个以上多|络存在时的路由配置?br />路由表示意图Q?br />
解释Q?br />默认|关为无U环境tplink?92.168.1.1Q所有的|络数据h都将通过q个|关出去Q也是说所有的|络h都从无线出去?br />persistent routes列表代表所?0|段的都从有U的|关10.99.31.2出去Q也是说所有属?0|段的请求都从有U出厅R通过q个路由来控制内|连接,也就是无U\由配|中所有网l请求走无线环境的例外!
另外Q如果网l环境中配置有自动配|脚本,那么Q配|脚本的优先U最高。网l的数据h按照配|脚本的配置实现。在此例中,如果有自动配|脚本proxy.pacQ那么优先别ؓproxy.pac>192.168.1.1>10.99.31.2Q?br />   


RTY 2012-03-06 13:25 发表评论
]]>
Linux l端中常用的快捷?/title><link>http://www.shnenglu.com/lauer3912/archive/2012/03/01/166872.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Thu, 01 Mar 2012 07:02:00 GMT</pubDate><guid>http://www.shnenglu.com/lauer3912/archive/2012/03/01/166872.html</guid><wfw:comment>http://www.shnenglu.com/lauer3912/comments/166872.html</wfw:comment><comments>http://www.shnenglu.com/lauer3912/archive/2012/03/01/166872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lauer3912/comments/commentRss/166872.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lauer3912/services/trackbacks/166872.html</trackback:ping><description><![CDATA[     摘要: 1. Ud光标快捷键ctrl+f 向前Ud一个字Wctrl+b 向后Ud一个字Walt+f 向前Ud一个单词alt+b 向后Ud一个单词ctrl+a Ud到当前行首ctrl+e Ud到当前行ctrl+l 清屏Qƈ在屏q最上面开始一个新?2. ~辑命o行快捷键ctrl+d 删除当前的字Wctrl+t 交换当前字符和前一个字W的位置alt+t 交换当前单词和前一个单词的位置alt+u 把当前单词变...  <a href='http://www.shnenglu.com/lauer3912/archive/2012/03/01/166872.html'>阅读全文</a><img src ="http://www.shnenglu.com/lauer3912/aggbug/166872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lauer3912/" target="_blank">RTY</a> 2012-03-01 15:02 <a href="http://www.shnenglu.com/lauer3912/archive/2012/03/01/166872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>codesign CSSMERR_TP_NOT_TRUSTEDhttp://www.shnenglu.com/lauer3912/archive/2012/03/01/166868.htmlRTYRTYThu, 01 Mar 2012 06:48:00 GMThttp://www.shnenglu.com/lauer3912/archive/2012/03/01/166868.htmlhttp://www.shnenglu.com/lauer3912/comments/166868.htmlhttp://www.shnenglu.com/lauer3912/archive/2012/03/01/166868.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/166868.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/166868.htmlcodesign -s "Developer ID Application: Mide Hu" "/Users/QtDev/11/build_trial/list.app"
Xcode iOS真机调试出现
Command /usr/bin/codesign failed with exit code 1
查看详细信息提示QCSSMERR_TP_NOT_TRUSTED

出现q一问题的原因可能是Q?br />Q?Q证?#8220;Developer ID Application: Mide Hu" 是无效的Q?br />  (2) ~少”Apple Woldwide Developer Relations Certification Authority“



================================================================
以下是备注:
查了点资料,发现原来之前在keychain(钥匙H访?中多删了一个证书:Apple Woldwide Developer Relations Certification AuthorityQ它是iPhone Developer证书的签发者,如果它被删除׃DiPhone Developer证书被识别ؓ未知颁发机构{֐Q然后xcode中真试就会出C面的错误。解x法当然是重新把AppleWWDRCA攑֛?/div>
从Apple官网下蝲一?nbsp;
http://www.apple.com/certificateauthority/
扑ֈ Woldwide Developer Relations 选择 Download certificate
下蝲后拖入keychain(钥匙H访?Q登录目录?/div>

RTY 2012-03-01 14:48 发表评论
]]>电信速度试http://www.shnenglu.com/lauer3912/archive/2012/02/15/165677.htmlRTYRTYWed, 15 Feb 2012 07:45:00 GMThttp://www.shnenglu.com/lauer3912/archive/2012/02/15/165677.htmlhttp://www.shnenglu.com/lauer3912/comments/165677.htmlhttp://www.shnenglu.com/lauer3912/archive/2012/02/15/165677.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/165677.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/165677.htmlhttp://202.102.26.5/st/


RTY 2011-11-09 06:52 发表评论
]]>Google Breakpad 完全解析Q二Q?—?Windows前台实现?/title><link>http://www.shnenglu.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.shnenglu.com/lauer3912/archive/2011/11/07/159785.html</guid><wfw:comment>http://www.shnenglu.com/lauer3912/comments/159785.html</wfw:comment><comments>http://www.shnenglu.com/lauer3912/archive/2011/11/07/159785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lauer3912/comments/commentRss/159785.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lauer3912/services/trackbacks/159785.html</trackback:ping><description><![CDATA[<div><h2>Google Breakpad 完全解析Q二Q?—— Windows前台实现?/h2> 2011q?2??— Asp J <div><h3>Table of contents for Google Breakpad 完全解析</h3><ol><li><a title="Google Breakpad 完全解析Q一Q?—— Windows入门?>Google Breakpad 完全解析Q一Q?—— Windows入门?/a></li><li>Google Breakpad 完全解析Q二Q?—— Windows前台实现?/li></ol></div> <p>原创文章Q{载请标明出处QSoul Apogee (<a target="_blank">http://bigasp.com</a>)Q谢谢?/p> <p>好,看完?a target="_blank">如何使用breakpad</a>Q我们现在看看breakpad在Windows下到底是如何实现的呢Q?/p> <h3><strong>代码l构</strong></h3> <p>在我们来看breakpad是如何实现其强大的功能之前,我们先来看一下他的代码结构吧?/p> <p>Google breakpad的源代码都在src的目录下Q他分ؓ如下几个文g夹:<br /> clientQ这下面包含了前台应用程序中捕捉dump的部分代码,里面按照q_分成各个子文件夹<br /> commonQ前台后台都会用到的部分基础代码Q字W串转换Q内存读写,md5马?br /> google_breakpadQbreakpad中公q头文?br /> processorQ用于在后台处理崩溃的核心代?br /> testingQ测试工E?br /> third_partyQ第三方?br /> toolsQ一些小工具Q用于处理dump文g和符可</p> <p>我们先来看Windows下前台实现的部分Q也是client文g夹下的代码?/p> <h3><strong>breakpad的崩溃捕h?/strong></h3> <p>在Windows下捕获崩溃,大家很容易会惛_那个捕获l构化异常的ApiQ?a target="blank" >SetUnhandledExceptionFilter</a>?/p> <p>breakpad中也使用了这个Api来实现的崩溃捕获Q另外,breakpadq捕获了另外两种C++q行库提供的崩溃Q一U是使用<a target="blank" >_set_purecall_handler</a>捕获U虚函数调用产生的崩溃,q有一U是使用<a target="blank" >_set_invalid_parameter_handler</a>捕获错误的参数调用生的崩溃?/p> <div><div class="1dzxp55" id="highlighter_32943" cpp"=""><div><a 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"="">    </code><code keyword="" bold"="">if</code> <code plain"="">(handler_types & HANDLER_EXCEPTION)</code></div><div number2="" index1="" alt1"=""><code spaces"="">      </code><code plain"="">previous_filter_ = SetUnhandledExceptionFilter(HandleException);</code></div><div number3="" index2="" alt2"=""> </div><div number4="" index3="" alt1"=""><code preprocessor"="">#if _MSC_VER >= 1400  // MSVC 2005/8</code></div><div number5="" index4="" alt2"=""><code spaces"="">    </code><code keyword="" bold"="">if</code> <code plain"="">(handler_types & HANDLER_INVALID_PARAMETER)</code></div><div number6="" index5="" alt1"=""><code spaces"="">      </code><code plain"="">previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);</code></div><div number7="" index6="" alt2"=""><code preprocessor"="">#endif  // _MSC_VER >= 1400</code></div><div number8="" index7="" alt1"=""> </div><div number9="" index8="" alt2"=""><code spaces"="">    </code><code keyword="" bold"="">if</code> <code plain"="">(handler_types & HANDLER_PURECALL)</code></div><div number10="" index9="" alt1"=""><code spaces"="">      </code><code plain"="">previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);</code></div></div></td></tr></tbody></table></div></div> <p>另外׃C++q行库提供的崩溃回调中,q不会提供当前的U程现场和崩溃信息,所以breakpad会自q成好q些信息Q然后请求生成dump?br /> q里值得一说的是,在非异常崩溃处理中,breakpad获取U程现场使用的函数是RtlCaptureContext而不是GetThreadContext?br /> RtlCaptureContext只能捕获当前U程的现场,而GetThreadContext可以捕获LU程的现场,只要有这个线E的句柄卛_?br /> 但是GetThreadContext有两个不好的地方Q不能获取当前线E的现场Q获取现场前必须先用SuspendThread暂停目标U程?br /> 而RtlCaptureContext虽然只能获取当前U程的现场,但是调用他时可以不用暂停U程的运行?br /> 对于breakpad来说Q崩溃发生后早获取现场p好,所以breakpad使用RtlCaptureContext函数作ؓ他的U程获取函数?/p> <h3><strong>breakpad中的C/Sl构</strong></h3> <p>׃breakpad是在q程外抓取dumpQ所以breakpad需要实C个C/Sl构来处理崩溃进E抓取dump的请求?/p> <p><strong>1. breakpad跨进E通信的实?br /> </strong>breakpad中用了命名道来实现IPC?/p> <p>在客LQ初始化ExceptionHandler的时候,如果指定了PipeNameQ也pC此旉要用进E外的dump?取,ExceptionHandlerQ会建立一?nbsp;CrashGenerationClient的对象,p个对象连接服务端Q将自己注册到服务端?厅R?br /> 大家可以参看exception_handler.cc中的ExceptionHandler::Initialize函数?/p> <p>在服务端Q初始化CrashGenerationServer的时候,׃建立一个命名管道,q等待客L来连接。一旦有客户端连接上来,服务端会 为每一个客L生成一个ClientInfo的对象,之后用这个对象来理所有的客户端,一旦有崩溃发生Q服务端都会从这个对象中取出dump所需要的?息?br /> 大家可以参看crash_generation_server.cc中的CrashGenerationServer::HandleReadDoneState函数?/p> <p><strong>2. breakpad捕获崩溃生成dump的流E?br /> </strong>breakpadq程外生成dump的流E大概如下:<br /> <strong>google-breakpad-out-of-process-dump:</strong><br /><a 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 /> q段程的代码就是crash_generation_client.cc和crash_generation_server.cc?/p> <p>有两个简单的问题Q这里说明一下,高手们就L接忽略吧Q咩哈哈Q?br /> <strong>在服务端如何为客L生成事g句柄Q?/strong><br /> 使用DuplicateHandleQ即可把L一个内核对象的句柄复制到其他进E,q且可以指定产生的句柄的权限?/p> <p><strong>如何异步的等待一个事Ӟ<br /> </strong>使用RegisterWaitForSingleObjectQ即可异步的{待一个事Ӟ当事件发生的时候,可以回调到一个指定的?调函CQ但是要注意的是QRegisterWaitForSingleObject会在一个新的线E中来等待这个事Ӟ此处很容易生多U程的调用,需 要注意线E问题?/p> <p><strong>3. 服务端关键数据结构:ClientInfo<br /> </strong>ClientInfo是服务端中最重要的数据结构,服务端通过它来理所有的客户端。客L注册Ӟ会保存或生成里面所有的信息Q在客户端请求生成dump的时候,服务端就会通过ClientInfo获取所有客L的信息。ClientInfo中保存了如下信息Q?/p> <ul><li>客户端进Epid和句?/li><li>生成Minidump的类?/li><li>自定义的客户端信?/li><li>客户端崩溃的U程ID</li><li>客户端崩溃的信息</li><li>客户端请求崩溃所使用的事件句?/li></ul> <p>q里有一个问题:在客L发生崩溃Ӟ服务器如何通过ClientInfo获取到客L的崩溃信息呢Q?/p> <p>客户端中有几个用于保存崩溃信息的变量Q在注册Ӟ客户端会这几个变量的地址发送至服务端,服务端将其保存在ClientInfo中,然后当崩?发生的时候,服务端就可以通过ReadProcessMemoryd客户端中的信息,从而生成dump。这样做避免了每次发生崩溃Q都要通过Pipe 崩溃信息传递到服务端中M?/p> <p>q些变量分别是:崩溃的线EIDQEXCEPTION_POINTERS和MDRawAssertionInfo?br /> EXCEPTION_POINTERS和MDRawAssertionInfo的区别在于,异常崩溃的信息会被写入EXCEPTION_POINTERSQ非异常崩溃Q非法参数和U虚函数调用Q的信息会被写入MDRawAssertionInfo中?/p> <h3><strong>dump文g的上?/strong></h3> <p>在breakpad的工E中Q有一个工E叫做:crash_report_senderQ里面是一个上传崩溃文件的c,他的实现很简单,他用Windows Internet Api来完成dump文g的上传?br /> 在用crash_report_senderӞ可以为其指定一个checkpoint_file?/p> <div><div class="d33jvbv" id="highlighter_216810" cpp"=""><div><a 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 &checkpoint_file);</code></div></div></td></tr></tbody></table></div></div> <p>q个文g只有一个作用,是用来保存上次上传崩溃的时间和今天上传q的崩溃的次数。通过q个文gQ我们就可以来设|每日上传的崩溃的最大数量?/p> <div><div class="13njt53" id="highlighter_535960" cpp"=""><div><a 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 &checkpoint_file)</code></div><div number2="" index1="" alt1"=""><code spaces"="">    </code><code plain"="">: checkpoint_file_(checkpoint_file),</code></div><div number3="" index2="" alt2"=""><code spaces"="">      </code><code plain"="">max_reports_per_day_(-1),</code></div><div number4="" index3="" alt1"=""><code spaces"="">      </code><code plain"="">last_sent_date_(-1),</code></div><div number5="" index4="" alt2"=""><code spaces"="">      </code><code plain"="">reports_sent_(0) {</code></div><div number6="" index5="" alt1"=""><code spaces"="">  </code><code color1="" bold"="">FILE</code> <code plain"="">*fd;</code></div><div number7="" index6="" alt2"=""><code spaces"="">  </code><code keyword="" bold"="">if</code> <code plain"="">(OpenCheckpointFile(L</code><code string"="">"r"</code><code plain"="">, &fd) == 0) {</code></div><div number8="" index7="" alt1"=""><code spaces"="">    </code><code plain"="">ReadCheckpoint(fd);</code></div><div number9="" index8="" alt2"=""><code spaces"="">    </code><code functions="" bold"="">fclose</code><code plain"="">(fd);</code></div><div number10="" index9="" alt1"=""><code spaces"="">  </code><code plain"="">}</code></div><div number11="" index10="" alt2"=""><code plain"="">}</code></div><div number12="" index11="" alt1"=""> </div><div number13="" index12="" alt2"=""><code plain"="">ReportResult CrashReportSender::SendCrashReport(</code></div><div number14="" index13="" alt1"=""><code spaces"="">    </code><code keyword="" bold"="">const</code> <code plain"="">wstring &url, </code><code keyword="" bold"="">const</code> <code plain"="">map<wstring, wstring> &parameters,</code></div><div number15="" index14="" alt2"=""><code spaces"="">    </code><code keyword="" bold"="">const</code> <code plain"="">wstring &dump_file_name, wstring *report_code) {</code></div><div number16="" index15="" alt1"=""><code spaces"="">  </code><code color1="" bold"="">int</code> <code plain"="">today = GetCurrentDate();</code></div><div number17="" index16="" alt2"=""><code spaces"="">  </code><code keyword="" bold"="">if</code> <code plain"="">(today == last_sent_date_ &&</code></div><div number18="" index17="" alt1"=""><code spaces"="">      </code><code plain"="">max_reports_per_day_ != -1 &&</code></div><div number19="" index18="" alt2"=""><code spaces"="">      </code><code plain"="">reports_sent_ >= max_reports_per_day_) {</code></div><div number20="" index19="" alt1"=""><code spaces"="">    </code><code keyword="" bold"="">return</code> <code plain"="">RESULT_THROTTLED;</code></div><div number21="" index20="" alt2"=""><code spaces"="">  </code><code plain"="">}</code></div><div number22="" index21="" alt1"=""> </div><div number23="" index22="" alt2"=""><code spaces"="">  </code><code comments"="">// 上传文g部分代码Q省?/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文g的时候,crash_report_senderq不会对dump文gq行分析Q而是直接上传整个dump文gQ?如果你需要上传的dump文g非常大的话,可以考虑把崩溃分析处理的逻辑攑օ前台Q通过去重或者直接上传分析结果,减少上传的文件大?/p> <h3><strong>breakpad存在的问?/strong></h3> <h3><span style="font-weight: normal; font-size: 13px;">q程外生成dump有很多好处,其中最大的好处是不会被崩溃进E媄响,q样dump的过E就不容易出错,但是q样也有一定的弊端?/span></h3> <p><strong>1. 部分崩溃无法抓取<br /> </strong>在一些极端的崩溃Q如堆栈溢出之类的崩溃,q程外抓取dump有时候会p|?/p> <p><strong>2. 无法抓取死锁或者其他原因导致的q程僉|<br /> </strong>breakpad现在没有进E死锁的代码Q也没有在服务端控制客户端请求dump的代码,所以现在breakpad无法抓取死锁{进E僵ȝ问题。不q因为breakpad的定位是处理崩溃Q如果有q种需要的童鞋Q可以自行修改breakpad的代码,dq些功能?/p> <p><strong>3. Ҏ务端有依?br /> </strong>如果指定了在使用q程外抓取dumpQbreakpadҎ务端有依赖。主要体现在抓取dumpӞ如果服务端不存在Q客L无法正常抓取dumpQ甚x时会出现d?/p> <p>当然对于q些问题Q随着breakpad的发展肯定会来完善。如果,你遇C了这些问题,而又l过不了Q那改代码Qƈ且提交给breakpad吧,开源项目就是这么发展的?/p> <p>好,到此breakpad的Windows实现已l说完了Q如果有马问题Q还请多多指教。谢谢大家?/p><p style="margin-bottom:0pt; margin-top:0pt; "><a ><span style=" color:#0000ff; text-decoration:underline ;font-family:'宋体'; ">北京徯门中医院</span></a><a ><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.shnenglu.com/lauer3912/aggbug/159785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lauer3912/" target="_blank">RTY</a> 2011-11-07 21:36 <a href="http://www.shnenglu.com/lauer3912/archive/2011/11/07/159785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Breakpad 完全解析Q一Q?—?Windows入门?/title><link>http://www.shnenglu.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.shnenglu.com/lauer3912/archive/2011/11/07/159784.html</guid><wfw:comment>http://www.shnenglu.com/lauer3912/comments/159784.html</wfw:comment><comments>http://www.shnenglu.com/lauer3912/archive/2011/11/07/159784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lauer3912/comments/commentRss/159784.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lauer3912/services/trackbacks/159784.html</trackback:ping><description><![CDATA[<div><h2>Google Breakpad 完全解析Q一Q?—— Windows入门?/h2> 2011q?1?3?— Asp J <div><h3>Table of contents for Google Breakpad 完全解析</h3><ol><li>Google Breakpad 完全解析Q一Q?—— Windows入门?/li><li><a title="Google Breakpad 完全解析Q二Q?—— Windows前台实现?>Google Breakpad 完全解析Q二Q?—— Windows前台实现?/a></li></ol></div> <p>原创文章Q{载请标明出处QSoul Apogee (<a target="_blank">http://bigasp.com</a>)Q谢谢? </p> <p><a title="Google Breakpad" target="_blank">Google breakpad</a>?一个非常实用的跨^台的崩溃转储和分析模块,他支持WindowsQLinux和Mac和Solaris。由于他本n跨^収ͼ所以很大的减少我们在^台移 植时的工作,毕竟崩溃转储Q每个^C都不同,使用h很难l一Q而Google breakpad帮我们做到了这一点,不管是哪个^C的崩溃,都能够进行统一的分析。现在很多工E都在用他Q最著名的几个如 ChromeQFirefoxQPicasa和Google Earth。另外他的License是BSD的,也就是说Q我们即便是在商业Y件中使用Q也是合法的Q哈哈,q么好的东西Q我们能放过么?现在p我们?看看q个奇的Y件吧?/p> <h3><strong>原理?/strong></h3> <p>breakpad抓取dump的方式和一般我们抓取dump的方式不一栗在breakpad的wiki上有一q图可以很好的概括他的原理?/p> <p><img title="breakpad" src="http://google-breakpad.googlecode.com/svn/wiki/breakpad.png" alt="" height="464" width="425" /></p> <p>breakpad把应用程序分成三个部分,代码Qbreakpad客户端和调试信息?/p> <p>1. 在build system中,通过symbol dumper用^台相关的调试信息生成q_无关的symbol文g。这样做的好处很明显Q一旦^台无关了Q所有^台的崩溃可以做l一的分析了?br /> 2. breakpad采取q程外{储和分析崩溃的方式,他用C/Sl构Q客L用来捕获当前q程中发生的崩溃Qƈ通知服务端崩溃发生。服务端用来响应客户端,抓取dump文g。这样做的目的是Z减少崩溃q程对dump的媄响?br /> 3. Dump生成后{发到崩溃分析器中Q这个部分可以在本地也可以在服务器上Q他对Dump文gq行解析Q生成可ȝ堆栈信息?/p> <p>q就是breakpad处理dump大概的流E?/p> <p>对于原理的介lgoogle写的已经相当好了。更多的详细信息Q可以直接移步到<a target="_blank">breakpad的wiki</a>?/p> <h3><strong>安装和编?/strong></h3> <p>breakpad的编译比较曲折,所以在此记录一下?/p> <p>~译breakpadQ请认你的机器上装有以下的软gQ?br /> 1. <a target="_blank">python 2.4.3</a><a target="_blank"><br /> </a>请不要用python3Q会报错。另外python2中推荐这个版本,使用新的版本在编译其他google的工E时有时会报?/p> <p>2. <a target="_blank">Windows SDK 7</a><a target="_blank"><br /> </a>如果没有q个Q编译会报错。另外这个是在线安装Q时间很久,最好ƈ行做其他的事情?/p> <p>3. VS2005的补?br /> KB918559<br /> KB926601<br /> KB935225<br /> KB943969<br /> KB947315</p> <p>已经安装了以上Y件的童鞋Q就可以开始进行下面的工作?/p> <p>1. 使用svn把代?a target="_blank">checkout</a>下来</p> <div><div class="13v5pz5" id="highlighter_301422" shell"=""><div><a 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的童鞋,记得一定要q行q一步,SDK的安装程序,q不会帮你设|VS?br /> q行开始菜?>E序->Microsoft Windows SDK v7.0->Visual Studio Registration->Windows SDK Configuration ToolQ选择v7.0Q点击Make Current?/p> <p>3. 为python讄环境变量<br /> ׃breakpad使用python来生成Windows下的工程文gQ所以需要将python所在目录,讄到环境变量PATH中去?/p> <p>4. 生成Windows工程文g</p> <div><div class="1h5df53" id="highlighter_825083" shell"=""><div><a 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"=""> </div><div number3="" index2="" alt2"=""><code comments"=""># 注意Q此处不能用全路径Q不然会出错</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>此时Q在src/client/windows下就可以看到生成好的breakpad_client.sln了。运行吧Q?/p> <p>5. Hello World!<br /> ~译build allQ现在一般是不会报错了,如果报错Q请查是不是漏了什么步骤,特别是补丁?br /> ~译完成之后Q运行crash_generation_app吧,q是他的试E序Qdump的默认位|保存在C:Dumps下,h意先建立好目录,不然会无法用?br /> 启动试E序之后Q此时还不能抓取dumpQ因个是breakpad中的服务器端Q需要再启动一个测试程序,在第二个试E序中,我们可以试验Client菜单中的各种崩溃了。这些崩溃都会被抓住转存到C:Dumps目录下?/p> <h3><strong>如何使用breakpad</strong></h3> <p> </p> <p>在Windows?a target="_blank">使用breakpad的方?/a>很简单,只需要创Z个ExceptionHandler的类卛_Q大家可以在crash_generation_appq个工程中找到示例代码,也可以直?a target="_blank">UL</a>WikiQ上面说的也很详l?/p> <p>1.q程内抓取Dump文g</p> <p>q程内抓取Dump文g是最单的breakpad的用法。用方法很单:</p> <div><div class="jj35fn5" id="highlighter_394770" cpp"=""><div><a 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"=""> </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"="">    </code><code plain"="">google_breakpad::ExceptionHandler *pCrashHandler =</code></div><div number7="" index6="" alt2"=""><code spaces"="">        </code><code keyword="" bold"="">new</code> <code plain"="">google_breakpad::ExceptionHandler(s_strCrashDir,</code></div><div number8="" index7="" alt1"=""><code spaces"="">        </code><code plain"="">onExceptionFilter,</code></div><div number9="" index8="" alt2"=""><code spaces"="">        </code><code plain"="">onMinidumpDumped,</code></div><div number10="" index9="" alt1"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number11="" index10="" alt2"=""><code spaces"="">        </code><code plain"="">google_breakpad::ExceptionHandler::HANDLER_ALL,</code></div><div number12="" index11="" alt1"=""><code spaces"="">        </code><code plain"="">MiniDumpNormal,</code></div><div number13="" index12="" alt2"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number14="" index13="" alt1"=""><code spaces"="">        </code><code plain"="">NULL);</code></div><div number15="" index14="" alt2"=""> </div><div number16="" index15="" alt1"=""><code spaces"="">    </code><code keyword="" bold"="">if</code><code plain"="">(pCrashHandler == NULL) {</code></div><div number17="" index16="" alt2"=""><code spaces"="">        </code><code keyword="" bold"="">return</code> <code keyword="" bold"="">false</code><code plain"="">;</code></div><div number18="" index17="" alt1"=""><code spaces"="">    </code><code plain"="">}</code></div><div number19="" index18="" alt2"=""> </div><div number20="" index19="" alt1"=""><code spaces"="">    </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.q程外抓取Dump文g</p> <p>使用q程外抓取DumpӞ需要指定服务端和客LQ在服务端中需要创建CrashGenerationServer的实例,而在客户端中则只需要创建ExceptionHandler卛_。此外,如果服务端自己需要抓q程内的DumpQ请pipe的参数置为NULL?/p> <div><div class="vzl3xfn" id="highlighter_709395" cpp"=""><div><a 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"=""> </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"="">    </code><code plain"="">google_breakpad::CrashGenerationServer *pCrashServer =</code></div><div number8="" index7="" alt1"=""><code spaces"="">        </code><code keyword="" bold"="">new</code> <code plain"="">google_breakpad::CrashGenerationServer(s_pPipeName,</code></div><div number9="" index8="" alt2"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number10="" index9="" alt1"=""><code spaces"="">        </code><code plain"="">onClientConnected,</code></div><div number11="" index10="" alt2"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number12="" index11="" alt1"=""><code spaces"="">        </code><code plain"="">onClientDumpRequest,</code></div><div number13="" index12="" alt2"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number14="" index13="" alt1"=""><code spaces"="">        </code><code plain"="">onClientExited,</code></div><div number15="" index14="" alt2"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number16="" index15="" alt1"=""><code spaces"="">        </code><code keyword="" bold"="">true</code><code plain"="">,</code></div><div number17="" index16="" alt2"=""><code spaces"="">        </code><code plain"="">&s_strCrashDir);</code></div><div number18="" index17="" alt1"=""> </div><div number19="" index18="" alt2"=""><code spaces"="">    </code><code keyword="" bold"="">if</code><code plain"="">(pCrashServer == NULL) {</code></div><div number20="" index19="" alt1"=""><code spaces"="">        </code><code keyword="" bold"="">return</code> <code keyword="" bold"="">false</code><code plain"="">;</code></div><div number21="" index20="" alt2"=""><code spaces"="">    </code><code plain"="">}</code></div><div number22="" index21="" alt1"=""> </div><div number23="" index22="" alt2"=""><code spaces"="">    </code><code comments"="">// 如果已经服务端已l启动了Q此处启动会p|</code></div><div number24="" index23="" alt1"=""><code spaces"="">    </code><code keyword="" bold"="">if</code><code plain"="">(!pCrashServer->Start()) {</code></div><div number25="" index24="" alt2"=""><code spaces"="">        </code><code keyword="" bold"="">delete</code> <code plain"="">pCrashServer;</code></div><div number26="" index25="" alt1"=""><code spaces"="">        </code><code plain"="">pCrashServer = NULL;</code></div><div number27="" index26="" alt2"=""><code spaces"="">    </code><code plain"="">}</code></div><div number28="" index27="" alt1"=""> </div><div number29="" index28="" alt2"=""><code spaces"="">    </code><code plain"="">google_breakpad::ExceptionHandler *pCrashHandler =</code></div><div number30="" index29="" alt1"=""><code spaces"="">        </code><code keyword="" bold"="">new</code> <code plain"="">google_breakpad::ExceptionHandler(s_strCrashDir,</code></div><div number31="" index30="" alt2"=""><code spaces"="">        </code><code plain"="">onExceptionFilter,</code></div><div number32="" index31="" alt1"=""><code spaces"="">        </code><code plain"="">onMinidumpDumped,</code></div><div number33="" index32="" alt2"=""><code spaces"="">        </code><code plain"="">NULL,</code></div><div number34="" index33="" alt1"=""><code spaces"="">        </code><code plain"="">google_breakpad::ExceptionHandler::HANDLER_ALL,</code></div><div number35="" index34="" alt2"=""><code spaces"="">        </code><code plain"="">MiniDumpNormal,</code></div><div number36="" index35="" alt1"=""><code spaces"="">        </code><code plain"="">(pCrashServer == NULL) ? s_pPipeName : NULL, </code><code comments"="">// 如果是服务端Q则直接使用q程内dump</code></div><div number37="" index36="" alt2"=""><code spaces"="">        </code><code plain"="">NULL);</code></div><div number38="" index37="" alt1"=""> </div><div number39="" index38="" alt2"=""><code spaces"="">    </code><code keyword="" bold"="">if</code><code plain"="">(pCrashHandler == NULL) {</code></div><div number40="" index39="" alt1"=""><code spaces"="">        </code><code keyword="" bold"="">return</code> <code keyword="" bold"="">false</code><code plain"="">;</code></div><div number41="" index40="" alt2"=""><code spaces"="">    </code><code plain"="">}</code></div><div number42="" index41="" alt1"=""> </div><div number43="" index42="" alt2"=""><code spaces"="">    </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的时候,有两个地斚w要注意:<br /> 1. 记得把breakpad的solution下的几个工程Q包含到你开发的工程中,或者直接包含他们的lib?br /> commonQ基功能Q包含一个对GUID的封装和http上传的类?br /> exception_handlerQ用来捕获崩溃的cR?br /> crash_generation_serverQbreakpad的服务端Q用来在产生崩溃时抓取dump?br /> crash_generation_clientQbreakpad的客LQ用来捕获当前进E的崩溃?/p> <p>2. 在初始化breakpad之前Q记得先创徏好dump文g的目录,不然breakpad服务端将不能正常的写dumpQ这会导致breakpad客户端在崩溃时无限等待服务端dump写完的消息,最后失d应?/p></div><img src ="http://www.shnenglu.com/lauer3912/aggbug/159784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lauer3912/" target="_blank">RTY</a> 2011-11-07 21:34 <a href="http://www.shnenglu.com/lauer3912/archive/2011/11/07/159784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试Release发布版程序的Crash错误 Q{Q?/title><link>http://www.shnenglu.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.shnenglu.com/lauer3912/archive/2011/11/07/159781.html</guid><wfw:comment>http://www.shnenglu.com/lauer3912/comments/159781.html</wfw:comment><comments>http://www.shnenglu.com/lauer3912/archive/2011/11/07/159781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lauer3912/comments/commentRss/159781.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lauer3912/services/trackbacks/159781.html</trackback:ping><description><![CDATA[<div><h1><a id="viewpost1_TitleUrl" href="../../Walker/articles/146153.html">调试Release发布版程序的Crash错误 Q{Q?/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" >http://blog.sina.com.cn/s/blog_48f93b530100fsln.html</a></p> <p> </p> <p>?span>Windowsq_下用C++开发应用程序,最不想见到的情冉|怕就是程序崩溃,而要惌军_起问题的bugQ最困难的应该就是调试release版本了。因为release版本来就了很多调试信息Q更何况一般都是发布出ȝ用户使用Qcrash的现场很难保留和重现。本文将l出几个解决ҎQ完成对release版应用程序crash错误的调试。(本文只讨论Windowsq_MSVC环境下的调试Q对于其他^台和开发环境没有关注,请大家自己借鉴和尝试。)</span></p> <p> <wbr></p> <p> <wbr> <wbr>  <wbr><strong>Ҏ一Q崩溃地址</strong> <span><strong><span>+ MAP</span></strong></span><strong>文g</strong></p> <p><span> <wbr> <wbr> <wbr> </span>q种Ҏ只能?span><span>VC7</span>以前的版本开发的E序使用?span> <wbr></span></span></p> <p><span> <wbr> <wbr> <wbr> <strong>1</strong></span><strong>、崩溃地址</strong></p> <p><span> <wbr> <wbr> <wbr> <wbr> <wbr>所谓崩溃地址是引vE序崩溃的内存地址Q在<span>WinXP</span>下应用程?span>crash</span>的对话框如下图:</span></p> <p align="center"><a 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 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 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> <wbr> <wbr> <wbr> </span><span>上面W?span>2</span>张图中画U线的gؓ<span>crash</span>的代码偏Ud址Q第<span>3</span>张图为即<span>crash</span>l对地址Q一般引?span>crash</span>的原因多为内存操作错误,我们用这两个地址?span>MAP</span>文gp定位出错的代码行?/span></p> <p><span> <wbr> <wbr> <wbr> <strong>2</strong></span><strong>?span><span>MAP</span>文g</span></strong></p> <p><span> <wbr> <wbr> <wbr> MAP</span>文g是记录应用程序信息的文gQ文本文ӞQ里面大概包含了E序的全局W号、源码模块名、源码文件和行号{信息,而这些信息能够帮助我们定位出错的代码行?/p> <p><span> <wbr> <wbr> <wbr> </span>怎样生成<span><span>MAP</span>文g呢??span>VC6</span>ZQ在 <span>Project Settings -> C/C++ <wbr>-> Debug info</span>中,选择 <span>Line Numbers Only </span>Q在 <span>Project Settings -> Link </span>中,选择 <span>Generate mapfile</span>,q在<span>Project Options </span>里面输入 </span><span>/MAPINFO:LINES</span> ?<span><span>/MAPINFO:EXPORTS</span>Q重新编译程序就会生?span>.map</span>文g?/span></p> <p><span> <wbr> <wbr> <wbr> </span>以上讄对应的编译链接选项分别分:</p> <p><span> <wbr> <wbr> <wbr> </span><strong><span>/Zi</span></strong> — 表示生成<span><span>pdb</span>调试信息Q?/span></p> <p><span> <wbr> <wbr> <wbr> </span><strong><span>/MAP[:filename]</span></strong> — 表示生成<span><span>map</span>文g名;</span></p> <p><span> <wbr> <wbr> <wbr> </span><strong><span>/MAPINFO:EXPORTS <wbr></span></strong>— 表示生成?span><span>map</span>文g中加?span>exported functions</span>Q生?span>DLL</span>文gӞQ?/span></p> <p><span> <wbr> <wbr> <wbr> </span><strong><span>/MAPINFO:LINES <wbr></span></strong>— 表示生成?span><span>map</span>文g中加入代码行信息?/span></p> <p><span> <wbr> <wbr> <wbr> </span>׃<span><span>/MAPINFO:LINES</span>选项?span>VC8</span>以后的版本中不再支持Q因此通过<span>MAP</span>文g中的信息?span>crash</span>地址定位出错代码行就比较困难了,所以这U方案只能在<span>VC7</span>及以前的版本中用?/span></p> <p><span> <wbr> <wbr> <wbr> <wbr>一?span>MAP</span>文g片段CZ如下Q?span> <wbr></span></span></p> <p><span> <wbr> <wbr> <wbr> <a 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> <wbr></span></a> <wbr></span></p> <p><span> <wbr> <wbr> <wbr> <a 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> <wbr> <wbr> <wbr> </span><span>图中<span>Rva+Base</span>列的地址行函数对应的函数l对地址Q?span>Address</span>列中冒号后面的地址为函数相对偏Ud址?span> <wbr> <wbr> <wbr></span></span></p> <p><span> <wbr> <wbr> <wbr> <strong>3</strong></span><strong>、定?span><span>crash</span>代码</span></strong></p> <p><span> <wbr> <wbr> <wbr> </span>有了上面的介l,定位<span><span>crash</span>代码很单了。用下面的公式来q行定位Q?/span></p> <p><span> <wbr> <wbr> <wbr> </span><strong>崩溃行偏U?<span><span>= </span>崩溃地址 <span>- </span>崩溃函数l对地址 <span>+ </span>函数相对偏移</span></strong></p> <p><span> <wbr> <wbr> <wbr> </span>我们首先Ҏ崩溃地址Q绝对地址Q,按照扑ֈW?span><span>2</span>张图?span>Rva+Base</span>列的地址扑ֈ发生崩溃的函敎ͼ卛_溃地址大于该函数行?span>Rva+Base</span>地址且小于下个函数的地址Q,然后扑ֈ该行对应的函数相对偏Ud址Q带入公式中Q就得到了崩溃行偏移Q该DC崩溃行的代码相对于代码所在函数的偏移量。用该值去与第<span>3</span>张图中对应函数冒号后面的偏移量去比较Q最接近的值前面的那个十进制数即ؓ代码所在函C的行受?/span></p> <p><span> <wbr> <wbr> <wbr> ok</span>Q到此我们已l成功找C崩溃的代码行Q只不过q种Ҏq是比较费力Qƈ且限制比较多Q我们看看下面的Ҏ?/p> <p>上篇l出的方案一q要补充几句。通过<span>“crash地址 + MAP文g”来定位出错代码位|虽焉要经q比较复杂的地址计算Q但却是最单实现的方式。如果仅仅想通过崩溃地址定位出错的函敎ͼ更加方便了。我在网上找C个解析MAP文g的小工具Q可以非常清晰的列出每个函数的地址Qƈ且可以将分析表格导出为Excel文g。工具下载地址Q?a ><span>http://e.ys168.com/?tinyfun</span></a></span>Q工L录下VCMapper.exe?/p> <p> <wbr> <wbr> <wbr> 另外上篇主要参考两文章:</p> <p> <wbr> <wbr> <wbr> <a ><span>http://www.vckbase.com/document/viewdoc/?id=908</span></a></p> <p> <wbr> <wbr> <wbr> <a ><span>http://www.vckbase.com/document/viewdoc/?id=1473</span></a></p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> <strong>Ҏ二:崩溃地址<span> + MAP文g + COD文g</span></strong></p> <p> <wbr> <wbr> <wbr> ׃<span>VC8以后的版本都不再支持MAP文g中生代码行信息Q因此我们寻扑֏一U定位方式:COD文g?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>1</span></strong><strong>?span>COD文g</span></strong></p> <p> <wbr> <wbr> <wbr> COD文g是一个包含了汇编码、二q制机器码和源代码对应信息的文gQ每一?span>cpp都对应一个COD文g。通过q个文gQ我们可以非常方便地q行定位?/span></p> <p> <wbr> <wbr> <wbr> ?span>VC6中生成COD文g的设|方式ؓQProject Settings -> C/C++Q在 Category 中?Listing FilesQ在 Listing file type l合框中?AssemblyQMachine codeQand source。在VC8中生成COD文g的设|方式ؓQProject Properties -> C/C++ -> Output Files -> Assembler Output ,选择 AssemblyQMachine codeQand Source(/Facs)?/span></p> <p> <wbr> <wbr> <wbr></p> <p> <wbr> <wbr> <wbr> <strong><span>2</span></strong><strong>、定位崩溃行</strong></p> <p> <wbr> <wbr> <wbr> 下面通过举例q行说明。现在我有一个基于对话框?span>MFC应用E序CrashTestQ在CCrashTestDlg::OnInitDialog函数中写入导致crash的代码语句(W?9行)Q源文g如下Q?/span></p> <p> <wbr> <wbr> <wbr> <a 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> <wbr> <wbr> <wbr> Ҏ崩溃地址Q?span>0x004012A3Q以及MAP文gQ定位片D图片如下)Q定位crash函数为OnInitDialogQƈ且我们可以很Ҏ地计出崩溃地址相对于崩溃函数的偏移量ؓ 0x004012A3 - 0x004011E0 = 0xC3?/span></p> <p> <wbr> <wbr> <wbr> <a 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> <wbr> <wbr> <wbr> 再来看看<span>CrashTestDlg.cod文gQ我们根据文件中源码信息扑ֈOnInitDialog函数信息片段Q?/span></p> <p> <wbr> <wbr> <wbr> <a 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> <wbr> <wbr> <wbr> 可以看到囄中第一行ؓ<span>OnInitDialog函数汇编代码的v始行Q找?#8220;int * p = NULL;”q一句源码,其前面的98表示q行代码在源文g中的行号Q下面的000c1表示相对于函数开始位|的偏移量,后面?#8220;33 c0”为机器码Q?#8220;xor eaxQeax”为汇~码。那么我们根据前面算出来的偏U量0xC3Q找到对应出错的语句?9行:“*p = 5;”?/span></p> <p> <wbr> <wbr> <wbr> ȝ一下定位步骤:</p> <p> <wbr> <wbr> <wbr> 1) Ҏ公式 <strong><span>崩溃语句在函C偏移地址<span> = 崩溃地址 - 崩溃函数地址</span></span></strong> 计算出偏U量XQ?/p> <p> <wbr> <wbr> <wbr> 2) Ҏ公式 <strong><span>崩溃语句?span>COD文g中地址 = 崩溃函数在COD文g中地址 + <wbr>X</span></span></strong> 计算出地址Y。其中崩溃函数在COD文g中地址为COD文g中函数v始括?#8220;{”后面表明的地址Q一般情况下?x0000Q?/p> <p> <wbr> <wbr> <wbr> 3) Ҏ<span>Y在COD文g中找到对应代码行?/span></p> <p> <wbr> <wbr> <wbr></p> <p> <wbr> <wbr> <wbr> okQ方案二介绍完了。这U方法最大的好处是没?span>VC开发环境版本限Ӟ而且COD文g里面包含的信息更加丰富,不但可以帮助我们定位crashQ还能帮我们分析很多东西。当Ӟq也D~译生成了很多信息文件?/span></p> <p>Ҏ前面两篇博文Q我们要定位崩溃行代码,必须要自己根据相关信息文件进行计。如果需要处理的量比较大Q恐怕会很费力气。有没有更简单快速的办法呢?</p> <p> <wbr> <wbr> <wbr> 最直接的想法就是写一个小工具Q根据规则和信息q行自动定位Q不q开发v来也是要费一番功夫的。o人开心的是,我们可以扑ֈcM的工P而且是开源免费的Q程序员的世界也许很多时候都是这么单U而乐于分享!</p> <p> <wbr> <wbr> <wbr></p> <p> <wbr> <wbr> <wbr> <strong>Ҏ三:崩溃地址<span> + PDB文g + CrashFinder</span></strong></p> <p> <wbr><wbr> <wbr><wbr> <wbr><wbr> CrashFinder是一个开源工P作者是<span>John RobbinQ大家可以去他的blog上去扑օ于CrashFinder的信息。我们这里以CrashFinder2.5版本Z介绍Q相x章链接ؓQ?a ><span>http://www.wintellect.com/CS/blogs/jrobbins/archive/2006/04/19/crashfinder-returns.aspx</span></a></span></p> <p> <wbr><wbr> <wbr><wbr> <wbr> <strong><span>1</span></strong><strong>?span>PDB文g</span></strong></p> <p> <wbr> <wbr> <wbr> PDBQ?span>Program DatabaseQ文件中包含了exeE序所有的调试相关信息Q具体可以查阅MSDN。当~译选项讄?ZiQ链接选项讄?DEBUGQ?OPT:REFӞ׃生成工程?pdb文g。具体到VC2005中,是 Project Propertise -> C/C++ -> General -> Debug Information Format 设|ؓ Program DatabaseQ?ZiQ,Linker -> Debugging -> Generate Debug Info 设|ؓ YesQ?DebugQ,Linker -> Optimization -> References <wbr>设|ؓ Eliminate <wbr>Unreferenced DataQ?OPT:REFQ?/span></p> <p> <wbr> <wbr> <wbr> 只要讄以上选项Q?span>release版本也能生成PDB文g。当Ӟ对应的应用程序也会稍大?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>2</span></strong><strong>?span>CrashFinder</span></strong></p> <p> <wbr> <wbr> <wbr> CrashFinder能够q行需要两个条Ӟ一是系l必要?span>dbghelp.dll文gQ二是PDB文g必须与exe文g在一个\径下。对于dbghelp.dllQ一般在pȝsystem32路径下都有,如果没有下蝲一个放到这个目录下可以了?/span></p> <p> <wbr> <wbr> <wbr> 先看一?span>CrashFinder的界面?/span></p> <p> <wbr> <wbr> <wbr></p> <p align="center"><a 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> <wbr> <wbr> <wbr> 用v来也非常单。首先选择<span>File->New或点dh新徏按钮Q选择要调试的exe文g打开Q会发现exe及所依赖的dll文g信息都已l加载进来。在下半部分的编辑框中输入崩溃地址Q?6q制Q,点右边的“Find”按钮Q就会在下面昄崩溃的源文g路径、名UC及崩溃所在行号了Q如下图所C?/span></p> <p align="center"><a 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> <wbr> <wbr> <wbr> ?span>CrashFinderq行crash定位真的非常方便。但是我在用过E中发现了一个bugQ每ơ启动程序后Q直接新建的话加载进来的exe模块都显C叉Q提C找不到debug symbols。但是用打开按钮随便打开一个文件失败后Q再新徏p成功。猜可能是直接新徏Q定位PDB文g时的路径不对引v的。有源码Q但是懒的看了呵呵,大家感兴可以试一下?/span></p> <p> <wbr> <wbr> <wbr> 好了Q方案三׃l到q里Q后面还有更加强大的Ҏ<span> : )</span></p> <p>前面几个Ҏ都是直接定位<span>crash的代码位|,但是在比较大型的E序中,只知道这个信息还是远q不够的Q我们希望知道更多关于调用函数顺序及变量值等信息Q也是crash时调用堆栈信息?/span></p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> <strong>Ҏ四:<span>SetUnhandledExceptionFil<wbr>ter + StackWalker</span></strong></p> <p> <wbr> <wbr> <wbr> q个Ҏ需要自己动手往工程里添加代码了。要实现上面的想法,需要做两g事情Q?span>1、需要在crash时有Z对程序堆栈进行处理;2、对堆栈信息q行攉?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>1</span></strong><strong>?span>SetUnhandleExceptionFilt<wbr>er函数</span></strong></p> <p> <wbr> <wbr> <wbr> Windowsq_下的<span>C++E序异常通常可分ZU:l构化异常(Structured ExceptionQ可以理解ؓ与操作系l相关的异常Q和C++异常。对于结构化异常处理QSEHQ,可以扑ֈ很多资料Q在此不l说。对于crash错误Q一般由未被正常捕获的异常引PWindows操作pȝ提供了一个API函数可以在程序crash之前有机会处理这些异常,是SetUnhandleExceptionFilt<wbr>er函数。(C++也有一个类似函数set_terminate可以处理未被捕获的C++异常。)</span></p> <p> <wbr> <wbr> <wbr> SetUnhandleExceptionFilt<wbr>er函数声明如下Q?/p> <p> <wbr> <wbr> <wbr> LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFil<wbr>ter(<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> LPTOP_LEVEL_EXCEPTION_FILTER <em>lpTopLevelExceptionFilte<wbr>r</em><br /> <wbr> <wbr> <wbr> );</p> <p> <wbr> <wbr> <wbr> 其中<span> LPTOP_LEVEL_EXCEPTION_FILTER 定义如下Q?/span></p> <p> <wbr> <wbr> <wbr> typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> __in struct _EXCEPTION_POINTERS *ExceptionInfo<br /> <wbr> <wbr> <wbr> );<br /> <wbr> <wbr> <wbr> typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;</p> <p> <wbr> <wbr> <wbr> 单来_<span>SetUnhandleExceptionFilt<wbr>er允许我们讄一个自q函数作ؓ全局SEHqo函数Q当E序crash前会调用我们的函数进行处理。我们可以利用的?_EXCEPTION_POINTERS l构cd的变量ExceptionInfoQ它包含了对异常的描qC及发生异常的U程状态,qo函数可以通过q回不同的值来让系ll运行或退出应用程序?/span></p> <p> <wbr> <wbr> <wbr> 关于<span> SetUnhandleExceptionFilt<wbr>er 函数的具体用法和CZ请参考MSDN?/span></p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> <strong><span>2</span></strong><strong>?span>StackWalker</span></strong><br /> <wbr> <wbr> <wbr> 现在我们已经有机会可以在<span>crash之前对程序状态信息进行处理了Q只需要生成ƈ保存堆栈信息大功告成了。Windows的dbghelp.dll库提供了一个函数可以得到当前堆栈信息:StackWalk64Q在Win2K以前版本中ؓStackWalkQ。该函数声明如下Q?/span></p> <p> <wbr> <wbr> <wbr> BOOL WINAPI StackWalk64(<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> DWORD <em>MachineType</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> HANDLE <em>hProcess</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> HANDLE <em>hThread</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in_out <wbr> <wbr> <wbr> <wbr> <wbr> LPSTACKFRAME64 <em>StackFrame</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in_out <wbr> <wbr> <wbr> <wbr> <wbr> PVOID <em>ContextRecord</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PREAD_PROCESS_MEMORY_ROUTINE64 <em>ReadMemoryRoutine</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PFUNCTION_TABLE_ACCESS_ROUTINE64 <em>FunctionTableAccessRouti<wbr>ne</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PGET_MODULE_BASE_ROUTINE64 <em>GetModuleBaseRoutine</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PTRANSLATE_ADDRESS_ROUTINE64 <em>TranslateAddress</em><br /> <wbr> <wbr> <wbr> );<br /> <wbr> <wbr> <wbr> 该函数的具体用法可以参?span>MSDN。在q里推荐一个牛人写好的StackWalkerQ可以直接拿来用Q开源的。StackWalker提供了一个基c,l出了几个简单的接口Q可以方便地生成堆栈信息Qƈ且支持一pdVC版本Q非常好用。我们可以自己写一个子c,q载虚函数OnOutputQ就可以堆栈信息输Zؓ特定格式了。StackWalker的地址为:<a ><span>http://www.codeproject.com/KB/threads/StackWalker.aspx</span></a></span>?/p> <p> <wbr> <wbr> <wbr> 不过对于<span>Release版本来说QStackWalk64函数获得的堆栈信息有可能不完整。如果异常是由MFC的模块抛出,那么获得的堆栈可能缺前面调用模块信息。另外,StackWalk64需要最新的dbghelp.dll文g支持才能工作Q要正确输出crash的函数名和行P需要要pdb文g支持。以上不x可能影响输出信息的完整性和效果Q而对于发布在外的E序Q要带上pdb文g几乎不可能,因此q个Ҏq是有缺憄Q比较适用于本地的release版本调试?/span></p> <p> <wbr> <wbr> <wbr> 下一我们将介绍一个更加完善的解决Ҏ</p> <p>当我们把自己?span>release版本E序发布出去以后Q一般都是在用户的机器上q行。这U情况下Q对于第四种ҎQ因为需要pdb文g才能够正生成堆栈调用的函数行号及代码行P因此Ҏ四只适用于本地release版的调试Q否则只能生成不完整的堆栈信息。对于前三种ҎQ其实只需要用户告知崩溃地址Q然后在本地查找crash地址可以了Q但是定位crash的过E非怸方便Q如果crash的情冉|较多Q前三种Ҏ都不合适。而且Q前三种Ҏ均不能生成堆栈调用信息,对于debug的作用有限?/span></p> <p> <wbr> <wbr> <wbr> 下面我们来看一个更加完善的解决Ҏ?/p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> <strong>Ҏ五:<span>SetUnhandledExceptionFil<wbr><wbr>ter + Minidump</span></strong></p> <p> <wbr> <wbr> <wbr> SetUnhandleExceptionFilt<wbr>er函数我们已经介绍q了Q本Ҏ的思\q是要利用我们自q异常处理函数Q来生成<span>minidump文g?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>1</span></strong><strong>?span>Minidump概念</span></strong></p> <p> <wbr> <wbr> <wbr> minidumpQ小存储器{储)可以理解Z?span>dump文gQ里面记录了能够帮助调试crash的最有用信息。实际上Q如果你?pȝ属?-> 高 -> 启动和故障恢?-> 讄 -> 写入调试信息 中选择“内存{?64 KB)”的话Q当pȝ意外停止旉会在C:\Windows\Minidump\路径下生成一?dmp后缀的文Ӟq个文g是minidump文gQ只不过q个是内核态的minidump?/span></p> <p> <wbr> <wbr> <wbr>我们要生成的是用h的<span>minidumpQ文件中包含了程序运行的模块信息、线E信息、堆栈调用信息等。而且ZW合其mini的特性,dump文g是压~过的?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>2</span></strong><strong>、生?span>minidump文g</span></strong></p> <p> <wbr> <wbr> <wbr> 生成<span>minidump文g的API函数是MiniDumpWriteDumpQ该函数需要dbghelp.lib支持Q其原型如下:</span></p> <p> <wbr> <wbr> <wbr> BOOL WINAPI MiniDumpWriteDump(<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> HANDLE <em>hProcess</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> DWORD <em>ProcessId</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> HANDLE <em>hFile</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> MINIDUMP_TYPE <em>DumpType</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PMINIDUMP_EXCEPTION_INFORMATION <em>ExceptionParam</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PMINIDUMP_USER_STREAM_INFORMATION <em>UserStreamParam</em>,<br /> <wbr> <wbr> <wbr> <wbr> <wbr> __in <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> PMINIDUMP_CALLBACK_INFORMATION <em>CallbackParam</em><br /> <wbr> <wbr> <wbr> );</p> <p> <wbr> <wbr> <wbr> 在我们的异常处理函数中加入以下代码:</p> <p> <wbr> <wbr> <wbr> HANDLE hFile = ::CreateFile( _T("E:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);<br /> <wbr> <wbr> <wbr> <wbr> if( hFile != INVALID_HANDLE_VALUE)<br /> <wbr> <wbr> <wbr> <wbr> {<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> MINIDUMP_EXCEPTION_INFORMATION einfo;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> einfo.ThreadId = ::GetCurrentThreadId();<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> einfo.ExceptionPointers = pExInfo;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> einfo.ClientPointers = FALSE;</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, &einfo, NULL, NULL);<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ::CloseHandle(hFile);<br /> <wbr> <wbr> <wbr> <wbr> }</p> <p> <wbr> <wbr> <wbr> 其中Q?span>pExInfo变量为异常处理函数PEXCEPTION_POINTERScd的参数。具体请参考MSDN?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>3</span></strong><strong>、调?span>minidump</span></strong></p> <p> <wbr> <wbr> <wbr> <wbr>调试<span>dump文g首先需要pdb文gQ因此我们buildE序旉要设|?Debug Infomation Format ?“Program DatabaseQ?ZiQ?#8221;。其ơ,我们q要保所用的dump文g与源代码、exe、pdb文g版本是一致的Q这要求我们必须l护好程序版本信息?/span></p> <p> <wbr> <wbr> <wbr> 调试<span>minidump最方便的环境就是VS了,我们只要?dmp?exe?pdb文g攑֜一个\径下Q保证源代码文g的\径与~译时的路径一致就可以了,剩下的就是VS帮我们完成。双?dmp文g或者在文g打开工程中选择“dump files”Q加载dump文gQ然后按F5q行p直接恢复crash时的现场了,你可以定位crash的代码,可以查看调用堆栈Q可以查看线E和模块信息...一切都跟你讄断点调试一P太强大了Q看个截囑֐?/span></p> <p><a 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> <wbr> <wbr> <wbr> 需要注意的是,对于<span>release版的E序来说Q很多代码是l过~译器优化过的,因此定位的时候可能会有所偏差Q大家可以考虑讄选项L代码优化?/span></p> <p> <wbr> <wbr> <wbr> 其他可以调试<span>minidump的工兯有WinDbg{,大家可以查阅相关资料?/span></p> <p> <wbr> <wbr> <wbr> 本文主要参考了q篇文章Q?span><a ><span>http://vicchina.51.net/research/other/seh/minidumps/intro.htm</span></a></span>?/p> <p> <wbr> <wbr> <wbr> 下一,我们给Z个调?span>release发布E序的完解x案,适合用户量较大的应用发布E序的调试?/span></p> <p>上一我们已l给ZҎQ能够非常方便的通过<span>dump文g对crash错误q行调试和定位;从整个流E上看还差最后一步,x样拿到crash时生的dump文g。如果可以让用户把文件发送过来自然不错,但对于类似免费共享Y件等在互联网上发布的E序呢?我们的用h不确定的Q而且用户量有可能非常大,即我们能想办法联系到用PM能挨个去攉crash信息吧?/span></p> <p> <wbr> <wbr> <wbr> 我们需要一U方案,能够提供<span>crash信息汇报功能?/span></p> <p> <wbr> <wbr> <wbr> 我们可以架设一台服务器专门q行信息攉Q只要客L?span>crash时正汇报即可,但是相应的维护成本和开发难度也不可忽视。有没有更简单的Ҏ呢?q记得我的博?#8220;<a target="_blank"><span><span>为程序添加自动发送Email</span><span>功能</span></span></a>”</span>吗?q就是简单有效的ҎQ?/p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> <strong>Ҏ六:<span>minidump + email</span></strong></p> <p> <wbr> <wbr> <wbr> 我们只需要在异常处理Ӟ先生?span>minidump信息文gQ再用email方式文件发送到指定邮箱p了。剩下的是我们每天查看邮箱Q提取dump文gq行调试了?/span></p> <p> <wbr> <wbr> <wbr> <strong><span>1</span></strong><strong>?span>Email功能</span></strong></p> <p> <wbr> <wbr> <wbr> 首先我们来看一?span>email发送都需要哪些相关信息?/span></p> <p> <wbr> <wbr> <wbr> a、发送端邮箱帐户Q?/p> <p> <wbr> <wbr> <wbr> b、接收端邮箱帐户Q?/p> <p> <wbr> <wbr> <wbr> c?span>email标题Q一般应有Y件名U及版本信息Q?/span></p> <p> <wbr> <wbr> <wbr> d?span>email正文Q一般应有简单的crash信息提示Q以区别不同原因造成的crashQ?/span></p> <p> <wbr> <wbr> <wbr> <wbr>e?span>email附gQ当然就是我们的dump文g了,q可以加上Y件生成的log文g{?/span></p> <p> <wbr> <wbr> <wbr> 当然Q对于标题应该尽量多加一些信息区别引?span>crash的原因,比如crash的地址信息加到标题中;因ؓ当每天有成百上千的crash汇报上来Q重复的crash占大多数Q把旉都花在区分它们n上有点太费。由此看来,前面Ҏ中提到的StackWalkerq是有些用处的,我们可以用它来生成一些crash的文字描qC息,写到标题或正文中厅R?/span></p> <p> <wbr> <wbr> <wbr> dump文g的大是否适合作ؓ邮g的附件呢Q实际上<span>minidump产生的文件一般在几K到几十K之间Q作为email的附件没有Q何问题?/span></p> <p> <wbr> <wbr> <wbr> 关于发?span>email相关技术细节,已经?#8220;<a target="_blank"><span><span>为程序添加自动发送Email</span><span>功能</span></span></a>”</span>文中介绍了,大家可以参考。其实,Ҏ受邮׃邮g的处理还是很Ҏ费力的,大家可以考虑写一些脚本将处理程自动化,提高效率?/p> <p> <wbr> <wbr> <wbr> <strong><span>2</span></strong><strong>?span>google breakpad</span></strong></p> <p> <wbr> <wbr> <wbr> google breakpad是一个开源的跨^?span>crash reportpȝQ光从开源和跨^台这两个特点上来看,它就以U的上是一个完善而有效的工具了。其实,breakpad在整个crash report层次上给Z一个系l的解x案,也就是说它几乎能适应各种软g、各U^台的应用要求?/span></p> <p> <wbr> <wbr> <wbr> breakpad的整体思\跟上面介l的Ҏ是相似的Q只不过最后提?span>dump文g的方式更加完善。大家有兴趣可以d的官方网址查阅相关资料Q?a ><span>http://code.google.com/p/google-breakpad/</span></a></span>?/p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> okQ关于调?span>release发布E序的crash错误pd文章写完了。这几篇文章l出的方案由单到复杂Q由陋到完善Q对crash调试有了一个比较全面的ȝ。当Ӟ其中涉及到的概念和技术还很多Q需要我们去不断学习和领悟,也希望大家能够互怺?/span></p> </div> </div></div><img src ="http://www.shnenglu.com/lauer3912/aggbug/159781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lauer3912/" target="_blank">RTY</a> 2011-11-07 21:15 <a href="http://www.shnenglu.com/lauer3912/archive/2011/11/07/159781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>E序员的共鸣 - 诅R卓有成效的E序员?/title><link>http://www.shnenglu.com/lauer3912/archive/2011/09/15/155812.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Wed, 14 Sep 2011 23:36:00 GMT</pubDate><guid>http://www.shnenglu.com/lauer3912/archive/2011/09/15/155812.html</guid><wfw:comment>http://www.shnenglu.com/lauer3912/comments/155812.html</wfw:comment><comments>http://www.shnenglu.com/lauer3912/archive/2011/09/15/155812.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lauer3912/comments/commentRss/155812.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lauer3912/services/trackbacks/155812.html</trackback:ping><description><![CDATA[<span id="5fthjh5" class="Apple-style-span" style="color: #333333; font-family: 微Y雅黑, verdana, Arial, sans-serif; background-color: #ffffff; "><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">最q读了《卓有成效的E序员》,感觉收获颇大。这是一本写l程序员的难得的好书。书中大都是一些浅昄道理Q但作者将q些东西加以攉、归U뀁ȝQƈ最l成书。作者ؓ了收集各U提高效率的工具和方法,东奔西走Q可谓费了一番苦心?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">我觉得此书第一部分ȝ的一些法则非常好Q我提取了一下:<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; " /></p><h3 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; font-weight: bold; color: #000000; ">法则Q?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; " /></h3><h4 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; font-weight: bold; color: #000000; ">1.加速法?/h4><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    x本质Q而非形式</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    一个应用程序列表的有用E度与它的长度成反比 <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; " /></p><p style="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; line-height: 1.5; color: red; ">E序员的很多旉都浪费在找东西上</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; " /></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; ">    键盘输入LD?/p><p style="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; line-height: 1.5; color: red; ">首选键盘而非鼠标</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    地址栏是Windows资源理器界面中最高效的部?/p><p style="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; line-height: 1.5; color: red; ">q旉来学习你手边的所有隐藏的快捷?/span></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; ">    <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; line-height: 1.5; color: red; ">成批复制_脓要比反复多次复制_脓?/span></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; ">    嵌入囑Ş化工L命o提示W让你鱼与熊掌兼?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    在上下文中学习IDE快捷键,而不要去背长长的列表</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    当你W二ơ输入一个复杂结构时Q将它做成模?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    如果要对多行文本做同L操作Q就应该扑և其中的模式,q把它记录ؓ一个宏</p><p style="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; line-height: 1.5; color: red; ">不要L重复输入相同的命?/span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    每天׃点点旉来每一天都更高?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; " /></p><h4 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; font-weight: bold; color: #000000; ">2.专注法则</h4><p style="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; line-height: 1.5; color: red; ">_֊集中,思维缜?/span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    排除q扰Q隔ȝ略,x不需要的提示Q创造安静时?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; " /></p><p style="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; line-height: 1.5; color: red; ">草堆大Q从中找C栚wp?/span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    不要问文件树Q要搜烦</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    使用多显C器</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    虚拟桌面可以让原本杂乱无章的一大堆H口变得整洁 <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; " /></p><h4 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; font-weight: bold; color: #000000; ">3.自动化法?/h4><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; ">    用Selenium览|页</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    不要费旉动手d可以被自动化的事?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    用Windows Power Shell替代批处理文?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    驯服Subversion命o?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    以创造性的方式解决问题Q有助于在将来解决类似的问题</p><p style="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; line-height: 1.5; color: red; ">是否应该自动化的关键在于投资回报率和~解风险</span></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; ">    别给牦牛剪毛 <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; " /></p><h4 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; font-weight: bold; color: #000000; ">4.规范性法?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; " /></h4><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    对于M你不自己L建的东西Q只在版本控制中保存一份副?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; " /></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; ">    <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; line-height: 1.5; color: red; ">通过复制_脓来复用是邪恶的,不论你复制粘贴的是什?/span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    利用虚拟q_佉K目依赖标准化</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    不要让对?- 关系映射工具QO/R映射器)q反规范原则 <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; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    通过扩展。开攄Qopen classQ,或者部分类Qpartial classQ?来ؓ生成的代码增加行?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; " /></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; ">    <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; line-height: 1.5; color: red; ">q时的文档比没有文档更糟Q因为它会主动误g</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    M需要费劲创造的东西Q都让它的创造者欲|不?/p><p style="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; line-height: 1.5; color: red; ">白板 + 数码相机MCASE工具</span></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; ">    <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; line-height: 1.5; color: red; ">重复是Y件开发中最大的d </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; " /></p><h3 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; font-weight: bold; color: #000000; ">工具Q?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; " /></h3><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">书中Q还提到了大量的提高效率的工P都是非常不错的。相信很多h都有自己的一个列表,下面是我电脑中必不可的几款软gQ?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    1. FireFox 及其各类插g<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; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    2. Launchy启动加速器</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    3. Total Commander</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    4. ClipX多重剪切?/p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    5. EmEditor文本~辑?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; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    6. Vistual Studio的VA插g</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    7. Search And Replace</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    8. Everything</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    9. Miranda IM<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; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    10. .... <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; " /></p><h3 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; font-weight: bold; color: #000000; ">感触Q?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; " /></h3><h4 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; font-weight: bold; color: #000000; ">1. 愤怒的猴子 <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; " /></h4><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">在书中的W二部分Q提C很多实践相关的内宏V让我感触最q?#8220;愤怒的猴子”的故事:</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">“<em 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; ">早在20世纪60q代Q那时候科学家们可以做M疯狂的事情)Q行为科学家们进行了一实验。他们把五只猴子和一架活梯放在一间屋子里Qƈ在天花板上挂了一串香蕉。这些猴子很快就惛_它们可以爬上梯子d香蕉Q但每当它们靠近zL的时候,U学家们q冰水满整个屋子。我想你能猜C发生什么:一愤怒的猴子。很快,再没有一只猴子会去靠q那个梯子了?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; " /></em></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><em 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; ">之后Q科学家们将其中一只猴子替换成另一只没有忍受过冰水折磨的新猴子。这只新猴子所做的W一件事是直奔那架梯子Q但当它q么做时其他所有猴子都痛打它。它不明白ؓ什么,但很快就学乖了:不要去靠q那架梯子。科学家们逐渐最初的那些猴子都替换成新猴子,直到q群猴子中谁都没有被水浸泡过Q然而它们还是会LMQ何靠q梯子的猴子?/em></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><em 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; ">q说明了什么?软g目中许多惯例之所以存在,因?#8221;我们一直是那样做的“。换句话_是因为愤怒的猴子?/em>”</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">我们组在制定C++相关的代码规范时遇到过无数cM的问题。比如,在制定变量的命名规范Ӟ我们针对是否采用匈牙利命名法争论了很久。有的h认ؓQ?几乎以前看到的所有C++代码都采用了匈牙利命名法Q甚臻I微Y定义的所有API都用了此类命名法。刚开始,我也是有同样的疑惑?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; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">后来Q我们经q仔l分析C++匈牙利命名法由来Q渐渐感觉我们就是那些愤怒的猴子Q盲目跟从前人的方式Q缺乏打破传l的勇气。C++有着其特D的历史原因Q很多标准一直沉淀下来q很改变。我们再看看后来新生的那些编E语aQC#, Python…… 都抛弃了匈牙利命名法Q同时再看看现在C++前沿的C++ 0x以及现在出版的一些书中,也渐渐放弃了对匈牙利命名法的使用。因为类型的意义在对象模型中来弱化。因此,最后我们放弃了匈牙利命名法q个老古董?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; " /></p><h4 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; font-weight: bold; color: #000000; ">2. 敏捷开?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; " /></h4><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">q本书带有强烈的ThoughtWorks色彩Q敏L思想贯穿全书Q包括测试驱动设计,白板Q结对编E。这也让我对敏捷产生了更加强烈的兴趣?其中有一D|试驱动开发TDD的一D|事:<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; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">“<em 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; ">记得W一ơ和一些已l习惯于单元试的开发h员一起动手开始修改代码时Q我也是非常紧张Q因为大量的修改往往会破坏很多东西,但他们看h丝毫没有犹U。逐渐圎ͼ我也放下心来Q因为我慢慢地认识到Q有了测试的保证Q完全可以放心大胆地M改代码?/em>” <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; " /></p><h4 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; font-weight: bold; color: #000000; ">3. 有趣的故?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; " /></h4><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">书中q有一些有的故事Q比如作者的一个朋友在和别人结对编E时Qؓ了养成同伴用快捷键的习惯,每当同伴未用快捷键Ӟ他都会要求将操作撤销Q然后要求用快捷键再重复操?ơ。然后,在其凶狠的眼中Q同伴很快掌握了快捷键?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; " /></p><h3 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; font-weight: bold; color: #000000; ">ȝQ?/h3><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">q本书很薄,蕴藏的道理却不少Q相信每个读q它的h都会从中收获。读q之后,我们不应该局限于书中提到的某些小技巧, 或是书中某一个细节,毕竟Q提供效率的Ҏ有很多很多,法则也有很多很多Q一本书很难其ID完。我们应该从书中吸取其思想Qƈ在实际工作和学习中不断ȝQ做一个真正的“卓有成效的程序员”Q?/p></span><img src ="http://www.shnenglu.com/lauer3912/aggbug/155812.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lauer3912/" target="_blank">RTY</a> 2011-09-15 07:36 <a href="http://www.shnenglu.com/lauer3912/archive/2011/09/15/155812.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Parallel Programming Essentials via the Intel TBBhttp://www.shnenglu.com/lauer3912/archive/2011/09/15/155810.htmlRTYRTYWed, 14 Sep 2011 23:05:00 GMThttp://www.shnenglu.com/lauer3912/archive/2011/09/15/155810.htmlhttp://www.shnenglu.com/lauer3912/comments/155810.htmlhttp://www.shnenglu.com/lauer3912/archive/2011/09/15/155810.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/155810.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/155810.html阅读全文

RTY 2011-09-15 07:05 发表评论
]]>
Google Test 架构http://www.shnenglu.com/lauer3912/archive/2011/09/15/155807.htmlRTYRTYWed, 14 Sep 2011 22:40:00 GMThttp://www.shnenglu.com/lauer3912/archive/2011/09/15/155807.htmlhttp://www.shnenglu.com/lauer3912/comments/155807.htmlhttp://www.shnenglu.com/lauer3912/archive/2011/09/15/155807.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/155807.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/155807.htmlhttp://code.google.com/p/googletest/

引文Q?a >http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html

玩{Google开源C++单元试框架Google Testpd(gtest)(?

前段旉学习和了解了下Google的开源C++单元试框架Google TestQ简UgtestQ非常的不错?我们原来使用的是自己实现的一套单元测试框Ӟ在用过E中Q发现越来越多用不便之处,而这样不便之处,gtest恰恰很好的解决了?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; " />

其实gtest本n的实现ƈ不复杂,我们完全可以模仿gtestQ不断的完善我们的测试框Ӟ 但最后我们还是决定用gtest取代掉原来的自己的测试框Ӟ原因是:

1.不断完善我们的测试框架之后就会发觉相当于把gtest重新做了一遍,虽然轮子造的很爽Q但是不是必要的?/p>

2.使用gtest可以免去l护试框架的麻烦,让我们有更多_֊投入到案例设计上?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; " />

3.gtest提高了非常完善的功能Qƈ且简单易用,极大的提高了~写试案例的效率?/p>

gtest的官方网站是Q?/p>

http://code.google.com/p/googletest/

从官方的使用文档里,你几乎可以获得你惌的所有东?nbsp;

http://code.google.com/p/googletest/wiki/GoogleTestPrimer

http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide 

如果q想对gtest内部探个I竟Q就把它的代码下载下来研I吧Q这是开源的好处Q哈Q?nbsp;

官方已经有如此完备的文档了,Z么我q要写呢Q一斚w是自p记笔讎ͼ好记性不如烂W头Q以后自己想查查一些用法也可以直接在这里查刎ͼ一斚w是对于不惛_看一大堆英文文档的朋友,在我q里可以快速的扑ֈgtest相关的内宏V?/p>

下面是该pd的目录:

1.玩{Google开源C++单元试框架Google Testpd(gtest)之一 - 初识gtest

2.玩{Google开源C++单元试框架Google Testpd(gtest)之二 - 断言

3.玩{Google开源C++单元试框架Google Testpd(gtest)之三 - 事g机制

4.玩{Google开源C++单元试框架Google Testpd(gtest)之四 - 参数?/a>

5.玩{Google开源C++单元试框架Google Testpd(gtest)之五 - M试 

6.玩{Google开源C++单元试框架Google Testpd(gtest)之六 - q行参数

7.玩{Google开源C++单元试框架Google Testpd(gtest)之七 - 深入解析gtest

8.玩{Google开源C++单元试框架Google Testpd(gtest)之八 - 打造自q单元试框架


额外:

1.gtest中如何蟩出当前测试案?/a>

2.~写优美的GTest试案例

3.gtest 参数化测试代码示?/a> (内含完整工程CZ)

作者:CoderZhQ?a target="_blank" 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; text-decoration: none; color: #0066aa; border-bottom-width: 0px; border-bottom-style: initial; border-bottom-color: initial; ">CoderZh的技术博?- 博客?/a>Q?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; " />微博Q?a target="_blank" 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; text-decoration: none; color: #0066aa; border-bottom-width: 0px; border-bottom-style: initial; border-bottom-color: initial; ">http://t.sina.com.cn/coderzh 
出处Q?a target="_blank" 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; text-decoration: none; color: #0066aa; border-bottom-width: 0px; border-bottom-style: initial; border-bottom-color: initial; ">http://coderzh.cnblogs.com
文章版权归本人所有,Ƣ迎转蝲Q但未经作者同意必M留此D声明,且在文章面明显位置l出原文q接Q否则保留追I法律责ȝ权利?/p>




RTY 2011-09-15 06:40 发表评论
]]>
ConstQConst函数QConst变量Q函数后面的Consthttp://www.shnenglu.com/lauer3912/archive/2011/07/26/151840.htmlRTYRTYMon, 25 Jul 2011 23:14:00 GMThttp://www.shnenglu.com/lauer3912/archive/2011/07/26/151840.htmlhttp://www.shnenglu.com/lauer3912/comments/151840.htmlhttp://www.shnenglu.com/lauer3912/archive/2011/07/26/151840.html#Feedback0http://www.shnenglu.com/lauer3912/comments/commentRss/151840.htmlhttp://www.shnenglu.com/lauer3912/services/trackbacks/151840.html

看到const 关键字,C++E序员首先想到的可能是const 帔R。这可不是良好的条g反射。如果只知道用const 定义帔RQ那么相当于把火药仅用于制作鞭炮。const 更大的魅力是它可以修饰函数的参数、返回|甚至函数的定义体?/p>

const 是constant 的羃写,“恒定不变”的意思。被const 修饰的东襉K受到强制保护Q可以预防意外的变动Q能提高E序的健壮性。所以很多C++E序设计书籍Q?#8220;Use const whenever you need”?/p>

1.用const 修饰函数的参?/p>

如果参数作输出用Q不论它是什么数据类型,也不论它采用“指针传?#8221;q是“引用传?#8221;Q都不能加const 修饰Q否则该参数失去输出功能。const 只能修饰输入参数Q?/p>

如果输入参数采用“指针传?#8221;Q那么加const 修饰可以防止意外地改动该指针QvC护作用?/strong>

例如StringCopy 函数Q?/p>

void StringCopy(char *strDestination, const char *strSource);

其中strSource 是输入参敎ͼstrDestination 是输出参数。给strSource 加上const修饰后,如果函数体内的语句试图改?/span>strSource 的内容,~译器将指出错误?/span>

如果输入参数采用“g?#8221;Q由于函数将自动产生临时变量用于复制该参敎ͼ该输入参数本来就无需保护Q所以不要加const 修饰?/p>

例如不要函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A 为用戯定义的数据类型?/p>

对于非内部数据类型的参数而言Q象void Func(A a) q样声明的函数注定效率比较底。因为函C内将产生A cd的时对象用于复制参数aQ而时对象的构造、复制、析构过E都消耗时间?/p>

Z提高效率Q可以将函数声明改ؓvoid Func(A &a)Q因?#8220;引用传?#8221;仅借用一下参数的别名而已Q不需要生时对象。但是函数void Func(A &a) 存在一个缺点:

“引用传?#8221;有可能改变参数aQ这是我们不期望的。解册个问题很ҎQ加const修饰卛_Q因此函数最l成为void Func(const A &a)?/p>

以此cLQ是否应void Func(int x) 改写为void Func(const int &x)Q以便提高效率?完全没有必要Q因为内部数据类型的参数不存在构造、析构的q程Q而复制也非常快,“g?#8221;?#8220;引用传?#8221;的效率几乎相当?/p>

问题是如此的~Q我只好?#8220;const &”修饰输入参数的用法ȝ一下?/p>

 

对于非内部数据类型的输入参数Q应该将“g?#8221;的方式改?#8220;const 引用传?#8221;Q目的是提高效率。例如将void Func(A a) 改ؓvoid Func(const A &a)?/p>

 

对于内部数据cd的输入参敎ͼ不要?#8220;g?#8221;的方式改?#8220;const 引用传?#8221;。否则既达不到提高效率的目的Q又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)?/p>

2 用const 修饰函数的返回?br />如果l以“指针传?#8221;方式的函数返回值加const 修饰Q那么函数返回|x针)的内容不能被修改Q?strong>该返回值只能被赋给加const 修饰的同cd指针。例如函?br />const char * GetString(void);
如下语句出现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();
如果函数q回值采?#8220;g递方?#8221;Q由于函C把返回值复制到外部临时的存储单元中Q加const 修饰没有M价倹{?br />例如不要把函数int GetInt(void) 写成const int GetInt(void)?br />同理不要把函数A GetA(void) 写成const A GetA(void)Q其中A 为用戯定义的数据类型?br />如果q回g是内部数据类型,函数A GetA(void) 改写为const A & GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是惌回一个对象的“拯”q是仅返?#8220;别名”可以了Q否则程序会出错?br />函数q回值采?#8220;引用传?#8221;的场合ƈ不多Q这U方式一般只出现在类的赋值函CQ目的是Z实现铑ּ表达?/p>

例如Q?br />class A
{
A & operate = (const A &other); // 赋值函?br />};
A a, b, c; // a, b, c 为A 的对?br />
a = b = c; // 正常的链式赋?br />(a = b) = c; // 不正常的铑ּ赋|但合?br />如果赋值函数的q回值加const 修饰Q那么该q回值的内容不允许被改动。上例中Q语?a = b = c 仍然正确Q但是语?(a = b) = c 则是非法的?br />3 const 成员函数
M不会修改数据成员的函数都应该声明为const cd。如果在~写const 成员函数Ӟ不慎修改了数据成员,或者调用了其它非const 成员函数Q编译器指出错误,q无疑会提高E序的健壮性。以下程序中Q类stack 的成员函数GetCount 仅用于计敎ͼ从逻辑上讲GetCount 应当为const 函数。编译器指出GetCount 函数中的错误?br />class Stack
{
public:
void Push(int elem);
int Pop(void);
int GetCount(void) const; // const 成员函数
private:
int m_num;
int m_data[100];
};
int Stack::GetCount(void) const
{
++ m_num; // ~译错误Q企图修Ҏ据成员m_num
Pop(); // ~译错误Q企图调用非const 函数
return m_num;
}
const 成员函数的声明看h怪怪的Qconst 关键字只能放在函数声明的NQ大概是因ؓ其它地方都已l被占用了?br />关于Const函数的几点规则:

a. const对象只能讉Kconst成员函数,而非const对象可以讉KL的成员函?包括const成员函数.
b. const对象的成员是不可修改?然而const对象通过指针l护的对象却是可以修改的.
c. const成员函数不可以修改对象的数据,不管对象是否hconst性质.它在~译?以是否修Ҏ员数据ؓ依据,q行?
e. 然而加上mutable修饰W的数据成员,对于M情况下通过M手段都可修改,自然此时的const成员函数是可以修改它?/p>

RTY 2011-07-26 07:14 发表评论
]]>
const 基本用法说明Q请注意Q?/title><link>http://www.shnenglu.com/lauer3912/archive/2011/07/26/151839.html</link><dc:creator>RTY</dc:creator><author>RTY</author><pubDate>Mon, 25 Jul 2011 23:13:00 GMT</pubDate><guid>http://www.shnenglu.com/lauer3912/archive/2011/07/26/151839.html</guid><wfw:comment>http://www.shnenglu.com/lauer3912/comments/151839.html</wfw:comment><comments>http://www.shnenglu.com/lauer3912/archive/2011/07/26/151839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lauer3912/comments/commentRss/151839.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lauer3912/services/trackbacks/151839.html</trackback:ping><description><![CDATA[<span id="5d3rdjz" class="Apple-style-span" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">constcd定义Q指明变量或对象的值是不能被更?引入目的是ؓ了取代预~译指o <br /><br />**************帔R必须被初始化*************************<br /><br />cons的作?br />   Q?Q可以定义const帔R         例如Q?br />             const int Max=100;<br />             int Array[Max];        <br />   Q?Q便于进行类型检?nbsp;           例如Q?br />             void f(const int i) { .........}<br />        ~译器就会知道i是一个常量,不允怿改;<br />   Q?Q可以保护被修饰的东西,防止意外的修改,增强E序的健壮性?br />        q是上面的例子,如果在函C内修改了iQ编译器׃报错Q?br />        例如Q?nbsp;<br />             void f(const int i) { i=10;//error! }<br />    (5) 为函数重载提供了一个参考?br />         class A<br />         {<br />           ......<br />           void f(int i)       {......} file://一个函?br />           void f(int i) const {......} file://上一个函数的重蝲<br />            ......<br />          };<br />     (6) 可以节省I间Q避免不必要的内存分配?br />         例如Q?br />              #define PI 3.14159         file://帔R?br />              const doulbe  Pi=3.14159;  file://此时q未Pi攑օROM?br />              ......<br />              double i=Pi;               file://此时为Pi分配内存Q以后不再分配!<br />              double I=PI;               file://~译期间q行宏替换,分配内存<br />              double j=Pi;               file://没有内存分配<br />              double J=PI;               file://再进行宏替换Q又一ơ分配内存!<br />         const定义帔R从汇~的角度来看Q只是给Z对应的内存地址Q而不是象#define一L出的是立xQ所以,const定义的常量在E序q行q程中只有一份拷贝,?define定义的常量在内存中有若干个拷贝?br />     Q?Q?nbsp;提高了效率?br />           ~译器通常不ؓ普通const帔R分配存储I间Q而是它们保存在W号表中Q这使得它成Z个编译期间的帔RQ没有了存储与读内存的操作,使得它的效率也很高?br /><br />使用const<br />   Q?Q修C般常?常数l,常对?br />   修饰Wconst可以用在cd说明W前Q也可以用在cd说明W后?nbsp;     例如Q?nbsp;  <br />           int const x=2;  或  const int x=2;<br /><br />       int const a[5]={1, 2, 3, 4, 5};    ?nbsp; const int a[5]={1, 2, 3, 4, 5};<br /><br />           class A;      const A a;  ?nbsp;    A const a;<br />     <br />   Q?Q修饰指?br />        const int *A;   ?nbsp; int const *A; //const修饰指向的对象,A可变QA指向的对象不可变<br />        int *const A;              //const修饰指针AQ?nbsp;    A不可变,A指向的对象可?nbsp;<br />        const int *const A;      //指针A和A指向的对象都不可?br />   Q?Q修饰引?br />        const double & v;      该引用所引用的对象不能被更新<br /> Q?Q修饰函数的q回|<br />        const修饰W也可以修饰函数的返回|是返回g可被改变Q格式如下:<br />            const int Fun1(); <br />            const MyClass Fun2();<br />   Q?Q修饰类的成员函敎ͼ<br />        const修饰W也可以修饰cȝ成员函数Q格式如下:<br />            class ClassName <br />     {<br />             public:<br />                  int Fun() const;<br />                    .....<br />             }Q?br />        q样Q在调用函数Fun时就不能修改c里面的数据 <br />    Q?Q在另一q接文g中引用const帔R<br />         extern const int i;     //正确的引?br />         extern const int j=10;  //错误Q常量不可以被再ơ赋?br />   <br /><br /><br />*******************攑֜cd部的帔R有什么限Ӟ<br />  <br />        class A<br />        {<br />         private:<br />           const int c3 = 7;               // err<br />           static int c4 = 7;               // err<br />           static const float c5 = 7;  // err<br />          ......<br />  };<br /> 初始化类内部的常?br />        1 初始化列表:<br />         class A<br />         {<br />          public:<br />                A(int i=0):test(i) {}<br />          private:<br />                const int i;<br />          }Q?br />         2 外部初始化,例如Q?br />         class A<br />         {<br />          public:<br />                A() {}<br />          private:<br />                static const int i;  <br />          }Q?br />          const int A::i=3; </span><img src ="http://www.shnenglu.com/lauer3912/aggbug/151839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lauer3912/" target="_blank">RTY</a> 2011-07-26 07:13 <a href="http://www.shnenglu.com/lauer3912/archive/2011/07/26/151839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.tongdiaocj.cn" target="_blank">һþ㽶</a>| <a href="http://www.52yydy.cn" target="_blank">ղƷþþþþþ</a>| <a href="http://www.cnmere.cn" target="_blank">ҹƵþþþһ</a>| <a href="http://www.td265.cn" target="_blank">þݺҹҹ2020һ</a>| <a href="http://www.sinaer.cn" target="_blank">þóۺɫۺ</a>| <a href="http://www.szlove.net.cn" target="_blank">99þþþþѿ</a>| <a href="http://www.zhouyimen.cn" target="_blank">2021¾þþӾƷ</a>| <a href="http://www.uoip.cn" target="_blank">þþþþһ </a>| <a href="http://www.rqtjc.cn" target="_blank">þþƷһ</a>| <a href="http://www.qvcz.cn" target="_blank">þþþƷ</a>| <a href="http://www.fgzpf.cn" target="_blank">69Ʒþþþվ</a>| <a href="http://www.scmyff.cn" target="_blank">Ʒ۲ӰԺþ</a>| <a href="http://www.sglshoes.cn" target="_blank">þۺ97ɫһһ</a>| <a href="http://www.aliyundjq.cn" target="_blank">ƷŮþþþavˬ</a>| <a href="http://www.78cbg.cn" target="_blank">þþþһƷɫ</a>| <a href="http://www.vocard.cn" target="_blank">þۺɫ99žak</a>| <a href="http://www.kaczw3.cn" target="_blank">ҹþӰԺ</a>| <a href="http://www.nanghang.cn" target="_blank">޹þþþƷ</a>| <a href="http://www.chaoyuemobile.com.cn" target="_blank">þþƷĻһ</a>| <a href="http://www.07sn.cn" target="_blank">þ99Ʒһ</a>| <a href="http://www.brill-sh.com.cn" target="_blank">ŷ޹Ʒþ</a>| <a href="http://www.zgsmkf.cn" target="_blank">ݺݾþۺ˲</a>| <a href="http://www.0352quan.cn" target="_blank">þþƷAVþþ </a>| <a href="http://www.bfav.cn" target="_blank">ղƷþþþþþɫ</a>| <a href="http://www.shamba.com.cn" target="_blank">þ㽶߿ۿè?v</a>| <a href="http://www.iamwilson.cn" target="_blank">wwwԾþþcom</a>| <a href="http://www.gg32.cn" target="_blank">һɫþۺϺݺ</a>| <a href="http://www.wuchui.cn" target="_blank">ùƷӰ˾þ</a>| <a href="http://www.babaishu.cn" target="_blank">˾Ʒþһav</a>| <a href="http://www.dogff.cn" target="_blank">ղƷþþһ</a>| <a href="http://www.shebianfen.cn" target="_blank">þۺɫˮ99ž </a>| <a href="http://www.henpu.cn" target="_blank">˳˳ۺþþ</a>| <a href="http://www.fc117.cn" target="_blank">þþþƵ</a>| <a href="http://www.uzri.cn" target="_blank">þþþ</a>| <a href="http://www.rocchetta.com.cn" target="_blank">Ʒѿþþ㽶</a>| <a href="http://www.wuchui.cn" target="_blank">ɫۺϾþþƷĻҳ</a>| <a href="http://www.lianliankan123.cn" target="_blank">ھƷþþþþ99</a>| <a href="http://www.qenw.cn" target="_blank">91þþƷ91þɫ</a>| <a href="http://www.40theft.cn" target="_blank">þþƷվ</a>| <a href="http://www.zzbxgsx.cn" target="_blank">þþùƷվ</a>| <a href="http://www.hzlike.cn" target="_blank">91龫Ʒ91þþþ </a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>