﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-elva-随笔分类-C\C++</title><link>http://www.cppblog.com/elva/category/4529.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 30 Dec 2011 13:41:06 GMT</lastBuildDate><pubDate>Fri, 30 Dec 2011 13:41:06 GMT</pubDate><ttl>60</ttl><item><title>__attribute__((deprecated))</title><link>http://www.cppblog.com/elva/archive/2011/12/28/162998.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 28 Dec 2011 12:26:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/12/28/162998.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/162998.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/12/28/162998.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/162998.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/162998.html</trackback:ping><description><![CDATA[RealView 编译工具 编译器参考指南<br /><br />
<div lang="en" class="sect2" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="Caccahah"></a>4.5.4. <code class="literal">__attribute__((deprecated))</code></h3></div></div></div>
<p>可以使用 <code class="literal">deprecated</code> 变量属性声明不提倡使用的变量，而不会导致编译器发出任何警告或错误。但是，对 <code class="literal">deprecated</code> 变量的任何访问都会生成警告，但仍会进行编译。警告指出了使用和定义变量的位置。这有助于确定不提倡使用特定定义的原因。</p>
<div class="note">
<h3 class="note">Note</h3>
<p>此变量属性是 ARM 编译器支持的 GNU 编译器扩展。</p></div>
<div lang="en" class="sect3" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h4 class="title"><a id="id4851969"></a>示例</h4></div></div></div><pre class="programlisting">extern int Variable_Attributes_deprecated_0 __attribute__ ((deprecated));
extern int Variable_Attributes_deprecated_1 __attribute__ ((deprecated));
void Variable_Attributes_deprecated_2()
{
    Variable_Attributes_deprecated_0=1;
    Variable_Attributes_deprecated_1=2;
}
</pre>
<p>编译此示例时，将生成两条警告消息。</p></div></div>
<div class="footers">
<table class="legalfooter" border="0" cellspacing="0" summary="Legal information footer" cellpadding="0" width="100%">
<tbody>
<tr class="copyrightdocnumbar">
<td class="copyrightcell" valign="top" align="left">Copyright &#169; 2007-2009 ARM Limited. All rights reserved.</td>
<td class="docnumcell" valign="top" align="right">ARM DUI 0348BC</td></tr>
<tr class="secstatusbar">
<td class="securitycell" valign="top" align="left">Non-Confidential</td></tr>
<tr class="pdflinkbar">
<td class="pdflinkcell" valign="top" colspan="2" align="center"><a href="http://infocenter.arm.com/help/topic/com.arm.doc.dui0348bc/DUI0348BC_rvct_comp_ref_guide.pdf" rel="nofollow" target="_blank"><img border="0" alt="PDF file icon" src="http://infocenter.arm.com/help/topic/com.arm.doc.common/images/pdficon_small.gif" /> PDF version</a></td></tr></tbody></table></div><br /><br /><br />转载自：<br /><a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0348bc/Caccahah.html">http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0348bc/Caccahah.html</a><img src ="http://www.cppblog.com/elva/aggbug/162998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-12-28 20:26 <a href="http://www.cppblog.com/elva/archive/2011/12/28/162998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gdb中忽略信号处理</title><link>http://www.cppblog.com/elva/archive/2011/11/01/159457.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 01 Nov 2011 06:46:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/11/01/159457.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/159457.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/11/01/159457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/159457.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/159457.html</trackback:ping><description><![CDATA[<div>信号（Signals）<br /> <br /> 信号是一种软中断，是一种处理异步事件的方法。一般来说，操作系统都支持许多信号。尤其是UNIX，比较重要应用程序一般都会处理信号。UNIX定义了许 多信号，比如SIGINT表示中断字符信号，也就是Ctrl+C的信号，SIGBUS表示硬件故障的信号；SIGCHLD表示子进程状态改变信号； SIGKILL表示终止程序运行的信号，等等。信号量编程是UNIX下非常重要的一种技术。<br /> <br /> GDB有能力在你调试程序的时候处理任何一种信号，你可以告诉GDB需要处理哪一种信号。你可以要求GDB收到你所指定的信号时，马上停住正在运行的程序，以供你进行调试。你可以用GDB的handle命令来完成这一功能。<br /> <br /> handle<br /> 在GDB中定义一个信号处理。信号可以以SIG开头或不以 SIG开头，可以用定义一个要处理信号的范围（如：SIGIO-SIGKILL，表示处理从SIGIO信号到SIGKILL的信号，其中包括SIGIO， SIGIOT，SIGKILL三个信号），也可以使用关键字all来标明要处理所有的信号。一旦被调试的程序接收到信号，运行程序马上会被GDB停住，以 供调试。其可以是以下几种关键字的一个或多个。<br /> <br /> nostop<br /> 当被调试的程序收到信号时，GDB不会停住程序的运行，但会打出消息告诉你收到这种信号。<br /> stop<br /> 当被调试的程序收到信号时，GDB会停住你的程序。<br /> print<br /> 当被调试的程序收到信号时，GDB会显示出一条信息。<br /> noprint<br /> 当被调试的程序收到信号时，GDB不会告诉你收到信号的信息。<br /> pass<br /> noignore<br /> 当被调试的程序收到信号时，GDB不处理信号。这表示，GDB会把这个信号交给被调试程序会处理。<br /> nopass<br /> ignore<br /> 当被调试的程序收到信号时，GDB不会让被调试程序来处理这个信号。<br /> <br /> <br /> info signals<br /> info handle<br /> 查看有哪些信号在被GDB检测中。 		 		 		</div><br />另外补充：<br /><div><span style="word-spacing: 0px; font: medium Simsun; text-transform: none; color: #000000; text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span style="font-size: 13px; color: #333333; line-height: 21px"> <p><strong>信号的处理</strong><br /> 程序是和网络相关的，调试期间经常地收到SIGPIPE，导致gdb停下来。看了一下gdb info，解决方法很简单。用handle命令设置一下缺省signal的处理行为就可以了:<code><br /> &nbsp;&nbsp; handle SIGPIPE nostop<br /> </code>如果连提示信息都不想看见，就可以这样设置:<code><br /> &nbsp;&nbsp; handle SIGPIPE nostop noprint<br /> </code>就可以了。其他相关信号也可以类似处理。想了解目前的signal状态可以使用<code>info signal</code>察看。</p> <p><strong>启动配置文件</strong><br /> GDB使用中比较麻烦的事情，就是每次启动，还要手动敲一把命令，特别是断点比较多的情况，这个特便影响，工作效率。查了一下gdb  info，gdb支持自动读取一个启动脚本文件.gdbinit，所以经常输入的启动命令，就都可以写在gdb启动目录的.gdbinit里面。比如<code><br /> .gdbinit:<br /> &nbsp;&nbsp; file myapp<br /> &nbsp;&nbsp; handle SIGPIPE nostop<br /> &nbsp;&nbsp; break ss.c:100<br /> &nbsp;&nbsp; break ss.c:200<br /> &nbsp;&nbsp; run<br /> </code>GDB和bash类似，也支持source这个命令，执行另外一个脚本文件。所以可以修改一下.gdbinit:<code><br /> .gdbinit:<br /> &nbsp;&nbsp; file myapp<br /> &nbsp;&nbsp; handle SIGPIPE nostop<br /> &nbsp;&nbsp; source gdb.break<br /> &nbsp;&nbsp; run<br /> gdb.break:<br /> &nbsp;&nbsp; break ss.c:100<br /> &nbsp;&nbsp; break ss.c:200<br /> </code>这样修改的断点配置，只需要编辑gdb.break就可以了。再后来，偶而还是需要单独启动GDB，不想执行自动脚本，于是又改进了一下。首先把.gdbinit命名为gdb.init，然后定义一个shell alias:<code><br /> &nbsp;&nbsp; $ alias .gdb=&#8221;gdb -x gdb.init&#8221;</code></p> <p>这样如果需要使用自动脚本，就用.gdb命令，否则用gdb进入交互状态的gdb。这样配置以后可以一个简单命令就开始调试，整个效率就能提高不少。</p> <p>注:转自<a style="font-weight: normal; font-size: 12px; color: #003300; line-height: 1.6em; text-decoration: none" href="http://blog.scaner.i.thu.cn/index.php/2006/04/15/gdb-tips-1/">http://blog.scaner.i.thu.cn/index.php/2006/04/15/gdb-tips-1/</a></p> <p>注解</p> <p>1<code>alias命令</code></p> <p><code><code>alias</code>顾名思义就是起别名的意思，在linux里，可以通过alias命令为常用命令设置快捷方式,命令格式如下： alias name='command' 例如：alias del='rm'</code></p> <div> <p>欲显示系统已有别名，直接使用 alias或alias -p</p> <p>若需要设置的命令别名比较多，可以直接修改/etc/bashrc或~/.bashrc，将需要的别名写到里面即可，不同之处是/etc/bashrc设置的别名对于所有登录用户都起作用，而~/.bashrc只对目前用户起作用。</p> </div> </span></span></div><img src ="http://www.cppblog.com/elva/aggbug/159457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-11-01 14:46 <a href="http://www.cppblog.com/elva/archive/2011/11/01/159457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c语言常量</title><link>http://www.cppblog.com/elva/archive/2011/01/26/139322.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 26 Jan 2011 03:14:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/01/26/139322.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/139322.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/01/26/139322.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/139322.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/139322.html</trackback:ping><description><![CDATA[常量只有四类：整型常量，浮点常量，枚举常量 和 字符常量。<br>
每类都有自己的一点规定，这个说起来比较扯，但记起来很容易：<br>
<br>
整型常量有三类：十、八、十六进制常量。<br>
&nbsp;&nbsp;&nbsp; 十进制的是指：非零数字起始的数字序列。<br>
&nbsp;&nbsp;&nbsp; 八进制：0起始的八进制数字序列。八进制数字是指 0-7 这八个数字<br>
&nbsp;&nbsp;&nbsp; 十六是：0x 或 0X 起始的十六进制数字序列。十六进制数字是指 0-9 a-f A-F 这些。<br>
&nbsp;&nbsp;&nbsp; 以上三类都可以追加整型后缀u, U, l, L, ll, LL 用以分别表示常量是 usigned, long, long-long 类型。<br>
<br>
浮点也有两类：一类是十进制浮点常量，另一个是十六进制浮点常量(这个不是很常用)。<br>
&nbsp;&nbsp;&nbsp; 十进制的有两种上表示方法：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一种借助小数点的：d.d&nbsp;&nbsp;&nbsp; .d&nbsp;&nbsp;&nbsp; d.&nbsp;&nbsp;&nbsp; 这三种形式。其中的 d 是数字序列的意思。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一种不用小数点，就必须给出指数部分(就是用科学记数法)。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;即使使用第一种方法，后面也可以再根指数部分，就是加个 e 或者 E 再可选地加一个正负号，再数字序列。<br>
&nbsp;&nbsp;&nbsp; 十六进制的，大体上差不多，但不管你前面有没有小数点，后面的指数部分都必须给出。用 p 或 P 代替 e E。<br>
&nbsp;&nbsp;&nbsp; 所有类型都可以加后缀 f F l L。<br>
<br>
枚举的一般不会考试出的，我想。它的语法也相对简单，就是加个 const 。我就不多说了。<br>
<br>
字符的其实最复杂。<br>
&nbsp;&nbsp;&nbsp; 简单的说就是用 '' 把数个(*见我后面的解释)字符括起来。比如 'a'。它也有两类，一个是所谓的普通字符常量。另一个(如果是应试的话其实可以无视)，是宽字符常量，区别就是前面给个缀L，比如 L'a'。<br>
&nbsp;&nbsp;&nbsp; 但是它有一些转义的规则。使得用文字描述起来超吃力，初学者也容易迷糊。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转义规则有三类：简单转义，八进制转义 和 十六进制转义。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;简单转义就是指&nbsp;&nbsp;\'&nbsp;&nbsp;\"&nbsp;&nbsp;\?&nbsp;&nbsp;\\&nbsp;&nbsp;\a \b \f \n \r \t \v 这么固定的几个。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;八进制是指 \ 后跟一至三个八进制数的形式，如 \1&nbsp;&nbsp;\12&nbsp;&nbsp;\ 123<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;十六进制是指 \x 后跟一个以上十六进制数字的形式，如 \xa \x123abc 这样的。但限制是追加的值不能超过 unsigned char 或者 wchar_t 表示的上限。<br>
&nbsp;&nbsp;&nbsp; 在语义上，一个字符常量的类型是 int 。<br>
<br><img src ="http://www.cppblog.com/elva/aggbug/139322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-01-26 11:14 <a href="http://www.cppblog.com/elva/archive/2011/01/26/139322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程程序中操作的原子性</title><link>http://www.cppblog.com/elva/archive/2011/01/21/139019.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 21 Jan 2011 05:47:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/01/21/139019.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/139019.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/01/21/139019.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/139019.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/139019.html</trackback:ping><description><![CDATA[转自：<br><a href="http://www.parallellabs.com/2010/04/15/atomic-operation-in-multithreaded-application/">http://www.parallellabs.com/2010/04/15/atomic-operation-in-multithreaded-application/</a><br><br>
<h3><span style="COLOR: #000000">0. 背景</span></h3>
<p><a style="COLOR: #551a8b" id=mpkc title=原子操作 onclick="javascript:_gaq.push(['_trackEvent','outbound-article','en.wikipedia.org']);" href="http://en.wikipedia.org/wiki/Atomic_operation">原子操作</a>就是不可再分的操作。在多线程程序中原子操作是一个非常重要的概念，它常常用来实现一些同步机制，同时也是一些常见的多线程Bug的源头。本文主要讨论了三个问题：1. 多线程程序中对变量的读写操作是否是原子的？2. 多线程程序中对Bit field（位域）的读写操作是否是线程安全的？3. 程序员该如何使用原子操作？</p>
<h3><span style="COLOR: #000000">1. 多线程环境下对变量的读写操作是否是原子的？</span></h3>
<p>我们先从一道很热门的百度笔试题讲起。很多人讲不清楚其背后的原理，下面我们就来对它进行一下剖析（其实这个题目有点歧义，后面我们会讲到）：</p>
<blockquote>
<p>以下多线程对int型变量x的操作，哪几个需要进行同步：（ ）<br>A. x=y; B. x++; C. ++x; D. x=1;</p>
</blockquote>
<p>要彻底理解这个问题，我们首先需要从硬件讲起。以常见的X86 CPU来说，根据Intel的<a style="COLOR: #551a8b" id=pvf3 title=参考手册 onclick="javascript:_gaq.push(['_trackEvent','outbound-article','download.intel.com']);" href="http://download.intel.com/design/processor/manuals/253668.pdf">参考手册</a>，它基于以下三种机制保证了多核中加锁的原子操作（8.1节）：<br>（1）Guaranteed atomic operations （注：8.1.1节有详细介绍）<br>（2）Bus locking, using the LOCK# signal and the LOCK instruction prefix<br>（3）Cache coherency protocols that ensure that atomic operations can be carried out on cached data structures (cache lock); this mechanism is present in the Pentium 4, Intel Xeon, and P6 family processors</p>
<p>这三个机制相互独立，相辅相承。简单的理解起来就是<br>（1）一些基本的内存读写操作是本身已经被硬件提供了原子性保证（例如读写单个字节的操作）；<br>（2）一些需要保证原子性但是没有被第（1）条机制提供支持的操作（例如read-modify-write）可以通过使用&#8221;LOCK#&#8221;来锁定总线，从而保证操作的原子性<br>（3）因为很多内存数据是已经存放在L1/L2 cache中了，对这些数据的原子操作只需要与本地的cache打交道，而不需要与总线打交道，所以CPU就提供了cache coherency机制来保证其它的那些也cache了这些数据的processor能读到最新的值（关于cache coherency可以参加我的<a style="COLOR: #551a8b" id=prz. title=一篇博文 href="http://www.parallellabs.com/2010/03/06/why-should-programmer-care-about-sequential-consistency-rather-than-cache-coherence/">一篇博文</a>）。</p>
<p>那么CPU对哪些（1）中的基本的操作提供了原子性支持呢？根据Intel手册8.1.1节的介绍：</p>
<p>从Intel486 processor开始，以下的基本内存操作是原子的：<br>&#8226; Reading or writing a byte（一个字节的读写）<br>&#8226; Reading or writing a word aligned on a 16-bit boundary（对齐到16位边界的字的读写）<br>&#8226; Reading or writing a doubleword aligned on a 32-bit boundary（对齐到32位边界的双字的读写）</p>
<p>从Pentium processor开始，除了之前支持的原子操作外又新增了以下原子操作：<br>&#8226; Reading or writing a quadword aligned on a 64-bit boundary（对齐到64位边界的四字的读写）<br>&#8226; 16-bit accesses to uncached memory locations that fit within a 32-bit data bus（未缓存且在32位数据总线范围之内的内存地址的访问）</p>
<p>从P6 family processors开始，除了之前支持的原子操作又新增了以下原子操作：<br>&#8226; Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache line（对单个cache line中缓存地址的未对齐的16/32/64位访问）</p>
<p>那么哪些操作是非原子的呢？<br>Accesses to cacheable memory that are split across bus widths, cache lines, and<br>page boundaries are not guaranteed to be atomic by the Intel Core 2 Duo, Intel&#174;<br>Atom&#8482;, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, P6 family, Pentium, and<br>Intel486 processors.（说点简单点，那些被总线带宽、cache line以及page大小给分隔开了的内存地址的访问不是原子的，你如果想保证这些操作是原子的，你就得求助于机制（2），对总线发出相应的控制信号才行）。</p>
<p>需要注意的是尽管从P6 family开始对一些非对齐的读写操作已经提供了原子性保障，但是非对齐访问是非常影响性能的，需要尽量避免。当然了，对于一般的程序员来说不需要太担心这个，因为大部分编译器会自动帮你完成内存对齐。</p>
<p>回到最开始那个笔试题。我们先反汇编一下看看它们到底执行了什么操作：</p>
<div>
<div id=highlighter_460976 class="syntaxhighlighter  cpp ie">
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">01</div>
            <div class="line number2 index1 alt1">02</div>
            <div class="line number3 index2 alt2">03</div>
            <div class="line number4 index3 alt1">04</div>
            <div class="line number5 index4 alt2">05</div>
            <div class="line number6 index5 alt1">06</div>
            <div class="line number7 index6 alt2">07</div>
            <div class="line number8 index7 alt1">08</div>
            <div class="line number9 index8 alt2">09</div>
            <div class="line number10 index9 alt1">10</div>
            <div class="line number11 index10 alt2">11</div>
            <div class="line number12 index11 alt1">12</div>
            <div class="line number13 index12 alt2">13</div>
            <div class="line number14 index13 alt1">14</div>
            <div class="line number15 index14 alt2">15</div>
            <div class="line number16 index15 alt1">16</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp plain"><font color=#d3d3d3>x = y; </font></code></div>
            <div class="line number2 index1 alt1"><code class="cpp plain"><font color=#d3d3d3>mov eax,dword ptr [y] </font></code></div>
            <div class="line number3 index2 alt2"><code class="cpp plain"><font color=#d3d3d3>mov dword ptr [x],eax </font></code></div>
            <div class="line number4 index3 alt1"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number5 index4 alt2"><code class="cpp plain"><font color=#d3d3d3>x++; </font></code></div>
            <div class="line number6 index5 alt1"><code class="cpp plain"><font color=#d3d3d3>mov eax,dword ptr [x] </font></code></div>
            <div class="line number7 index6 alt2"><code class="cpp plain"><font color=#d3d3d3>add eax,1 </font></code></div>
            <div class="line number8 index7 alt1"><code class="cpp plain"><font color=#d3d3d3>mov dword ptr [x],eax </font></code></div>
            <div class="line number9 index8 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number10 index9 alt1"><code class="cpp plain"><font color=#d3d3d3>++x; </font></code></div>
            <div class="line number11 index10 alt2"><code class="cpp plain"><font color=#d3d3d3>mov eax,dword ptr [x] </font></code></div>
            <div class="line number12 index11 alt1"><code class="cpp plain"><font color=#d3d3d3>add eax,1 </font></code></div>
            <div class="line number13 index12 alt2"><code class="cpp plain"><font color=#d3d3d3>mov dword ptr [x],eax </font></code></div>
            <div class="line number14 index13 alt1"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number15 index14 alt2"><code class="cpp plain"><font color=#d3d3d3>x = 1; </font></code></div>
            <div class="line number16 index15 alt1"><code class="cpp plain"><font color=#d3d3d3>mov dword ptr [x],1</font></code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>（1）很显然，x=1是原子操作。<br>因为x是int类型，32位CPU上int占32位，在X86上由硬件直接提供了原子性支持。实际上不管有多少个线程同时执行类似x=1这样的赋值语句，x的值最终还是被赋的值（而不会出现例如某个线程只更新了x的低16位然后被阻塞，另一个线程紧接着又更新了x的低24位然后又被阻塞，从而出现x的值被损坏了的情况）。</p>
<p>（2）再来看x++和++x。<br>其实类似x++, x+=2, ++x这样的操作在多线程环境下是需要同步的。因为X86会按三条指令的形式来处理这种语句：从内存中读x的值到寄存器中，对寄存器加1，再把新值写回x所处的内存地址（见上面的反汇编代码）。</p>
<p>例如有两个线程，它们按照如下顺序执行（注意读x和写回x是原子操作，两个线程不能同时执行）：</p>
<p>time &nbsp; &nbsp;Thread 1 &nbsp; &nbsp; &nbsp; &nbsp; Thread 2<br>0 &nbsp; &nbsp; &nbsp;load eax, x<br>1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;load eax, x<br>2 &nbsp; &nbsp; &nbsp;add eax, 1 &nbsp; &nbsp; &nbsp; &nbsp;add eax, 1<br>3 &nbsp; &nbsp; &nbsp;store x, eax<br>4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;store x, eax</p>
<p>我们会发现最终x的值会是1而不是2，因为Thread 1的结果被覆盖掉了。这种情况下我们就需要对x++这样的操作加锁（例如Pthread中的mutex）以保证同步，或者使用一些提供了atomic operations的库（例如Windows API中的<a style="COLOR: #551a8b" id=w3tu title=atomic库 onclick="javascript:_gaq.push(['_trackEvent','outbound-article','msdn.microsoft.com']);" href="http://msdn.microsoft.com/en-us/library/ms686360(VS.85).aspx">atomic库</a>，Linux内核中的<a style="COLOR: #551a8b" id=jbi8 title=atomic.h onclick="javascript:_gaq.push(['_trackEvent','outbound-article','lxr.linux.no']);" href="http://lxr.linux.no/linux+v2.6.26.5/include/asm-x86/atomic_32.h">atomic.h</a>，Java concurrent库中的Atomic Integer，C++0x中即将支持的atomic_int等等，这些库会利用CPU提供的硬件机制做一层封装，提供一些保证了原子性的API）。</p>
<p>（3）最后来看看x=y。<br>在X86上它包含两个操作：读取y至寄存器，再把该值写入x。读y的值这个操作本身是原子的，把值写入x也是原子的，但是两者合起来是不是原子操作呢？我个人认为x=y不是原子操作，因为它不是不可再分的操作。但是它需要不需要同步呢？其实问题的关键在于程序的上下文。</p>
<p>例如有两个线程，线程1要执行{y = 1; x = y;}，线程2要执行{y = 2; y = 3;}，假设它们按如下时间顺序执行：</p>
<p>time &nbsp; &nbsp;Thread 1 &nbsp; &nbsp; &nbsp; &nbsp;Thread 2<br>0 &nbsp; &nbsp; &nbsp; &nbsp;store y, 1<br>1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;store y, 2<br>2 &nbsp; &nbsp; &nbsp; &nbsp;load eax, y<br>3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;store y, 3<br>4 &nbsp; &nbsp; &nbsp; &nbsp;store x, eax</p>
<p>那么最终线程1中x的值为2，而不是它原本想要的1。我们需要加上相应的同步语句确保y = 2不会在线程1的两条语句之间发生。y = 3那条语句尽管在load y和store x之间执行，但是却不影响x=y这条语句本身的语义。所以你可以说x=y需要同步，也可以说x=y不需要同步，看你怎么理解题意了。x=1是否需要同步也是一样的道理，虽然它本身是原子操作，但是如果有另一个线程要读x=1之后的值，那肯定也需要同步，否则另一个线程读到的就是x的旧值而不是1了。</p>
<h3><span style="COLOR: #000000">2. 对Bit field（位域）的读写操作是否是线程安全的？</span></h3>
<p><a style="COLOR: #551a8b" id=spoi title="Bit field" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','learn.akae.cn']);" href="http://learn.akae.cn/media/ch19s04.html">Bit field</a>常用来高效的存储有限位数的变量，多用于内核/底层开发中。一般来说，对同一个结构体内的不同bit成员的多线程访问是无法保证线程安全的。</p>
<p>例如<a style="COLOR: #551a8b" id=s:v. title=WikiPedia onclick="javascript:_gaq.push(['_trackEvent','outbound-article','en.wikipedia.org']);" href="http://en.wikipedia.org/wiki/Bit_field">Wikipedia</a>中的如下例子：</p>
<div>
<div id=highlighter_960619 class="syntaxhighlighter  cpp ie">
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">01</div>
            <div class="line number2 index1 alt1">02</div>
            <div class="line number3 index2 alt2">03</div>
            <div class="line number4 index3 alt1">04</div>
            <div class="line number5 index4 alt2">05</div>
            <div class="line number6 index5 alt1">06</div>
            <div class="line number7 index6 alt2">07</div>
            <div class="line number8 index7 alt1">08</div>
            <div class="line number9 index8 alt2">09</div>
            <div class="line number10 index9 alt1">10</div>
            <div class="line number11 index10 alt2">11</div>
            <div class="line number12 index11 alt1">12</div>
            <div class="line number13 index12 alt2">13</div>
            <div class="line number14 index13 alt1">14</div>
            <div class="line number15 index14 alt2">15</div>
            <div class="line number16 index15 alt1">16</div>
            <div class="line number17 index16 alt2">17</div>
            <div class="line number18 index17 alt1">18</div>
            <div class="line number19 index18 alt2">19</div>
            <div class="line number20 index19 alt1">20</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp keyword bold"><strong><font color=#00ffff>struct</font></strong></code> <code class="cpp plain"><font color=#d3d3d3>foo { </font></code></div>
            <div class="line number2 index1 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp color1 bold"><strong><font color=#ebdb8d>int</font></strong></code> <code class="cpp plain"><font color=#d3d3d3>flag : 1; </font></code></div>
            <div class="line number3 index2 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp color1 bold"><strong><font color=#ebdb8d>int</font></strong></code> <code class="cpp plain"><font color=#d3d3d3>counter : 15; </font></code></div>
            <div class="line number4 index3 alt1"><code class="cpp plain"><font color=#d3d3d3>}; </font></code></div>
            <div class="line number5 index4 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number6 index5 alt1"><code class="cpp keyword bold"><strong><font color=#00ffff>struct</font></strong></code> <code class="cpp plain"><font color=#d3d3d3>foo my_foo; </font></code></div>
            <div class="line number7 index6 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number8 index7 alt1"><code class="cpp comments"><font color=#ff7d27>/* ... */</font></code></div>
            <div class="line number9 index8 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number10 index9 alt1"><code class="cpp comments"><font color=#ff7d27>/* in thread 1 */</font></code></div>
            <div class="line number11 index10 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number12 index11 alt1"><code class="cpp plain"><font color=#d3d3d3>pthread_mutex_lock(&amp;my_mutex_for_flag); </font></code></div>
            <div class="line number13 index12 alt2"><code class="cpp plain"><font color=#d3d3d3>my_foo.flag = !my_foo.flag; </font></code></div>
            <div class="line number14 index13 alt1"><code class="cpp plain"><font color=#d3d3d3>pthread_mutex_unlock(&amp;my_mutex_for_flag); </font></code></div>
            <div class="line number15 index14 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number16 index15 alt1"><code class="cpp comments"><font color=#ff7d27>/* in thread 2 */</font></code></div>
            <div class="line number17 index16 alt2"><code class="cpp spaces">&nbsp;</code>&nbsp;</div>
            <div class="line number18 index17 alt1"><code class="cpp plain"><font color=#d3d3d3>pthread_mutex_lock(&amp;my_mutex_for_counter); </font></code></div>
            <div class="line number19 index18 alt2"><code class="cpp plain"><font color=#d3d3d3>++my_foo.counter; </font></code></div>
            <div class="line number20 index19 alt1"><code class="cpp plain"><font color=#d3d3d3>pthread_mutex_unlock(&amp;my_mutex_for_counter);</font></code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>两个线程分别对my_foo.flag和my_foo.counter进行读写操作，但是即使有上面的加锁方式仍然不能保证它是线程安全的。原因在于不同的成员在内存中的具体排列方式&#8220;跟Byte Order、Bit Order、对齐等问题都有关，不同的平台和编译器可能会排列得很不一样，要编写可移植的代码就不能假定Bit-field是按某一种固定方式排列的&#8221;[3]。而且一般来讲CPU对内存操作的最小单位是<a style="COLOR: #551a8b" id=mmki title=word onclick="javascript:_gaq.push(['_trackEvent','outbound-article','en.wikipedia.org']);" href="http://en.wikipedia.org/wiki/Word_length">word</a>（X86的word是16bits），而不是1bit。这就是说，如果my_foo.flag和my_foo.counter存储在同一个word里，CPU在读写任何一个bit member的时候会同时把两个值一起读进寄存器，从而造成读写冲突。这个例子正确的处理方式是用一个mutex同时保护my_foo.flag和my_foo.counter，这样才能确保读写是线程安全的。</p>
<p>在<a style="COLOR: #551a8b" id=k.sc title=C++0x草案 onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.open-std.org']);" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf">C++0x草案</a>中对bit field是这样定义的：<br>连续的多个非0bit的bit fields是属于同一个memory location的；长度为0bit的bit field会把占单独的一个memory location。对同一个memory location的读写不是线程安全的；对不同memory location的读写是线程安全的。<br>例如在下图的例子中bf1和bf2是同一个memory location，bf3是一个单独的memory location，bf4是一个单独的memory location：<br><img class="size-full wp-image-508 alignnone" title="bit field" alt="bit field" src="http://www.parallellabs.com/wp-content/uploads/2010/04/bitfield.JPG" width=525 height=388></p>
<p>这里有一个因为Bit field不是线程安全所导致的一个Linux内核中的<a style="COLOR: #551a8b" id=bq8v title=bug onclick="javascript:_gaq.push(['_trackEvent','outbound-article','lkml.indiana.edu']);" href="http://lkml.indiana.edu/hypermail/linux/kernel/0810.1/0828.html">Bug</a>。</p>
<p>引用一下Pongba的<a style="COLOR: #551a8b" id=m40. title=总结 onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.newsmth.net']);" href="http://www.newsmth.net/bbscon.php?bid=335&amp;id=186723">总结</a>：</p>
<blockquote>
<p>所以，如果你的多个bitfields是连续的，同时又想要无冲突的读取它们，有两种做法，一是在中间用0大小bitfield隔开，但这种做法实际上就消除了bitfield的节省内存的初衷，因为为了使它们不冲突，至少被隔开的两个bitfield肯定不可能共享byte了。另一种做法当然就是用锁了。</p>
</blockquote>
<h3><span style="COLOR: #000000">3. 程序员该怎么用Atomic操作？</span></h3>
<p>一般情况下程序员不需要跟CPU提供的原子操作直接打交道，所以只需要选择语言或者平台提供的atomic API即可。而且使用封装好了的API还有一个好处是它们常常还提供了诸如compare_and_swap，fetch_and_add这样既有读又有写的较复杂操作的封装。</p>
<p>常见的API如下：</p>
<p>Windows上<a style="COLOR: #551a8b" id=fuwa title=InterlockedXXXX onclick="javascript:_gaq.push(['_trackEvent','outbound-article','msdn.microsoft.com']);" href="http://msdn.microsoft.com/en-us/library/ms686360(VS.85).aspx">InterlockedXXXX</a>的API<br>GNU/Linux上linux kernel中<a style="COLOR: #551a8b" id=k6en title=atomic_32.h onclick="javascript:_gaq.push(['_trackEvent','outbound-article','lxr.linux.no']);" href="http://lxr.linux.no/linux+v2.6.26.5/include/asm-x86/atomic_32.h">atomic_32.h</a><br>GCC中的<a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','gcc.gnu.org']);" href="http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html">Atomic Builtins</a> (__sync_fetch_and_add()等)<br>Java中的java.util.concurrent.atomic<br>C++0x中的<a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.open-std.org']);" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf">atomic operation</a><br>Intel TBB中的<a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','software.intel.com']);" href="http://software.intel.com/en-us/blogs/2007/09/12/threading-building-blocks-atomic-operations-introduction/">atomic operation</a></p>
<h3><span style="COLOR: #000000">4. 参考文献：</span></h3>
<p>[1]&nbsp;<a style="COLOR: #551a8b" title=关于变量操作的原子性(atomicity)FAQ onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.newsmth.net']);" href="http://www.newsmth.net/bbstcon.php?board=CPlusPlus&amp;gid=236548">关于变量操作的原子性(atomicity)FAQ</a><br>[2]&nbsp;<a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','en.wikipedia.org']);" href="http://en.wikipedia.org/wiki/Atomic_operation">http://en.wikipedia.org/wiki/Atomic_operation</a><br>[3]&nbsp;<a style="COLOR: #551a8b" title="关于内存对齐、bit field等" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','learn.akae.cn']);" href="http://learn.akae.cn/media/ch19s04.html">关于内存对齐、bit field等 &#8211;《Linux C编程一站式学习》</a><br>[4] <a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.alexonlinux.com']);" href="http://www.alexonlinux.com/do-you-need-mutex-to-protect-int">Do you need mutex to protect an &#8216;int&#8217;?</a><br>[5] <a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.amazon.com']);" href="http://www.amazon.com/C-Concurrency-Action-Practical-Multithreading/dp/1933988770/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1272232877&amp;sr=8-1">C++ Concurrency in Action</a><br>[6] <a style="COLOR: #551a8b" onclick="javascript:_gaq.push(['_trackEvent','outbound-article','www.alexonlinux.com']);" href="http://www.alexonlinux.com/multithreaded-simple-data-type-access-and-atomic-variables">Multithreaded simple data type access and atomic variables</a><br><span style="COLOR: #ffffff">[6] http://www.newsmth.net/bbscon.php?bid=335&amp;id=236629</span><span style="COLOR: #ffffff"><br>[7] </span><span style="COLOR: #ffffff">http://www.newsmth.net/bbscon.php?bid=335&amp;id=209239</span><span style="COLOR: #ffffff"><br>[8] </span><span style="COLOR: #ffffff">http://www.newsmth.net/bbscon.php?bid=335&amp;id=186723</span><br><span style="COLOR: #ffffff">转载请注明来自</span><a href="http://www.parallellabs.com/" target=_blank><span style="COLOR: #ffffff">parallellabs.com</span></a></p>
<img src ="http://www.cppblog.com/elva/aggbug/139019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-01-21 13:47 <a href="http://www.cppblog.com/elva/archive/2011/01/21/139019.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于多线程同步的问题</title><link>http://www.cppblog.com/elva/archive/2011/01/21/139014.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 21 Jan 2011 05:33:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/01/21/139014.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/139014.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/01/21/139014.html#Feedback</comments><slash:comments>-1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/139014.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/139014.html</trackback:ping><description><![CDATA[<p>今天 看到一道百度笔试题 <br>以下多线程对int型变量x的操作，哪几个需要进行同步： <br>A. x=y;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B. x++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C. ++x;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D. x=1; <br>&nbsp; <br>最初有人说选B 因为操作了2个寄存器。答案：ABC <br>&nbsp; <br>后面干脆将代码汇编了。 <br>得到 <br>x = y;<br>00411A25 mov eax,dword ptr [y] <br>00411A28 mov dword ptr [x],eax <br><br>x++;<br>00411A2B mov eax,dword ptr [x] <br>00411A2E add eax,1 <br>00411A31 mov dword ptr [x],eax <br><br>++x;<br>00411A34 mov eax,dword ptr [x] <br>00411A37 add eax,1 <br>00411A3A mov dword ptr [x],eax <br><br>x = 1;<br>00411A3D mov dword ptr [x],1<br>&nbsp; <br>我们看到ABC都对2个寄存器进行操作。 <br>&nbsp; <br>下表是一个多线程加锁的规律表&nbsp;<br>
<table style="WIDTH: 575px; BORDER-COLLAPSE: collapse; HEIGHT: 116px" border=1 cellSpacing=0 cellPadding=3>
    <tbody>
        <tr>
            <td style="WIDTH: 186px"></td>
            <td style="WIDTH: 194px; HEIGHT: 29px">&nbsp;操作的结果与初值无关</td>
            <td>&nbsp;操作的结果与初值相关 </td>
        </tr>
        <tr>
            <td>&nbsp;&nbsp;写简单数据类型</td>
            <td>&nbsp;不需要加锁①</td>
            <td style="HEIGHT: 30px">需要加锁② </td>
        </tr>
        <tr>
            <td>&nbsp;写复杂数据类型</td>
            <td>需要加锁③</td>
            <td style="HEIGHT: 29px">需要加锁④ </td>
        </tr>
        <tr>
            <td>&nbsp;读简单数据类型</td>
            <td>不需要加锁⑤</td>
            <td style="WIDTH: 191px; HEIGHT: 26px">不需要加锁⑥</td>
        </tr>
        <tr>
            <td>&nbsp;读复杂数据类型</td>
            <td>需要加锁⑦</td>
            <td>需要加锁⑧ </td>
        </tr>
    </tbody>
</table>
<br><br>&nbsp;&nbsp;&nbsp;写简单数据类型&nbsp; 不需要加锁①&nbsp; 需要加锁② <br>&nbsp;写复杂数据类型&nbsp; 需要加锁③&nbsp; 需要加锁④ <br>&nbsp;读简单数据类型&nbsp; 不需要加锁⑤&nbsp; 不需要加锁⑥ <br>&nbsp;读复杂数据类型&nbsp; 需要加锁⑦&nbsp; 需要加锁⑧ </p>
<p>&nbsp; <br>可以同样看到ABC都是写简单数据类型 并且操作的结果与初值相关。所以需要加锁。即要求同步</p>
<p><br>文章出处：飞诺网(<a href="http://www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/2008717/133440.html">www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/2008717/133440.html</a><br>&nbsp; <br>可以同样看到ABC都是写简单数据类型 并且操作的结果与初值相关。所以需要加锁。即要求同步</p>
<p>第2种情况的典型代表是&#8220;i++;&#8221;，需要对它加锁是因为它表面上虽然只有一条语句，却要执行至少两个操作，一是读出i的初始, 二是把加一后的结果写回去，两个操作就没有&#8220;原子性&#8221;了，所以需要加锁.</p>
<p><br>文章出处：飞诺网(<a href="http://www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/2008717/133440.html">www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/2008717/133440.html</a></p>
<img src ="http://www.cppblog.com/elva/aggbug/139014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-01-21 13:33 <a href="http://www.cppblog.com/elva/archive/2011/01/21/139014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++类型转换</title><link>http://www.cppblog.com/elva/archive/2011/01/20/138950.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 20 Jan 2011 02:08:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2011/01/20/138950.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/138950.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2011/01/20/138950.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/138950.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/138950.html</trackback:ping><description><![CDATA[<p>C++类型转换一共有4种：static_cast、const_cast、dynamic_cast、reinterpret_cast。</p>
<p>1、static_cast</p>
<p>用法：static_cast&lt;type-id&gt;(expression)</p>
<p>该运算符把expression转换为type-id类型，但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法：</p>
<p>①用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换（把子类的指针或引用转换成基类表示）是安全的；进行下行转换（把基类指针或引用转换成子类表示）时，由于没有动态类型检查，所以是不安全的。</p>
<p>②用于基本数据类型之间的转换，如把int转换成char，把int转换成enum。这种转换的安全性也要开发人员来保证。</p>
<p>③把空指针转换成目标类型的空指针。</p>
<p>④把任何类型的表达式转换成void类型。</p>
<p>注意：static_cast不能转换掉expression的const、volitale、或者__unaligned属性。</p>
<p>2、const_cast</p>
<p>用法：const_cast&lt;type_id&gt;(expression)</p>
<p>该运算符用来修改类型的const或volatile属性。除了const
或volatile修饰之外，type_id和expression的类型是一样的。常量指针被转化成非常量指针，并且仍然指向原来的对象；常量引用被转
换成非常量引用，并且仍然指向原来的对象；常量对象被转换成非常量对象。</p>
<p>3、dynamic_cast</p>
<p>用法：dynamic_cast&lt;type-id&gt;(expression)</p>
<p>该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void
*；如果type-id是类指针类型，那么expression也必须是一个指针，如果type-id是一个引用，那么expression也必须是一个
引用。</p>
<p>dynamic_cast主要用于类层次间的上行转换和下行转换，还可以用于类之间的交叉转换。在类层次间进行上行转换
时，dynamic_cast和static_cast的效果是一样的；在进行下行转换时，dynamic_cast具有类型检查的功能，比
static_cast更安全。</p>
<p>4、reinterpret_cast</p>
<p>用法：reinterpret_cast&lt;type-id&gt;(expression)</p>
<p>reinterpret_cast是C++里的强制类型转换符。操作符修改了操作数类型，但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。</p>
<p>使用注意：</p>
<p>1、static_cast转换的类型有限制，例如不能把int转成指针等。static_cast不能从表达式中去除const、volatile等属性。进行下行转换（把基类指针或引用转换成子类表示）时，由于没有动态类型检查，所以是不安全的。</p>
<p>2、const_cast只用来修改类型的const或volatile属性。</p>
<p>3、dynamic_cast主要用于类层次间的上行转换和下行转换，还可以用于类之间的交叉转换。有类型检查，失败的转换将返回空指针（当对指针进行类型转换时）或者抛出异常（当对引用进行类型转换时）。</p>
<p>4、reinterpret_cast不进行任何意义的二进制转换。reinterpret_cast只能在指针之间转换。</p>
<br><img src ="http://www.cppblog.com/elva/aggbug/138950.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2011-01-20 10:08 <a href="http://www.cppblog.com/elva/archive/2011/01/20/138950.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数模板和类模板</title><link>http://www.cppblog.com/elva/archive/2010/10/18/130292.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 18 Oct 2010 08:54:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/10/18/130292.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/130292.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/10/18/130292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/130292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/130292.html</trackback:ping><description><![CDATA[<div class=blog_content>
<p><span style="FONT-SIZE: medium"><strong><font size=3>模板</font></strong></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;模板(template)是一个将数据类型参化的工具,它提供了一种将代码与数据类相脱离的机制,即代码不受具体的数据类型的影响。模板分为函数模板和类模板两种。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)<span style="FONT-SIZE: medium"><font size=3>函数模板</font></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 函数模板是一种不说明某些参数的数据类型的函数。例如，下面定义了一个可对任何类型变量进行操作（求绝对值）的函数模板。</p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools>Cpp代码 <a title=复制代码 onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#" src_cetemp="http://www.cppblog.com/images/icon_copy.gif" icon_copy.gif? images www.cppblog.com http:></a></div>
</div>
<ol class=dp-cpp>
    <li><span><span>&nbsp;</span><span class=keyword><strong><font color=#7f0055>template</font></strong></span><span>&nbsp;&lt;</span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;T&gt;&nbsp;</span><span class=comment><font color=#008200>//或写成:template&nbsp;&lt;typename&nbsp;T&gt; </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;T&nbsp;abs(T&nbsp;val) &nbsp;&nbsp;</span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>return</font></strong></span><span>&nbsp;val&lt;0&nbsp;?&nbsp;-val&nbsp;:&nbsp;val; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre style="DISPLAY: none" class=cpp name="code"> template &lt;class T&gt; //或写成:template &lt;typename T&gt;
T abs(T val)
{
return val&lt;0 ? -val : val;
}
</pre>
<p>&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp; 在函数模板被调用时，编译器根据实际参数的类型确定模板参数T的类型，并自动生成一个对应的函数，即模板函数。模板参数的类型不同，生成的模板函数也不同。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例 1 函数模板的定义和使用</p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools>Cpp代码 <a title=复制代码 onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#" src_cetemp="http://www.cppblog.com/images/icon_copy.gif" icon_copy.gif? images www.cppblog.com http:></a></div>
</div>
<ol class=dp-cpp>
    <li><span><span class=preprocessor><font color=#808080>#include&nbsp;&lt;iostream.h&gt; </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>template</font></strong></span><span>&nbsp;&lt;</span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;T&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//定义模板 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>T&nbsp;abs(T&nbsp;val)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//定义函数模板 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>return</font></strong></span><span>&nbsp;val&lt;0&nbsp;?&nbsp;-val&nbsp;:&nbsp;val; &nbsp;&nbsp;</span></span>
    <li><span>} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>void</font></strong></span><span>&nbsp;main() &nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;i=100; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;abs(i)&lt;&lt;endl;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//类型参数T替换为int </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>long</font></strong></span><span>&nbsp;l=-12345L; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;abs(l)&lt;&lt;endl;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//类型参数T替换为long </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>float</font></strong></span><span>&nbsp;f=-125.78F; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;abs(f)&lt;&lt;endl;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//类型参数T替换为float </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre style="DISPLAY: none" class=cpp name="code">#include &lt;iostream.h&gt;
template &lt;class T&gt;			//定义模板
T abs(T val)				//定义函数模板
{
return val&lt;0 ? -val : val;
}
void main()
{
int i=100;
cout &lt;&lt;abs(i)&lt;&lt;endl;	//类型参数T替换为int
long l=-12345L;
cout &lt;&lt;abs(l)&lt;&lt;endl;	//类型参数T替换为long
float f=-125.78F;
cout &lt;&lt;abs(f)&lt;&lt;endl;	//类型参数T替换为float
}</pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 定义函数模板时也可以使用多个类型参数，这时每个类型参数前面都要加上关键字class或typename，其间用逗分隔，其形式如下所示。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template &lt;class T1,class T2,class T3&gt;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例 2 使用多个类型参数的函数模板</p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools>Cpp代码 <a title=复制代码 onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#" src_cetemp="http://www.cppblog.com/images/icon_copy.gif" icon_copy.gif? images www.cppblog.com http:></a></div>
</div>
<ol class=dp-cpp>
    <li><span><span class=preprocessor><font color=#808080>#include&nbsp;&lt;iostream.h&gt; </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>template</font></strong></span><span>&nbsp;&lt;</span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;T1,</span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;T2&gt; &nbsp;&nbsp;</span></span>
    <li><span>T1&nbsp;Max(T1&nbsp;x,T2&nbsp;y) &nbsp;&nbsp;</span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>return</font></strong></span><span>&nbsp;x&gt;y&nbsp;?&nbsp;x:&nbsp;(T1)y; &nbsp;&nbsp;</span></span>
    <li><span>} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>void</font></strong></span><span>&nbsp;main() &nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;i=100; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>float</font></strong></span><span>&nbsp;f=-125.78F; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;Max(i,f)&lt;&lt;endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//类型参数T1替换为int,T2替换为float </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre style="DISPLAY: none" class=cpp name="code">#include &lt;iostream.h&gt;
template &lt;class T1,class T2&gt;
T1 Max(T1 x,T2 y)
{
return x&gt;y ? x: (T1)y;
}
void main()
{
int i=100;
float f=-125.78F;
cout &lt;&lt;Max(i,f)&lt;&lt;endl;			//类型参数T1替换为int,T2替换为float
}</pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp; <span style="FONT-SIZE: medium"><font size=3>(2)类模板</font></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用多个类型参数的类模板</p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools>Cpp代码 <a title=复制代码 onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#" src_cetemp="http://www.cppblog.com/images/icon_copy.gif" icon_copy.gif? images www.cppblog.com http:></a></div>
</div>
<ol class=dp-cpp>
    <li><span><span class=preprocessor><font color=#808080>#include&nbsp;&lt;iostream.h&gt; </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>template</font></strong></span><span>&nbsp;&lt;</span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;T1,</span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;T2&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//使用2个类型参数 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>class</font></strong></span><span>&nbsp;MyTemClass&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//定义类模板 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>private</font></strong></span><span>: &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;T1&nbsp;x; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;T2&nbsp;y; &nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>public</font></strong></span><span>: &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;MyTemClass(T1&nbsp;a,T2&nbsp;b)&nbsp;{&nbsp;x=a;y=b;&nbsp;}&nbsp;&nbsp;</span><span class=comment><font color=#008200>//构造函数 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>void</font></strong></span><span>&nbsp;ShowMax()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//输出最大的数据成员 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;</span><span class=string><font color=#0000ff>"MaxMember="</font></span><span>&lt;&lt;(x&gt;y?x:y)&lt;&lt;endl; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>}; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>void</font></strong></span><span>&nbsp;main() &nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;a=100; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>float</font></strong></span><span>&nbsp;b=123.45F; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;MyTemClass&lt;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>,</span><span class=datatypes><strong><font color=#2e8b57>float</font></strong></span><span>&gt;&nbsp;mt(a,b);&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//声明类模板的对象 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;mt.ShowMax(); &nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre style="DISPLAY: none" class=cpp name="code">#include &lt;iostream.h&gt;
template &lt;class T1,class T2&gt;			//使用2个类型参数
class MyTemClass						//定义类模板
{
private:
T1 x;
T2 y;
public:
MyTemClass(T1 a,T2 b) { x=a;y=b; }	//构造函数
void ShowMax()						//输出最大的数据成员
{
cout &lt;&lt;"MaxMember="&lt;&lt;(x&gt;y?x:y)&lt;&lt;endl;
}
};
void main()
{
int a=100;
float b=123.45F;
MyTemClass&lt;int,float&gt; mt(a,b);	//声明类模板的对象
mt.ShowMax();
}
</pre>
<p>&nbsp;</p>
<br>原帖地址：<br><a href="http://fpwjp.javaeye.com/blog/377892">http://fpwjp.javaeye.com/blog/377892</a><br></div>
<img src ="http://www.cppblog.com/elva/aggbug/130292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-10-18 16:54 <a href="http://www.cppblog.com/elva/archive/2010/10/18/130292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在C函数中传递指向二维数组的指针参数</title><link>http://www.cppblog.com/elva/archive/2010/09/09/126259.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 09 Sep 2010 11:10:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/09/09/126259.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/126259.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/09/09/126259.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/126259.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/126259.html</trackback:ping><description><![CDATA[<p style="text-indent: 2em;">如何在C函数中传递指向二维数组的指针参数 </p>
<p style="text-indent: 2em;">[zz]<a  href="http://itrock.blog.ccidnet.com/blog-htm-do-showone-uid-255426-type-blog-itemid-717920.html">http://itrock.blog.ccidnet.com/blog-htm-do-showone-uid-255426-type-blog-itemid-717920.html</a></p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">前几日用C编写DSP程序时，遇到一个问题：如何向C函数中传递指向二维数组的指针参数。初
接触以为很简单，直接声明一个二维数组，然后把数组名传进去。但是一经编译便报错。后来仔细想了一下，并查找了一些相关资料，发现二维数组在概念上远比一
维数组复杂，或者说二维数组以一种晦涩的方式构建在一维数组之上。 </p>
<p style="text-indent: 2em;">先来回顾一下一维数组。一维数组的数组名即为指向该数组的指针，该指针值保存了数组存放在内
存中的一块连续区域的起始地址；数组的下标表示了这片内存区域的某存储区相对于起始地址的偏移量。简单来讲就是：指向一维数组的指针，指向数据存放区域的
起始位置。 </p>
<p style="text-indent: 2em;">事实上，计算机系统的多维数组其实最终还是以一维数组的形式实现的。就N x
M的二维数组来讲，设其数组名为array。指针array指向一个数组，该数组存放的是一系列指针，这些指针分别指向相应的一维数组，而这些数组中存放
的才是我们的数据。 </p>
<p style="text-indent: 2em;">array -&gt; [一维数组指针1] -&gt; &nbsp; [ 一维数组，M长] </p>
<p style="text-indent: 2em;">&nbsp; &nbsp; [一维数组指针2] -&gt; &nbsp; [ 一维数组，M长] </p>
<p style="text-indent: 2em;">&nbsp; &nbsp; &nbsp; &nbsp; &#8230;&#8230; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8230;&#8230; </p>
<p style="text-indent: 2em;">&nbsp; &nbsp; [一维数组指针N] -&gt; &nbsp; [ 一维数组，M长] </p>
<p style="text-indent: 2em;">由此array是第i个指针变量地址，array[j]则表示相对于第i个指针变量偏移
j*sizeof(数组类型)。系统通过这种机制访问了该二维数组的第i行，第j列的内容。 </p>
<p style="text-indent: 2em;">有上述可知，指向二维数组的指针其实是指向&#8220;指针变量地址&#8221;的指针变量。所以在声明指向二维
数组的指针时，用 int ** array的形式。</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; 有以下两种方式来对二维数组分配内存：</p>
<p style="text-indent: 2em;">///// 方法一</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; #include &lt;stdlib.h&gt; &nbsp; //
必须包含该头文件，里面定义了malloc的实现</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; int ** array = malloc( N * sizeof(int
*) );</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; for (int k=0;k&lt;N;k++)</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; &nbsp; array[k] = malloc( M * sizeof(int) );
&nbsp; </p>
<p style="text-indent: 2em;">///// 方法二</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; #include &lt;stdlib.h&gt;</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; int ** array = malloc( N * sizeof(int
*) );</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; array[0] = malloc( M * sizeof(int) );</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; for (int k=1;k&lt;N;k++)</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; &nbsp; array[k] = array[0]+M*k;</p>
<p style="text-indent: 2em;">&nbsp; &nbsp;
上述两种方法的区别在于：前者在内存中分配的区域有可能是不连续的；而后者则在内存中的一片连续区域为该数组分配空间。</p>
<p style="text-indent: 2em;">&nbsp; &nbsp;
我们还可以通过一维数组模拟二维数组。在这中间要进行下标转换。如对于模拟的NxM数组，访问其第i行，第j列元素时，在一维数组中对应的位置是
i*M+j。当然为了更简捷，我们可以把这个数组下标转换过程定义为一个宏，交由编译系统来处理。</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; #define Arr2 ( array_name, row,col ) &nbsp;
array_name[row*M+col]</p>
<p style="text-indent: 2em;">&nbsp; &nbsp; 定义该宏后，访问Arr2( array, i, j)等价于访问
array[i*M+j]。</p><img src ="http://www.cppblog.com/elva/aggbug/126259.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-09-09 19:10 <a href="http://www.cppblog.com/elva/archive/2010/09/09/126259.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread_kill</title><link>http://www.cppblog.com/elva/archive/2010/08/11/123091.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 11 Aug 2010 10:03:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/11/123091.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/123091.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/11/123091.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/123091.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/123091.html</trackback:ping><description><![CDATA[<div id="blog_text" class="cnt">
<p><strong> pthread_kill：</strong> </p>
<p>别被名字吓到，<font color="#ff00ff">pthread_kill可不是kill，而是向线程发送signal。</font>还记得signal吗，大部分signal的默认动作是终止进程的运行，所以，我们才要用signal()去抓信号并加上处理函数。</p>
<p>int pthread_kill(pthread_t thread, int sig);</p>
<p><font color="#ff00ff">向指定ID的线程发送sig信号，</font>如果线程代码内不做处理，则按照信号默认的行为影响整个进程，也就是说，<font color="#ff0000">如果你给一个线程发送了SIGQUIT，但线程却没有实现signal处理函数，则整个进程退出。</font></p>
<p><font color="#0000ff">pthread_kill(threadid, SIGKILL)也一样，杀死整个进程。<br>
如果要获得正确的行为，就需要在线程内实现signal(SIGKILL,sig_handler)了。</font></p>
<p><font color="#ff00ff">所以，如果int sig的参数不是0，那一定要清楚到底要干什么，而且一定要实现线程的信号处理函数，否则，就会影响整个进程。</font></p>
<p><br>
<font color="#ff00ff">OK，如果int sig是0呢，这是一个保留信号，一个作用是用来判断线程是不是还活着。</font></p>
<p><font color="#ff00ff">我们来看一下pthread_kill的返回值：<br>
成功:0<br>
线程不存在：ESRCH<br>
信号不合法：EINVAL</font></p>
<p>所以，pthread_kill(threadid,0)就很有用啦。</p>
<p>int kill_rc = pthread_kill(thread_id,0);</p>
<p>if(kill_rc == ESRCH)<br>
printf("the specified thread did not exists or already quit\n");<br>
else if(kill_rc == EINVAL)<br>
printf("signal is invalid\n");<br>
else<br>
printf("the specified thread is alive\n");</p>
<p>上述的代码就可以判断线程是不是还活着了。</p>
</div>
<br>转自：<br><a  href="http://hi.baidu.com/jesserei/blog/item/22184c2237206b49ac34deb8.html">http://hi.baidu.com/jesserei/blog/item/22184c2237206b49ac34deb8.html</a><br><br><img src ="http://www.cppblog.com/elva/aggbug/123091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-11 18:03 <a href="http://www.cppblog.com/elva/archive/2010/08/11/123091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Linux 的多线程编程的高效开发经验</title><link>http://www.cppblog.com/elva/archive/2010/08/09/122843.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 09 Aug 2010 13:08:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/09/122843.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/122843.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/09/122843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/122843.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/122843.html</trackback:ping><description><![CDATA[<p>2009 年  4 月  23 日</p>
<blockquote>本文中我们针对 Linux 上多线程编程的主要特性总结出 5 条经验，用以改善 Linux 多线程编程的习惯和避免其中的开发陷阱。在本文中，我们穿插一些 Windows 的编程用例用以对比 Linux 特性，以加深读者印象。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
<!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p><a name="1.背景|outline">背景</a></p>
<p>Linux 平台上的多线程程序开发相对应其他平台（比如 Windows）的多线程 API 有一些细微和隐晦的差别。不注意这些
Linux 上的一些开发陷阱，常常会导致程序问题不穷，死锁不断。本文中我们从 5 个方面总结出 Linux
多线程编程上的问题，并分别引出相关改善的开发经验，用以避免这些的陷阱。我们希望这些经验可以帮助读者们能更好更快的熟悉 Linux
平台的多线程编程。</p>
<p>我们假设读者都已经很熟悉 Linux 平台上基本的线程编程的 Pthread 库 API 。其他的第三方用以线程编程的库，如 boost，将不会在本文中提及。本文中主要涉及的题材包括线程开发中的线程管理，互斥变量，条件变量等。进程概念将不会在本文中涉及。</p>
<br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td>
        </tr>
    </tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/index.html#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name="2.Linux上线程开发API的概要介绍|outline">Linux 上线程开发 API 的概要介绍</a></p>
<p>多线程开发在 Linux 平台上已经有成熟的 Pthread
库支持。其涉及的多线程开发的最基本概念主要包含三点：线程，互斥锁，条件。其中，线程操作又分线程的创建，退出，等待 3 种。互斥锁则包括 4
种操作，分别是创建，销毁，加锁和解锁。条件操作有 5
种操作：创建，销毁，触发，广播和等待。其他的一些线程扩展概念，如信号灯等，都可以通过上面的三个基本元素的基本操作封装出来。</p>
<p>线程，互斥锁，条件在 Linux 平台上对应的 API 可以用表 1 归纳。为了方便熟悉 Windows 线程编程的读者熟悉 Linux 多线程开发的 API，我们在表中同时也列出 Windows SDK 库中所对应的 API 名称。</p>
<br><a name="表格1|table"><strong>表 1. 线程函数列表</strong></a><br>
<table class="data-table-1" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="text-align: left; vertical-align: top;">对象</td>
            <td style="text-align: left; vertical-align: top;">操作</td>
            <td style="text-align: left; vertical-align: top;">Linux Pthread API</td>
            <td style="text-align: left; vertical-align: top;">Windows SDK 库对应 API</td>
        </tr>
        <tr>
            <td rowspan="3" style="text-align: left; vertical-align: top;">线程</td>
            <td style="text-align: left; vertical-align: top;">创建</td>
            <td style="text-align: left; vertical-align: top;">pthread_create</td>
            <td style="text-align: left; vertical-align: top;">CreateThread</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">退出</td>
            <td style="text-align: left; vertical-align: top;">pthread_exit</td>
            <td style="text-align: left; vertical-align: top;">ThreadExit</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">等待</td>
            <td style="text-align: left; vertical-align: top;">pthread_join</td>
            <td style="text-align: left; vertical-align: top;">WaitForSingleObject</td>
        </tr>
        <tr>
            <td rowspan="4" style="text-align: left; vertical-align: top;">互斥锁</td>
            <td style="text-align: left; vertical-align: top;">创建</td>
            <td style="text-align: left; vertical-align: top;">pthread_mutex_init</td>
            <td style="text-align: left; vertical-align: top;">CreateMutex</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">销毁</td>
            <td style="text-align: left; vertical-align: top;">pthread_mutex_destroy</td>
            <td style="text-align: left; vertical-align: top;">CloseHandle</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">加锁</td>
            <td style="text-align: left; vertical-align: top;">pthread_mutex_lock</td>
            <td style="text-align: left; vertical-align: top;">WaitForSingleObject</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">解锁</td>
            <td style="text-align: left; vertical-align: top;">pthread_mutex_unlock</td>
            <td style="text-align: left; vertical-align: top;">ReleaseMutex</td>
        </tr>
        <tr>
            <td rowspan="5" style="text-align: left; vertical-align: top;">条件</td>
            <td style="text-align: left; vertical-align: top;">创建</td>
            <td style="text-align: left; vertical-align: top;">pthread_cond_init</td>
            <td style="text-align: left; vertical-align: top;">CreateEvent</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">销毁</td>
            <td style="text-align: left; vertical-align: top;">pthread_cond_destroy</td>
            <td style="text-align: left; vertical-align: top;">CloseHandle</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">触发</td>
            <td style="text-align: left; vertical-align: top;">pthread_cond_signal</td>
            <td style="text-align: left; vertical-align: top;">SetEvent</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">广播</td>
            <td style="text-align: left; vertical-align: top;">pthread_cond_broadcast</td>
            <td style="text-align: left; vertical-align: top;">SetEvent / ResetEvent</td>
        </tr>
        <tr>
            <td style="text-align: left; vertical-align: top;">等待</td>
            <td style="text-align: left; vertical-align: top;">pthread_cond_wait / pthread_cond_timedwait</td>
            <td style="text-align: left; vertical-align: top;">SingleObjectAndWait</td>
        </tr>
    </tbody>
</table>
<br>
<p>多线程开发在 Linux 平台上已经有成熟的 Pthread
库支持。其涉及的多线程开发的最基本概念主要包含三点：线程，互斥锁，条件。其中，线程操作又分线程的创建，退出，等待 3 种。互斥锁则包括 4
种操作，分别是创建，销毁，加锁和解锁。条件操作有 5
种操作：创建，销毁，触发，广播和等待。其他的一些线程扩展概念，如信号灯等，都可以通过上面的三个基本元素的基本操作封装出来。</p>
<br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td>
        </tr>
    </tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/index.html#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name="3.Linux线程编程中的5条经验|outline">Linux 线程编程中的 5 条经验</a></p>
<p><a name="N10193">尽量设置 recursive 属性以初始化 Linux 的互斥变量</a></p>
<p>互斥锁是多线程编程中基本的概念，在开发中被广泛使用。其调用次序层次清晰简单：建锁，加锁，解锁，销毁锁。但是需要注意的是，与诸如 Windows 平台的互斥变量不同，在默认情况下，Linux 下的同一线程无法对同一互斥锁进行递归加速，否则将发生死锁。</p>
<p>所谓递归加锁，就是在同一线程中试图对互斥锁进行两次或两次以上的行为。其场景在 Linux 平台上的代码可由清单 1 所示。</p>
<br><a name="N101A1"><strong>清单 1. Linux 重复对互斥锁加锁实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">// 通过默认条件建锁<br>    pthread_mutex_t *theMutex = new pthread_mutex_t; <br>    pthread_mutexattr_t attr; <br>    pthread_mutexattr_init(&amp;attr); <br>    pthread_mutex_init(theMutex,&amp;attr); <br>    pthread_mutexattr_destroy(&amp;attr); <br><br>    // 递归加锁<br>    pthread_mutex_lock (theMutex); <br>    pthread_mutex_lock (theMutex); <br>    pthread_mutex_unlock (theMutex); <br>    pthread_mutex_unlock (theMutex);</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>在以上代码场景中，问题将出现在第二次加锁操作。由于在默认情况下，Linux 不允许同一线程递归加锁，因此在第二次加锁操作时线程将出现死锁。</p>
<p>Linux 互斥变量这种奇怪的行为或许对于特定的某些场景会所有用处，但是对于大多数情况下看起来更像是程序的一个 bug 。毕竟，在同一线程中对同一互斥锁进行递归加锁在尤其是二次开发中经常会需要。</p>
<p>这个问题与互斥锁的中的默认 recursive 属性有关。解决问题的方法就是显式地在互斥变量初始化时将设置起 recursive 属性。基于此，以上代码其实稍作修改就可以很好的运行，只需要在初始化锁的时候加设置一个属性。请看清单 2 。</p>
<br><a name="N101B3"><strong>清单 2. 设置互斥锁 recursive 属性实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">pthread_mutexattr_init(&amp;attr); <br>    // 设置 recursive 属性<br>    pthread_mutexattr_settype(&amp;attr,PTHREAD_MUTEX_RECURSIVE_NP); <br>    pthread_mutex_init(theMutex,&amp;attr);</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>因此，建议尽量设置 recursive 属性以初始化 Linux 的互斥锁，这样既可以解决同一线程递归加锁的问题，又可以避免很多情况下死锁的发生。这样做还有一个额外的好处，就是可以让 Windows 和 Linux 下让锁的表现统一。</p>
<p><a name="N101BD">注意 Linux 平台上触发条件变量的自动复位问题</a></p>
<p>条件变量的置位和复位有两种常用模型：第一种模型是当条件变量置位（signaled）以后，如果当前没有线程在等待，其状态会保持为置位
（signaled），直到有等待的线程进入被触发，其状态才会变为复位（unsignaled），这种模型的采用以 Windows 平台上的
Auto-set Event 为代表。其状态变化如图 1 所示：</p>
<br><a name="N101C8"><strong>图 1. Windows 的条件变量状态变化流程</strong></a><br>
<img alt="Windows 的条件变量状态变化流程" src="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/images/image001.gif" height="154" width="526">
<br>
<p>第二种模型则是 Linux 平台的 Pthread 所采用的模型，当条件变量置位（signaled）以后，即使当前没有任何线程在等待，其状态也会恢复为复位（unsignaled）状态。其状态变化如图 2 所示：</p>
<br><a name="N101D9"><strong>图 2. Linux 的条件变量状态变化流程</strong></a><br>
<img alt="Linux 的条件变量状态变化流程" src="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/images/image002.gif" height="182" width="521">
<br>
<p>具体来说，Linux 平台上 Pthread 下的条件变量状态变化模型是这样工作的：调用 pthread_cond_signal()
释放被条件阻塞的线程时，无论存不存在被阻塞的线程，条件都将被重新复位，下一个被条件阻塞的线程将不受影响。而对于 Windows，当调用
SetEvent 触发 Auto-reset 的 Event
条件时，如果没有被条件阻塞的线程，那么条件将维持在触发状态，直到有新的线程被条件阻塞并被释放为止。</p>
<p>这种差异性对于那些熟悉 Windows 平台上的条件变量状态模型而要开发 Linux
平台上多线程的程序员来说可能会造成意想不到的尴尬结果。试想要实现一个旅客坐出租车的程序：旅客在路边等出租车，调用条件等待。出租车来了，将触发条
件，旅客停止等待并上车。一个出租车只能搭载一波乘客，于是我们使用单一触发的条件变量。这个实现逻辑在第一个模型下即使出租车先到，也不会有什么问题，
其过程如图 3 所示：</p>
<br><a name="N101ED"><strong>图 3. 采用 Windows 条件变量模型的出租车实例流程</strong></a><br><img alt="索引使用的容量要求" src="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/images/image003.gif" height="207" width="521">
<br>
<p>然而如果按照这个思路来在 Linux 上来实现，代码看起来可能是清单 3 这样。</p>
<br><a name="N101FF"><strong>清单 3. Linux 出租车案例代码实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&#8230;&#8230;<br> // 提示出租车到达的条件变量<br> pthread_cond_t taxiCond; <br><br> // 同步锁<br> pthread_mutex_t taxiMutex; <br><br> // 旅客到达等待出租车<br> void * traveler_arrive(void * name) { <br>    cout&lt;&lt; &#8221; Traveler: &#8221; &lt;&lt;(char *)name&lt;&lt; &#8221; needs a taxi now! &#8221; &lt;&lt;endl; <br>    pthread_mutex_lock(&amp;taxiMutex); <br>    pthread_cond_wait (&amp;taxiCond, &amp;taxtMutex); <br>    pthread_mutex_unlock (&amp;taxtMutex); <br>    cout&lt;&lt; &#8221; Traveler: &#8221; &lt;&lt; (char *)name &lt;&lt; &#8221; now got a taxi! &#8221; &lt;&lt;endl; <br>    pthread_exit( (void *)0 ); <br> } <br><br> // 出租车到达<br> void * taxi_arrive(void *name) { <br>    cout&lt;&lt; &#8221; Taxi &#8221; &lt;&lt;(char *)name&lt;&lt; &#8221; arrives. &#8221; &lt;&lt;endl; <br>    pthread_cond_signal(&amp;taxtCond); <br>    pthread_exit( (void *)0 ); <br> } <br><br> void main() {  <br>    // 初始化<br>    taxtCond= PTHREAD_COND_INITIALIZER; <br>    taxtMutex= PTHREAD_MUTEX_INITIALIZER; <br>    pthread_t thread; <br>    pthread_attr_t threadAttr; <br>    pthread_attr_init(&amp;threadAttr); <br><br>    pthread_create(&amp;thread, &amp; threadAttr, taxt_arrive, (void *)( &#8221; Jack &#8221; )); <br>    sleep(1); <br>    pthread_create(&amp;thread, &amp;threadAttr, traveler_arrive, (void *)( &#8221; Susan &#8221; )); <br>    sleep(1); <br>    pthread_create(&amp;thread, &amp;threadAttr, taxi_arrive, (void *)( &#8221; Mike &#8221; )); <br>    sleep(1); <br><br>    return 0; <br> }</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>好的，运行一下，看看结果如清单 4 。</p>
<br><a name="N1020B"><strong>清单 4. 程序结果输出</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">Taxi Jack arrives. <br>    Traveler Susan needs a taxi now! <br>    Taxi Mike arrives. <br>    Traveler Susan now got a taxi.</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>其过程如图 4 所示：</p>
<br><a name="N10217"><strong>图 4. 采用 Linux 条件变量模型的出租车实例流程</strong></a><br>
<img alt="图 4. 采用linux条件变量模型的出租车实例流程" src="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/images/image004.gif" height="202" width="516">
<br>
<p>通过对比结果，你会发现同样的逻辑，在 Linux 平台上运行的结果却完全是两样。对于在 Windows 平台上的模型一， Jack
开着出租车到了站台，触发条件变量。如果没顾客，条件变量将维持触发状态，也就是说 Jack 停下车在那里等着。直到 Susan
小姐来了站台，执行等待条件来找出租车。 Susan 搭上 Jack 的出租车离开，同时条件变量被自动复位。</p>
<p>但是到了 Linux 平台，问题就来了，Jack 到了站台一看没人，触发的条件变量被直接复位，于是 Jack
排在等待队列里面。来迟一秒的 Susan 小姐到了站台却看不到在那里等待的 Jack，只能等待，直到 Mike
开车赶到，重新触发条件变量，Susan 才上了 Mike 的车。这对于在排队系统前面的 Jack 是不公平的，而问题症结是在于 Linux
平台上条件变量触发的自动复位引起的一个 Bug 。</p>
<p>条件变量在 Linux
平台上的这种模型很难说好坏。但是在实际开发中，我们可以对代码稍加改进就可以避免这种差异的发生。由于这种差异只发生在触发没有被线程等待在条件变量的
时刻，因此我们只需要掌握好触发的时机即可。最简单的做法是增加一个计数器记录等待线程的个数，在决定触发条件变量前检查下该变量即可。改进后
Linux 函数如清单 5 所示。</p>
<br><a name="N1022E"><strong>清单 5. Linux 出租车案例代码实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&#8230;&#8230;<br> // 提示出租车到达的条件变量<br> pthread_cond_t taxiCond; <br><br> // 同步锁<br> pthread_mutex_t taxiMutex; <br><br> // 旅客人数，初始为 0 <br> int travelerCount=0; <br><br> // 旅客到达等待出租车<br> void * traveler_arrive(void * name) { <br>    cout&lt;&lt; &#8221; Traveler: &#8221; &lt;&lt;(char *)name&lt;&lt; &#8221; needs a taxi now! &#8221; &lt;&lt;endl; <br>    pthread_mutex_lock(&amp;taxiMutex); <br><br>    // 提示旅客人数增加<br>    travelerCount++; <br>    pthread_cond_wait (&amp;taxiCond, &amp;taxiMutex); <br>    pthread_mutex_unlock (&amp;taxiMutex); <br>    cout&lt;&lt; &#8221; Traveler: &#8221; &lt;&lt; (char *)name &lt;&lt; &#8221; now got a taxi! &#8221; &lt;&lt;endl; <br>    pthread_exit( (void *)0 ); <br> } <br><br> // 出租车到达<br> void * taxi_arrive(void *name) <br> { <br>    cout&lt;&lt; &#8221; Taxi &#8221; &lt;&lt;(char *)name&lt;&lt; &#8221; arrives. &#8221; &lt;&lt;endl; <br><br> while(true) <br> { <br>        pthread_mutex_lock(&amp;taxiMutex); <br><br>        // 当发现已经有旅客在等待时，才触发条件变量<br>        if(travelerCount&gt;0) <br>        { <br>            pthread_cond_signal(&amp;taxtCond); <br>            pthread_mutex_unlock (&amp;taxiMutex); <br>            break; <br>        } <br>        pthread_mutex_unlock (&amp;taxiMutex); <br>    } <br><br>    pthread_exit( (void *)0 ); <br> }</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>因此我们建议在 Linux 平台上要出发条件变量之前要检查是否有等待的线程，只有当有线程在等待时才对条件变量进行触发。</p>
<p><a name="N10238">注意条件返回时互斥锁的解锁问题</a></p>
<p>在 Linux 调用 pthread_cond_wait 进行条件变量等待操作时，我们增加一个互斥变量参数是必要的，这是为了避免线程间的竞争和饥饿情况。但是当条件等待返回时候，需要注意的是一定不要遗漏对互斥变量进行解锁。</p>
<p>Linux 平台上的 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t
*mutex) 函数返回时，互斥锁 mutex 将处于锁定状态。因此之后如果需要对临界区数据进行重新访问，则没有必要对 mutex
就行重新加锁。但是，随之而来的问题是，每次条件等待以后需要加入一步手动的解锁操作。正如前文中乘客等待出租车的 Linux 代码如清单 6 所示：</p>
<br><a name="N10246"><strong>清单 6. 条件变量返回后的解锁实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">void * traveler_arrive(void * name) { <br>    cout&lt;&lt; &#8221; Traveler: &#8221; &lt;&lt;(char *)name&lt;&lt; &#8221; needs a taxi now! &#8221; &lt;&lt;endl; <br>    pthread_mutex_lock(&amp;taxiMutex); <br>    pthread_cond_wait (&amp;taxiCond, &amp;taxtMutex); <br>    pthread_mutex_unlock (&amp;taxtMutex); <br>    cout&lt;&lt; &#8221; Traveler: &#8221; &lt;&lt; (char *)name &lt;&lt; &#8221; now got a taxi! &#8221; &lt;&lt;endl; <br>    pthread_exit( (void *)0 ); <br> }</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>这一点对于熟悉 Windows 平台多线程开发的开发者来说尤为重要。 Windows 上的
SignalObjectAndWait() 函数是常与 Linux 平台上的 pthread_cond_wait()
函数被看作是跨平台编程时的一对等价函数。但是需要注意的是，两个函数退出时的状态是不一样的。在 Windows
平台上，SignalObjectAndWait(HANDLE a, HANDLE b, &#8230;&#8230; ) 方法在调用结束返回时的状态是 a 和 b
都是置位（signaled）状态，在普遍的使用方法中，a 经常是一个 Mutex 变量，在这种情况下，当返回时，Mutex a
处于解锁状态（signaled），Event b 处于置位状态（signaled）, 因此，对于 Mutex a
而言，我们不需要考虑解锁的问题。而且，在 SignalObjectAndWait() 之后，如果需要对临界区数据进行重新访问，都需要调用
WaitForSingleObject() 重新加锁。这一点刚好与 Linux 下的 pthread_cond_wait() 完全相反。</p>
<p>Linux 对于 Windows 的这一点额外解锁的操作区别很重要，一定得牢记。否则从 Windows 移植到 Linux 上的条件等待操作一旦忘了结束后的解锁操作，程序将肯定会发生死锁。</p>
<p><a name="N10253">等待的绝对时间问题</a></p>
<p>超时是多线程编程中一个常见的概念。例如，当你在 Linux 平台下使用 pthread_cond_timedwait()
时就需要指定超时这个参数，以便这个 API 的调用者最多只被阻塞指定的时间间隔。但是如果你是第一次使用这个 API 时，首先你需要了解的就是这个
API 当中超时参数的特殊性（就如本节标题所提示的那样）。我们首先来看一下这个 API 的定义。
pthread_cond_timedwait() 定义请看清单 7 。</p>
<br><a name="N1025E"><strong>清单 7. pthread_cond_timedwait() 函数定义</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">int pthread_cond_timedwait(pthread_cond_t *restrict cond, <br>              pthread_mutex_t *restrict mutex, <br>              const struct timespec *restrict abstime);</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>参数 abstime
在这里用来表示和超时时间相关的一个参数，但是需要注意的是它所表示的是一个绝对时间，而不是一个时间间隔数值，只有当系统的当前时间达到或者超过
abstime 所表示的时间时，才会触发超时事件。这对于拥有 Windows 平台线程开发经验的人来说可能尤为困惑。因为 Windows
平台下所有的 API 等待参数（如 SignalObjectAndWait，等）都是相对时间，</p>
<p>假设我们指定相对的超时时间参数如 dwMilliseconds （单位毫秒）来调用和超时相关的函数，这样就需要将 dwMilliseconds 转化为 Linux 下的绝对时间参数 abstime 使用。常用的转换方法如清单 8 所示：</p>
<br><a name="N1026D"><strong>清单 8. 相对时间到绝对时间转换实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">/* get the current time */ <br>    struct timeval now; <br>    gettimeofday(&amp;now, NULL); <br>	<br>    /* add the offset to get timeout value */ <br>    abstime -&gt;tv_nsec = now.tv_usec * 1000 + (dwMilliseconds % 1000) * 1000000; <br>    abstime -&gt;tv_sec = now.tv_sec + dwMilliseconds / 1000;</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>Linux
的绝对时间看似简单明了，却是开发中一个非常隐晦的陷阱。而且一旦你忘了时间转换，可以想象，等待你的错误将是多么的令人头疼：如果忘了把相对时间转换成
绝对时间，相当于你告诉系统你所等待的超时时间是过去式的 1970 年 1 月 1 号某个时间段，于是操作系统毫不犹豫马上送给你一个
timeout 的返回值，然后你会举着拳头抱怨为什么另外一个同步线程耗时居然如此之久，并一头扎进寻找耗时原因的深渊里。</p>
<p><a name="N10277">正确处理 Linux 平台下的线程结束问题</a></p>
<p>在 Linux 平台下，当处理线程结束时需要注意的一个问题就是如何让一个线程善始善终，让其所占资源得到正确释放。在 Linux
平台默认情况下，虽然各个线程之间是相互独立的，一个线程的终止不会去通知或影响其他的线程。但是已经终止的线程的资源并不会随着线程的终止而得到释放，
我们需要调用 pthread_join() 来获得另一个线程的终止状态并且释放该线程所占的资源。 Pthread_join() 函数的定义如清单
9 。</p>
<br><a name="N10282"><strong>清单 9. pthread_join 函数定义</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">int pthread_join(pthread_t th, void **thread_return);</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>调用该函数的线程将挂起，等待 th 所表示的线程的结束。 thread_return 是指向线程 th 返回值的指针。需要注意的是
th 所表示的线程必须是 joinable 的，即处于非 detached（游离）状态；并且只可以有唯一的一个线程对 th 调用
pthread_join() 。如果 th 处于 detached 状态，那么对 th 的 pthread_join() 调用将返回错误。</p>
<p>如果你压根儿不关心一个线程的结束状态，那么也可以将一个线程设置为 detached
状态，从而来让操作系统在该线程结束时来回收它所占的资源。将一个线程设置为 detached 状态可以通过两种方式来实现。一种是调用
pthread_detach() 函数，可以将线程 th 设置为 detached 状态。其申明如清单 10 。</p>
<br><a name="N10291"><strong>清单 10. pthread_detach 函数定义</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">int pthread_detach(pthread_t th);</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>另一种方法是在创建线程时就将它设置为 detached 状态，首先初始化一个线程属性变量，然后将其设置为 detached
状态，最后将它作为参数传入线程创建函数 pthread_create()，这样所创建出来的线程就直接处于 detached 状态。方法如清单
11 。</p>
<br><a name="N1029D"><strong>清单 11. 创建 detach 线程代码实例</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230; .. <br>    pthread_t       tid; <br>    pthread_attr_t  attr; <br>    pthread_attr_init(&amp;attr); <br>    pthread_attr_setdetachstate(&amp;attr, PTHREAD_CREATE_DETACHED); <br>    pthread_create(&amp;tid, &amp;attr, THREAD_FUNCTION, arg);</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>总之为了在使用 Pthread 时避免线程的资源在线程结束时不能得到正确释放，从而避免产生潜在的内存泄漏问题，在对待线程结束时，要确保该线程处于 detached 状态，否着就需要调用 pthread_join() 函数来对其进行资源回收。</p>
<br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td>
        </tr>
    </tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/index.html#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name="4.总结与补充|outline">总结与补充</a></p>
<p>本文以上部分详细介绍了 Linux 的多线程编程的 5 条高效开发经验。另外你也可以考虑尝试其他一些开源类库来进行线程开发。</p>
<p>1. Boost 库</p>
<p>Boost 库来自于由 C++ 标准委员会类库工作组成员发起，致力于为 C++ 开发新的类库的 Boost
组织。虽然该库本身并不是针对多线程而产生，但是发展至今，其已提供了比较全面的多线程编程的 API 支持。 Boost 库对于多线程支持的 API
风格上更类似于 Linux 的 Pthread 库，差别在于其将线程，互斥锁，条件等线程开发概念都封装成了 C++ 类，以方便开发调用。
Boost 库目前对跨平台支持的很不错，不仅支持 Windows 和 Linux ，还支持各种商用的 Unix
版本。如果开发者想使用高稳定性的统一线程编程接口减轻跨平台开发的难度， Boost 库将是首选。</p>
<p>2. ACE</p>
<p>ACE 全称是 ADAPTIVE Communication
Environment，它是一个免费的，开源的，面向对象的工具框架，用以开发并发访问的软件。由于 ACE
最初是面向网络服务端的编程开发，因此对于线程开发的工具库它也能提供很全面的支持。其支持的平台也很全面，包括 Windows，Linux
和各种版本  Unix 。 ACE
的唯一问题是如果仅仅是用于线程编程，其似乎显得有些过于重量级。而且其较复杂的配置也让其部署对初学者而言并非易事。</p>
<br>原文地址：<br><a  href="http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/index.html">http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/index.html</a><br><br><img src ="http://www.cppblog.com/elva/aggbug/122843.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-09 21:08 <a href="http://www.cppblog.com/elva/archive/2010/08/09/122843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于DBG加载core文件</title><link>http://www.cppblog.com/elva/archive/2010/08/06/122421.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 06 Aug 2010 04:03:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/06/122421.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/122421.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/06/122421.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/122421.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/122421.html</trackback:ping><description><![CDATA[<div class="SECT1" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 19px; "><h1 class="SECT1" style="color: rgb(153, 0, 0); line-height: 1.3; margin-left: -41px; margin-top: 0.8em; margin-right: 0px; margin-bottom: 0px; "><a id="DEBUGGING" name="DEBUGGING">2.6 调试</a></h1><div class="SECT2" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><h2 class="SECT2" style="color: rgb(153, 0, 0); line-height: 1.3; margin-left: -41px; margin-top: 0.8em; margin-right: 0px; margin-bottom: 0px; "><a id="AEN930" name="AEN930">2.6.1 调试器</a></h2><p>　　FreeBSD 自带的调试器叫&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;(<strong class="APPLICATION" style="color: rgb(0, 0, 0); ">GNU debugger</strong>)。要运行，输入</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; "><samp class="PROMPT">%</samp> <kbd class="USERINPUT">gdb <tt class="REPLACEABLE"><em>progname</em></tt></kbd>
</pre><p>　　然而大多数人喜欢在&nbsp;<strong class="APPLICATION" style="color: rgb(0, 0, 0); ">Emacs</strong>&nbsp;中运行这个命令。 可以这样来起动这个命令：</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; "><kbd class="USERINPUT">M-x gdb RET <tt class="REPLACEABLE"><em>progname</em></tt> RET</kbd>
</pre><p>　　调试器能让你在一个可控制的环境中运行一个程序。例如，你可以一次运行程 序的一行代码，检查变量的值，改变这些值，或者让程序运行到某个定点然后停止等 等。你甚至可以调试内核，当然这样会比我们将要讨论的问题要多一点点技巧。</p><p>　　<tt class="COMMAND">gdb</tt>&nbsp;有非常棒的在线帮助，还有同样棒的 info 页面。 因此这一章我们会把注意力集中到一些基本的命令上。</p><p>　　最后，如果你不习惯这个命令的命令行界面，在 Ports 中还有一个它的图形 前端 (<a href="http://www.freebsd.org/cgi/url.cgi?ports/devel/xxgdb/pkg-descr"><tt class="FILENAME" style="color: rgb(0, 122, 0); ">devel/xxgdb</tt></a>)。</p><p>　　这一章准备只介绍&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;的使用方法，而不会牵涉到特殊 的问题比如调试内核。</p></div><div class="SECT2" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><h2 class="SECT2" style="color: rgb(153, 0, 0); line-height: 1.3; margin-left: -41px; margin-top: 0.8em; margin-right: 0px; margin-bottom: 0px; "><a id="AEN951" name="AEN951">2.6.2 在调试器中运行一个程序</a></h2><p>　　要最大限度的利用&nbsp;<tt class="COMMAND">gdb</tt>，需要使用&nbsp;<code class="OPTION">-g</code>&nbsp;这个选项来编译你的程序。如果你没有这样做，那么你只会看 到你正在调试的函数名字，而不是它的源代码。如果&nbsp;<tt class="COMMAND">gdb</tt>起动 时提示：</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; ">... (no debugging symbols found) ...
</pre><p>　　你就知道你的程序在编译的时候没有使用&nbsp;<code class="OPTION">-g</code>&nbsp;选项。</p><p>　　当&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;给出提示符，输入&nbsp;<kbd class="USERINPUT">break main</kbd>。 这就是告诉调试器你对正在运行的程序中预先设置的代码没有兴趣， 并且调试器应该停在你的代码的开头。然后输入&nbsp;<kbd class="USERINPUT">run</kbd>&nbsp;来开始你的程序──这会从 预先设置的代码开始然后在调试器调用&nbsp;<code class="FUNCTION">main()</code>&nbsp;的时候就停 下来。(如果你曾迷惑&nbsp;<code class="FUNCTION">main()</code>&nbsp;是在哪里被调用的，现在应该 明白了吧！)</p><p>　　现在你可以一步一步来检查你的程序，按下&nbsp;<tt class="COMMAND">n</tt>一次就查 一行。一旦你碰见了一个函数调用，可以输入&nbsp;<tt class="COMMAND">f</tt>&nbsp;从函数调用中 退出来。你可以输入&nbsp;<tt class="COMMAND">up</tt>或&nbsp;<tt class="COMMAND">down</tt>&nbsp;来快速 检查这个调用。</p><p>　　这里列出了一个简单的例子。展示了怎样用&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;定位一个错 误。这是我们的程序(其中有一个明显的错误)：</p><pre class="PROGRAMLISTING" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; background-color: rgb(238, 238, 238); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); ">#include &lt;stdio.h&gt;

int bazz(int anint);

main() {
    int i;

    printf("This is my program\n");
    bazz(i);
    return 0;
}

int bazz(int anint) {
    printf("You gave me %d\n", anint);
    return anint;
}
</pre><p>　　这个程序给&nbsp;<code class="SYMBOL">i</code>&nbsp;赋值&nbsp;<tt class="LITERAL">5</tt>&nbsp;并把它传递给 一个函数&nbsp;<code class="FUNCTION">bazz()</code>，这个函数将打印出我们给出的数值。</p><p>　　我们现在编译并运行这个程序，我们会得到</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; "><samp class="PROMPT">%</samp> <kbd class="USERINPUT">cc -g -o temp temp.c</kbd>
<samp class="PROMPT">%</samp> <kbd class="USERINPUT">./temp</kbd>
This is my program
anint = 4231
</pre><p>　　但这并不是我们想要的！应该看看到底发生了什么！</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; "><samp class="PROMPT">%</samp> <kbd class="USERINPUT">gdb temp</kbd>
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc.
(gdb) <kbd class="USERINPUT">break main</kbd>               Skip the set-up code
Breakpoint 1 at 0x160f: file temp.c, line 9.    <tt class="COMMAND">gdb</tt> puts breakpoint at <code class="FUNCTION">main()</code>
(gdb) <kbd class="USERINPUT">run</kbd>                   Run as far as <code class="FUNCTION">main()</code>
Starting program: /home/james/tmp/temp      Program starts running

Breakpoint 1, main () at temp.c:9       <tt class="COMMAND">gdb</tt> stops at <code class="FUNCTION">main()</code>
(gdb) <kbd class="USERINPUT">n</kbd>                       Go to next line
This is my program              Program prints out
(gdb) <kbd class="USERINPUT">s</kbd>                       step into <code class="FUNCTION">bazz()</code>
bazz (anint=4231) at temp.c:17          <tt class="COMMAND">gdb</tt> displays stack frame
(gdb)
</pre><p>　　停住！怎么&nbsp;<code class="SYMBOL">anint</code>&nbsp;会是&nbsp;<tt class="LITERAL">4231</tt>？难道 我们没有在函数&nbsp;<code class="FUNCTION">main()</code>&nbsp;中设定为&nbsp;<tt class="LITERAL">5</tt>&nbsp;吗？现在我们转到&nbsp;<code class="FUNCTION">main()</code>&nbsp;来看看。</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; ">(gdb) <kbd class="USERINPUT">up</kbd>                   Move up call stack
#1  0x1625 in main () at temp.c:11      <tt class="COMMAND">gdb</tt> displays stack frame
(gdb) <kbd class="USERINPUT">p i</kbd>                   Show us the value of <code class="SYMBOL">i</code>
$1 = 4231                   <tt class="COMMAND">gdb</tt> displays <tt class="LITERAL">4231</tt>
</pre><p>　　哦，天哪！看看这代码，我们忘了初始化&nbsp;<code class="SYMBOL">i</code>&nbsp;了。本来我们 是想的</p><pre class="PROGRAMLISTING" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; background-color: rgb(238, 238, 238); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); ">...
main() {
    int i;

    i = 5;
    printf("This is my program\n");
...
</pre><p>　　但是我们忘了&nbsp;<tt class="LITERAL">i=5;</tt>&nbsp;这一行。因为我们没有初始化&nbsp;<code class="SYMBOL">i</code>，这个变量在程序运行的时候就储存了偶然在那块内存中存在的 任意值。</p><div class="NOTE" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><blockquote class="NOTE" style="margin-top: 0.75em; line-height: 1.5; margin-bottom: 0.75em; color: rgb(34, 34, 34); background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(238, 238, 238); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); padding-top: 0.4em; padding-right: 0.4em; padding-bottom: 0.4em; padding-left: 0.4em; width: 880px; background-position: initial initial; background-repeat: initial initial; "><p><strong>注意:</strong>&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;会显示我们进入或离开一个函数时的栈的值。即 使是我们在使用&nbsp;<tt class="COMMAND">up</tt>&nbsp;或&nbsp;<tt class="COMMAND">down</tt>&nbsp;的时候。 这会显示函数的名称还有参数的值，让我们知道自己的位置以及正在发生什么事情。 (栈能储存程序在调用函数的时使用的参数，以及调用时的位置，以便程序在从函 数调用结束后知道自己的位置。)</p></blockquote></div></div><div class="SECT2" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><h2 class="SECT2" style="color: rgb(153, 0, 0); line-height: 1.3; margin-left: -41px; margin-top: 0.8em; margin-right: 0px; margin-bottom: 0px; "><a id="AEN1038" name="AEN1038">2.6.3 检查 core 文件</a></h2><p>　　基本上 core 文件就是一个包含了程序崩溃时这个进程的所有信息的文件。在那 &#8220;遥远的黄金年代&#8221;，程序员不得不把 core 文件以十六进制的方式显示 出来，然后满头大汗的阅读机器码的手册，但是现在事情就简单得多了。顺便说一下， 在 FreeBSD 和其他的 4.4BSD 系统下，core 文件都叫作&nbsp;<tt class="FILENAME" style="color: rgb(0, 122, 0); "><tt class="REPLACEABLE"><em>progname</em></tt>.core</tt>&nbsp;而不是简单叫&nbsp;<tt class="FILENAME" style="color: rgb(0, 122, 0); ">core</tt>，这样可以很清楚的表示出这个 core 文件是属于哪个 程序。</p><p>　　要检查一个 core 文件，以通常的方式起动&nbsp;<tt class="COMMAND">gdb</tt>。不要 输入&nbsp;<tt class="COMMAND">break</tt>&nbsp;或者&nbsp;<tt class="COMMAND">run</tt>，而要输入</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; ">(gdb) <kbd class="USERINPUT">core <tt class="REPLACEABLE"><em>progname</em></tt>.core</kbd>
</pre><p>　　如果你没有和 core 文件在同一个目录，首先要执行&nbsp;<kbd class="USERINPUT">dir /path/to/core/file</kbd>。</p><p>　　你应该可以看见：</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; "><samp class="PROMPT">%</samp> <kbd class="USERINPUT">gdb a.out</kbd>
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc.
(gdb) <kbd class="USERINPUT">core a.out.core</kbd>
Core was generated by `a.out'.
Program terminated with signal 11, Segmentation fault.
Cannot access memory at address 0x7020796d.
#0  0x164a in bazz (anint=0x5) at temp.c:17
(gdb)
</pre><p>　　这种情况下，运行的程序叫&nbsp;<tt class="FILENAME" style="color: rgb(0, 122, 0); ">a.out</tt>，因此 core 文件 就叫&nbsp;<tt class="FILENAME" style="color: rgb(0, 122, 0); ">a.out.core</tt>。我们知道程序崩溃的原因就是函数&nbsp;<code class="FUNCTION">bazz</code>&nbsp;试图访问一块不属于它的内存。</p><p>　　有时候，能知道一个函数是怎么被调用的是非常有用处的。因为在一个复杂的 程序里面问题可能会发生在函数调用栈上面很远的地方。命令<tt class="COMMAND">bt</tt>&nbsp;会让&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;输出函数调用栈的回溯追踪。</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; ">(gdb) <kbd class="USERINPUT">bt</kbd>
#0  0x164a in bazz (anint=0x5) at temp.c:17
#1  0xefbfd888 in end ()
#2  0x162c in main () at temp.c:11
(gdb)
</pre><p>　　函数&nbsp;<code class="FUNCTION">end()</code>&nbsp;在一个程序崩溃的时候将被调用；在本例 中，函数&nbsp;<code class="FUNCTION">bazz()</code>&nbsp;是从&nbsp;<code class="FUNCTION">main()</code>&nbsp;中被 调用的。</p></div><div class="SECT2" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><h2 class="SECT2" style="color: rgb(153, 0, 0); line-height: 1.3; margin-left: -41px; margin-top: 0.8em; margin-right: 0px; margin-bottom: 0px; "><a id="AEN1072" name="AEN1072">2.6.4 粘付到一个正在运行的程序</a></h2><p>　　<tt class="COMMAND">gdb</tt>&nbsp;一个最精致的特性就是它能粘付到一个已经在运行 的程序上。当然，我们得首先假定你有足够的权限这样去做。一个常见的问题就是， 当我们在追踪一个包含子进程的程序时，如果你要追踪子进程，但是调试器只允许你 追踪父进程。</p><p>　　你要做的就是起动另一个&nbsp;<tt class="COMMAND">gdb</tt>，然后用&nbsp;<tt class="COMMAND">ps</tt>&nbsp;找出子进程的进程号。然后在&nbsp;<tt class="COMMAND">gdb</tt>中执行</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; ">(gdb) <kbd class="USERINPUT">attach <tt class="REPLACEABLE"><em>pid</em></tt></kbd>
</pre><p>　　就可以像平时一样调试了。</p><p>　　&#8220;这很好，&#8221;你可能在想，&#8220;当我这样做了以后，子进程就 会不见了&#8221;。别怕，亲爱的读者，我们可以这样来做(参照&nbsp;<tt class="COMMAND">gdb</tt>&nbsp;的 info 页)</p><pre class="SCREEN" style="margin-top: 0.75em; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; line-height: 1; font-family: monospace; padding-top: 1ex; padding-right: 1ex; padding-bottom: 1ex; padding-left: 1ex; ">...
if ((pid = fork()) &lt; 0)      /* _Always_ check this */
    error();
else if (pid == 0) {        /* child */
    int PauseMode = 1;

    while (PauseMode)
        sleep(10);  /* Wait until someone attaches to us */
    ...
} else {            /* parent */
    ...
</pre><p>　　现在所有你要做的就是粘付到子进程，设置&nbsp;<code class="SYMBOL">PauseMode</code>&nbsp;为&nbsp;<tt class="LITERAL">0</tt>，然后等待函数&nbsp;<code class="FUNCTION">sleep</code>&nbsp;返回！</p></div></div><div class="NAVFOOTER" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 19px; "></div>
<img src ="http://www.cppblog.com/elva/aggbug/122421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-06 12:03 <a href="http://www.cppblog.com/elva/archive/2010/08/06/122421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GDB（GNU 项目调试器）</title><link>http://www.cppblog.com/elva/archive/2010/08/05/122338.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 05 Aug 2010 10:05:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/05/122338.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/122338.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/05/122338.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/122338.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/122338.html</trackback:ping><description><![CDATA[GDB（GNU 项目调试器）可以让您了解程序在执行时&#8220;内部&#8221; 究竟在干些什么，以及在程序发生崩溃的瞬间正在做什么。<br>GDB 做以下 4 件主要的事情来帮助您捕获程序中的 bug：<br>l<br>在程序启动之前指定一些可以影响程序行为的变量或条件 <br>l<br>在某个指定的地方或条件下暂停程序 <br>l<br>在程序停止时检查已经发生了什么 <br>l<br>在程序执行过程中修改程序中的变量或条件，这样就可以体验修复一个 bug 的成果，并继续了解其他 bug<br><br>要调试的程序可以是使用 C、C++、Pascal、Objective-C 以及其他很多语言编写的。GDB 的二进制文件名是 gdb。<br>gdb 中有很多命令。使用help命令可以列出所有的命令，以及关于如何使用这些命令的介绍。下表给出了最常用的 GDB 命令。<br><br>表 1. gdb 中最常用的命令<br>命令<br>说明<br>例子<br>help<br>显示命令类别<br>help- 显示命令类别<br>help breakpoints- 显示属于 breakpoints 类别的命令<br>help break- 显示 break 命令的解释<br>run<br>启动所调试的程序<br>?<br>kill<br>终止正在调试的程序的执行<br>通常这会在要执行的代码行已经超过了您想要调试的代码时使用。执行kill会重置断点，并从头再次运行这个程序<br><br><br><br>cont<br>所调试的程序运行到一个断点、异常或单步之后，继续执行<br>?<br>info break<br>显示当前的断点或观察点<br>?<br>break<br>在指定的行或函数处设置断点<br>break 93 if i=8- 当变量 i 等于 8 时，在第 93 行停止程序执行<br>Step<br>单步执行程序，直到它到达一个不同的源代码行。您可以使用s来代表 step 命令<br>?<br>Next<br>与 step 命令类似，只是它不会&#8220;单步跟踪到&#8221;子例程中<br>?<br>print<br>打印一个变量或表达式的值<br>print pointer- 打印变量指针的内容<br>print *pointer- 打印指针所指向的数据结构的内容<br>delete<br>删除某些断点或自动显示表达式<br>delete 1- 删除断点 1。断点可以通过info break来显示<br>watch<br>为一个表达式设置一个观察点。当表达式的值发生变化时，这个观察点就会暂停程序的执行<br>?<br>where<br>打印所有堆栈帧的栈信息<br>where- 不使用参数，输出当前线程的堆栈信息<br>where all- 输出当前线程组中所有线程的堆栈信息<br>where threadindex- 输出指定线程的堆栈信息<br>attach<br>开始查看一个已经运行的进程<br>attach <process_id> - 附加到进程 process_id 上。process_id 可以使用 ps 命令找到<br>info thread<br>显示当前正在运行的线程<br>?<br>thread apply threadno command<br>对一个线程运行 gdb 命令<br>thread apply 3 where- 对线程 3 运行where命令<br>Thread threadno<br>选择一个线程作为当前线程<br>?<br>如果一个程序崩溃了，并生成了一个 core 文件，您可以查看 core 文件来判断进程结束时的状态。使用下面的命令启动 gdb：<br># gdb programname corefilename<br>要调试一个 core 文件，您需要可执行程序、源代码文件以及 core 文件。要对一个 core 文件启动 gdb，请使用 -c 选项：<br># gdb -c core programname<br>gdb 会显示是哪行代码导致这个程序产生了核心转储。<br>默认情况下，核心转储在 Novell 的 SUSE LINUX Enterprise Server 9（SLES 9）和 Red Hat? Enterprise Linux Advanced Server（RHEL AS 4）上都是禁用的。要启用核心转储，请以 root 用户的身份在命令行中执行ulimit &#8211;c unlimited。<br>清单 8中的例子阐述了如何使用 gdb 来定位程序中的 bug。清单 8 是一段包含 bug 的 C++ 代码。<br>清单 8中的 C++ 程序试图构建 10 个链接在一起的数字框（number box），例如：<br><br>图 1. 一个包含 10 个链接在一起的数字框的列表<br><br>然后试图从这个列表中逐个删除数字框。<br>编译并运行这个程序，如下所示：<br><br>清单 9. 编译并运行这个程序<br># g++ -g -o gdbtest1 gdbtest1.cpp<br># ./gdbtest1<br>Number Box "0" created<br>Number Box "1" created<br>Number Box "2" created<br>Number Box "3" created<br>Number Box "4" created<br>Number Box "5" created<br>Number Box "6" created<br>Number Box "7" created<br>Number Box "8" created<br>Number Box "9" created<br>list created<br>Number Box "9" deleted<br>Segmentation fault<br>正如您可以看到的一样，这个程序会导致段错误。调用 gdb 来看一下这个问题，如下所示：<br><br>清单 10. 调用 gdb<br># gdb ./gdbtest1<br>GNU gdb 6.2.1<br>Copyright 2004 Free Software Foundation, Inc.<br>GDB is free software, covered by the GNU General Public License, and you <br>are welcome to change it and/or distribute copies of it under certain <br>conditions.<br>Type "show copying" to see the conditions.<br>There is absolutely no warranty for GDB.<br>Type "show warranty" for <br>details.<br>This GDB was configured as "ppc-suse-linux"...Using host libthread_db <br>library "/lib/tls/libthread_db.so.1".<br>(gdb)<br>您知道段错误是在数字框 "9" 被删除之后发生的。执行run和where命令来精确定位段错误发生在程序中的什么位置。<br><br>清单 11. 执行 run 和 where 命令<br>(gdb) run<br>Starting program: /root/test/gdbtest1 <br>Number Box "0" created<br>Number Box "1" created<br>Number Box "2" created<br>Number Box "3" created<br>Number Box "4" created<br>Number Box "5" created<br>Number Box "6" created<br>Number Box "7" created<br>Number Box "8" created<br>Number Box "9" created<br>list created<br>Number Box "9" deleted<br>Program received signal SIGSEGV, Segmentation fault.<br>0x10000f74 in NumBox<int>::GetNext (this=0x0) at gdbtest1.cpp:14<br>14<br>NumBox<t>*GetNext() const { return Next; }<br>(gdb) where<br>#0<br>0x10000f74 in NumBox<int>::GetNext (this=0x0) at gdbtest1.cpp:14<br>#1<br>0x10000d10 in NumChain<int>::RemoveBox (this=0x10012008,<br>item_to_remove=@0xffffe200) at gdbtest1.cpp:63<br>#2<br>0x10000978 in main (argc=1, argv=0xffffe554) at gdbtest1.cpp:94<br>(gdb)<br>跟踪信息显示这个程序在第 14 行NumBox<int>::GetNext (this=0x0)接收到一个段错误。这个数字框上 Next 指针的地址是 0x0，这对于一个数字框来说是一个无效的地址。从上面的跟踪信息可以看出，GetNext函数是由 63 行调用的。看一下在 gdbtest1.cpp 的 63 行附近发生了什么：<br><br>清单 12. gdbtest1.cpp<br>54<br>} else {<br><br>55<br>temp-&gt;SetNext (current-&gt;GetNext());<br><br>56<br>delete temp;<br><br>57<br><br>temp = 0;<br><br>58<br>return 0;<br><br>59<br>}<br><br>60<br>}<br><br>61<br>current = 0;<br><br>62<br>temp = current;<br><br>63<br>current = current-&gt;GetNext();<br><br>64<br>}<br><br>65 <br><br>66<br>return -1;<br>第 61 行current=0将这个指针设置为一个无效的地址，这正是产生段错误的根源。注释掉第 61 行，将其保存为 gdbtest2.cpp，然后编译并重新运行。<br><br>清单 13. 再次运行程序（gdbtest2.cpp）<br># g++ -g -o gdbtest2 gdbtest2.cpp<br># ./gdbtest2<br>Number Box "0" created<br>Number Box "1" created<br>Number Box "2" created<br>Number Box "3" created<br>Number Box "4" created<br>Number Box "5" created<br>Number Box "6" created<br>Number Box "7" created<br>Number Box "8" created<br>Number Box "9" created<br>list created<br>Number Box "9" deleted<br>Number Box "0" deleted<br>这个程序现在可以成功完成而不会出现段错误了。然而，结果并不像我们预期的一样：程序在删除 Number Box "9"之后删除了 Number Box "0"，而不像我们期望的一样删除 Number Box "8,"。使用 gdb 再次来看一下。<br><br>清单 14. 再次使用 gdb 进行查看<br># gdb ./gdbtest2<br>GNU gdb 6.2.1<br>Copyright 2004 Free Software Foundation, Inc.<br>GDB is free software, covered by the GNU General Public License, and you <br>are welcome to change it and/or distribute copies of it under certain <br>conditions.<br>Type "show copying" to see the conditions.<br>There is absolutely no warranty for GDB.<br>Type "show warranty" for <br>details.<br>This GDB was configured as "ppc-suse-linux"...Using host libthread_db <br>library "/lib/tls/libthread_db.so.1".<br>(gdb) break 94 if i==8<br>Breakpoint 1 at 0x10000968: file gdbtest2.cpp, line 94.<br>(gdb) run<br>Starting program: /root/test/gdbtest2 <br>Number Box "0" created<br>Number Box "1" created<br>Number Box "2" created<br>Number Box "3" created<br>Number Box "4" created<br>Number Box "5" created<br>Number Box "6" created<br>Number Box "7" created<br>Number Box "8" created<br>Number Box "9" created<br>list created<br>Number Box "9" deleted<br>Breakpoint 1, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94<br>94<br>list -&gt;RemoveBox(i);<br>您可能希望找出为什么这个程序删除的是 Number Box 0，而不是 Number Box 8，因此需要在您认为程序会删除 Number Box 8 的地方停止程序。设置这个断点：break 94 if i==8，可以在 i 等于 8 时在第 94 行处停止程序。然后单步跟踪到RemoveBox()函数中。<br><br>清单 15. 单步跟踪到 RemoveBox() 函数中<br>(gdb) s<br>38<br>NumBox<t> *temp = 0;<br><br>(gdb) s<br>40<br>while (current != 0) {<br>(gdb) print pointer<br>$1 = (NumBox<int> *) 0x100120a8<br><br>(gdb) print *pointer<br>$2 = {Num = 0, Next = 0x0}<br>(gdb)<br>指针早已指向了 Number Box "0"，因此这个 bug 可能就存在于程序删除 Number Box "9" 的地方。要在 gdb 中重新启动这个程序，请使用kill删除原来的断点，然后添加一个 i 等于 9 时的新断点，然后再次运行这个程序。<br><br>清单 16. 在 gdb 中重新启动程序<br>(gdb) kill<br>Kill the program being debugged? (y or n) y<br>(gdb) info break<br>Num Type<br>Disp Enb Address<br>What<br>1<br>breakpoint<br>keep y<br>0x10000968 in main at gdbtest2.cpp:94<br><br>stop only if i == 8<br><br>breakpoint already hit 1 time<br>(gdb) delete 1<br>(gdb) break 94 if i==9<br>Breakpoint 2 at 0x10000968: file gdbtest2.cpp, line 94.<br>(gdb) run<br>Starting program: /root/test/gdbtest2 <br>Number Box "0" created<br>Number Box "1" created<br>Number Box "2" created<br>Number Box "3" created<br>Number Box "4" created<br>Number Box "5" created<br>Number Box "6" created<br>Number Box "7" created<br>Number Box "8" created<br>Number Box "9" created<br>list created<br>Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94<br>94<br>list -&gt;RemoveBox(i);<br>(gdb)<br>当这一次单步跟踪RemoveBox()函数时，要特别注意list-&gt;pointer正在指向哪一个数字框，因为 bug 可能就在于list-&gt;pointer开始指向 Number Box "0" 的地方。请使用display *pointer命令来查看，这会自动显示这个函数。<br><br>清单 17. 使用 display *pointer 命令进行监视<br>Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94<br>94<br>list -&gt;RemoveBox(i);<br>(gdb) s<br>NumChain<int>::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)<br>at gdbtest2.cpp:37<br>37<br>NumBox<t> *current = pointer;<br>(gdb) display *pointer<br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>38<br>NumBox<t> *temp = 0;<br><br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>40<br>while (current != 0) {<br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>41<br>if (current-&gt;GetValue() == item_to_remove) {<br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>NumBox<int>::GetValue (this=0x100120a8) at gdbtest2.cpp:16<br>16<br>const T&amp; GetValue () const { return Num; }<br>(gdb) s<br>NumChain<int>::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)<br>at gdbtest2.cpp:42<br>42<br>if (temp == 0) { <br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>44<br>if (current-&gt;GetNext() == 0) {<br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>NumBox<int>::GetNext (this=0x100120a8) at gdbtest2.cpp:14<br>14<br>NumBox<t>*GetNext() const { return Next; }<br>(gdb) s<br>NumChain<int>::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)<br>at gdbtest2.cpp:50<br>50<br>delete current;<br>1: *this-&gt;pointer = {Num = 9, Next = 0x10012098}<br>(gdb) s<br>~NumBox (this=0x100120a8) at gdbtest2.cpp:10<br>10<br>std::cout &lt;&lt; "Number Box " &lt;&lt;"\""<br>&lt;&lt; GetValue()<br>&lt;&lt;"\""<br>&lt;&lt;" deleted" &lt;&lt; std::endl;<br>(gdb) s<br>NumBox<int>::GetValue (this=0x100120a8) at gdbtest2.cpp:16<br>16<br>const T&amp; GetValue () const { return Num; }<br>(gdb) s<br>Number Box "9" deleted<br>~NumBox (this=0x100120a8) at gdbtest2.cpp:11<br>11<br>Next = 0;<br>(gdb) s<br>NumChain<int>::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)<br>at gdbtest2.cpp:51<br>51<br>current = 0;<br>1: *this-&gt;pointer = {Num = 0, Next = 0x0}<br>(gdb) s<br>53<br>return 0;<br>1: *this-&gt;pointer = {Num = 0, Next = 0x0}<br>(gdb) s<br>0x10000d1c<br>66<br>return -1;<br>1: *this-&gt;pointer = {Num = 0, Next = 0x0}<br>从上面的跟踪过程中，您可以看到list-&gt;pointer在删除 Number Box "9" 之后指向了 Number Box "0"。这个逻辑并不正确，因为在删除 Number Box "9" 之后，list-&gt;pointer应该指向的是 Number Box "8"。现在非常显然我们应该在第 50 行之前添加一条语句pointer = pointer-&gt;GetNext();，如下所示：<br><br>清单 18. 在第 50 行之前添加一条 pointer = pointer-&gt;GetNext(); 语句<br>49<br>} else {<br><br>50<br>pointer = pointer-&gt;GetNext();<br><br>51<br>delete current;<br><br>52<br>current = 0;<br><br>53<br>}<br><br>54<br><br>return 0;<br>将新修改之后的程序保存为 gdbtest3.cpp，然后编译并再次运行。<br><br>清单 19. 再次运行程序（gdbtest3.cpp）<br># g++ -g -o gdbtest3 gdbtest3.cpp<br># ./gdbtest3<br>Number Box "0" created<br>Number Box "1" created<br>Number Box "2" created<br>Number Box "3" created<br>Number Box "4" created<br>Number Box "5" created<br>Number Box "6" created<br>Number Box "7" created<br>Number Box "8" created<br>Number Box "9" created<br>list created<br>Number Box "9" deleted<br>Number Box "8" deleted<br>Number Box "7" deleted<br>Number Box "6" deleted<br>Number Box "5" deleted<br>Number Box "4" deleted<br>Number Box "3" deleted<br>Number Box "2" deleted<br>Number Box "1" deleted<br>Number Box "0" deleted<br>这才是我们期望的结果。<br>多线程环境<br>在 GDB 中有一些特殊的命令可以用于多线程应用程序的调试。下面这个例子给出了一个死锁情况，并介绍了如何使用这些命令来检查多线程应用程序中的问题：<br><br>清单 20. 多线程的例子<br>#include <stdio.h><br>#include "pthread.h&gt;<br>pthread_mutex_t AccountA_mutex;<br>pthread_mutex_t AccountB_mutex;<br>struct BankAccount {<br><br>char account_name[1];<br><br>int balance;<br>};<br>struct BankAccount<br>accountA = {"A", 10000 };<br>struct BankAccount<br>accountB = {"B", 20000 };<br>void * transferAB (void* amount_ptr) {<br><br>int amount = *((int*)amount_ptr);<br><br>pthread_mutex_lock(&amp;AccountA_mutex);<br><br>if (accountA.balance &lt; amount)<br>{<br><br>printf("There is not enough memory in Account A!\n");<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br><br><br>pthread_exit((void *)1);<br><br>}<br><br>accountA.balance -=amount;<br><br>sleep(1);<br><br>pthread_mutex_lock(&amp;AccountB_mutex);<br><br>accountB.balance +=amount;<br><br>pthread_mutex_unlock(&amp;AccountA_mutex); <br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br>}<br>void * transferBA (void* amount_ptr) {<br><br>int amount = *((int*)amount_ptr);<br><br>pthread_mutex_lock(&amp;AccountB_mutex);<br><br>if (accountB.balance &lt; amount)<br>{<br><br>printf("There is not enough memory in Account B!\n");<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br><br>pthread_exit((void *)1);<br><br>}<br><br>accountB.balance -=amount;<br><br>sleep(1);<br><br>pthread_mutex_lock(&amp;AccountA_mutex);<br><br>accountA.balance +=amount;<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br>}<br>int main(int argc, char* argv[]) {<br><br>int<br>threadid[4];<br><br>pthread_t<br>pthread[4];<br><br>int<br>transfer_amount[4] = {100, 200, 300, 400};<br><br>int<br>final_balanceA, final_balanceB;<br><br>final_balanceA=accountA.balance-transfer_amount[0]-<br>transfer_amount[1]+transfer_amount[2]+transfer_amount[3];<br><br>final_balanceB=accountB.balance+transfer_amount[0]<br>+transfer_amount[1]-transfer_amount[2]-transfer_amount[3];<br><br>if (threadid[0] = pthread_create(&amp;pthread[0], NULL, transferAB,<br>(void*)&amp;transfer_amount[0]) " 0) {<br><br>perror("Thread #0 creation failed.");<br><br>exit (1);<br><br>}<br><br>if (threadid[1] = pthread_create(&amp;pthread[1], NULL, transferAB,<br>(void*)&amp;transfer_amount[1]) " 0) {<br><br>perror("Thread #1 creation failed.");<br><br>exit (1);<br><br>}<br><br>if (threadid[2] = pthread_create(&amp;pthread[2], NULL, transferBA,<br>(void*)&amp;transfer_amount[2]) &lt; 0) {<br><br>perror("Thread #2 creation failed.");<br><br>exit (1);<br><br>}<br><br>if (threadid[3] = pthread_create(&amp;pthread[3], NULL, transferBA,<br>(void*)&amp;transfer_amount[3]) &lt; 0) {<br><br>perror("Thread #3 creation failed.");<br><br>exit (1);<br><br>}<br><br>printf("Transitions are in progress..");<br><br>while ((accountA.balance != final_balanceA) &amp;&amp; (accountB.balance<br>!= final_balanceB)) {<br><br>printf("..");<br><br>}<br><br>printf("\nAll the<br>money is transferred !!\n");<br>}<br>使用 gcc 来编译这个程序，如下所示： <br># gcc -g -o gdbtest2 gdbtest2.c -L/lib/tls -lpthread<br>程序 gdbtest2 会挂起，不会返回一条All the money is transferred !!消息。<br>将 gdb 附加到正在运行的进程上，从而了解这个进程内部正在发生什么。<br><br>清单 21. 将 gdb 附加到正在运行的进程上<br># ps -ef |grep gdbtest2<br>root<br>9510<br>8065<br>1 06:30 pts/1<br>00:00:00 ./gdbtest2<br>root<br>9516<br>9400<br>0 06:30 pts/4<br>00:00:00 grep gdbtest2<br># gdb -pid 9510<br>GNU gdb 6.2.1<br>Copyright 2004 Free Software Foundation, Inc.<br>GDB is free software, covered by the GNU General Public License, and you <br>are welcome to change it and/or distribute copies of it under certain <br>conditions.<br>Type "show copying" to see the conditions.<br>There is absolutely no warranty for GDB.<br>Type "show warranty" for <br>details.<br>This GDB was configured as "ppc-suse-linux".<br>Attaching to process 9510<br>Reading symbols from /root/test/gdbtest2...done.<br>Using host libthread_db library "/lib/tls/libthread_db.so.1".<br>Reading symbols from /lib/tls/libpthread.so.0...done.<br>[Thread debugging using libthread_db enabled]<br>[New Thread 1073991712 (LWP 9510)]<br>[New Thread 1090771744 (LWP 9514)]<br>[New Thread 1086577440 (LWP 9513)]<br>[New Thread 1082383136 (LWP 9512)]<br>[New Thread 1078188832 (LWP 9511)]<br>Loaded symbols for /lib/tls/libpthread.so.0<br>Reading symbols from /lib/tls/libc.so.6...done.<br>Loaded symbols for /lib/tls/libc.so.6<br>Reading symbols from /lib/ld.so.1...done.<br>Loaded symbols for /lib/ld.so.1<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br>(gdb) info thread<br><br>5 Thread 1078188832 (LWP 9511)<br>0x0ffe94ec in __lll_lock_wait ()<br>from /lib/tls/libpthread.so.0<br><br>4 Thread 1082383136 (LWP 9512)<br>0x0ffe94ec in __lll_lock_wait ()<br>from /lib/tls/libpthread.so.0<br><br>3 Thread 1086577440 (LWP 9513)<br>0x0ffe94ec in __lll_lock_wait ()<br>from /lib/tls/libpthread.so.0<br><br>2 Thread 1090771744 (LWP 9514)<br>0x0ffe94ec in __lll_lock_wait ()<br>from /lib/tls/libpthread.so.0<br><br>1 Thread 1073991712 (LWP 9510)<br>0x0ff4ac40 in __write_nocancel ()<br>from /lib/tls/libc.so.6<br>(gdb)<br>从info thread命令中，我们可以了解到除了主线程（thread #1）之外的所有线程都在等待函数__lll_lock_wait ()完成。<br>使用thread apply threadno where命令来查看每个线程到底运行到了什么地方：<br><br>清单 22. 查看每个线程运行到了什么地方<br>(gdb) thread apply 1 where<br>Thread 1 (Thread 1073991712 (LWP 9510)):<br>#0<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br>#1<br>0x0ff4ac28 in __write_nocancel () from /lib/tls/libc.so.6<br>Previous frame. identical to this frame. (corrupt stack?)<br>#0<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br>(gdb) thread apply 2 where<br>Thread 2 (Thread 1090771744 (LWP 9514)):<br>#0<br>0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0<br>#1<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#2<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#3<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#4<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>Previous frame. inner to this frame. (corrupt stack?)<br>#0<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br>(gdb) thread apply 3 where<br>Thread 3 (Thread 1086577440 (LWP 9513)):<br>#0<br>0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0<br>#1<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#2 <br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#3<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#4<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>Previous frame. inner to this frame. (corrupt stack?)<br>#0<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br>(gdb) thread apply 4 where<br>Thread 4 (Thread 1082383136 (LWP 9512)):<br>#0<br>0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0<br>#1<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#2<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#3<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#4<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>Previous frame. inner to this frame. (corrupt stack?)<br>#0<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br><br>(gdb) thread apply 5 where<br>Thread 5 (Thread 1078188832 (LWP 9511)):<br>#0<br>0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0<br>#1<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#2<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#3<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>#4<br>0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0<br>Previous frame. inner to this frame. (corrupt stack?)<br>#0<br>0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6<br>每个线程都试图对一个互斥体进行加锁，但是这个互斥体却是不可用的，可能是因为有另外一个线程已经对其进行加锁了。从上面的证据我们可以判断程序中一定存在死锁。您还可以看到哪个线程现在拥有这个互斥体。<br><br>清单 23. 查看哪个线程拥有互斥体<br>(gdb) print AccountA_mutex<br>$1 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2527,<br>__m_kind = 0, __m_lock<br>= {__status = 1, __spinlock = 0}}<br>(gdb) print 0x2527<br>$2 = 9511<br>(gdb) print AccountB_mutex<br>$3 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2529,<br>__m_kind = 0, __m_lock = {__status = 1, __spinlock = 0}}<br>(gdb) print 0x2529<br>$4 = 9513<br>(gdb)<br>从上面的命令中，我们可以看出AccontA_mutex是被线程 5（LWP 9511）加锁（拥有）的，而AccontB_mutex是被线程 3（LWP 9513）加锁（拥有）的。<br>为了解决上面的死锁情况，可以按照相同的顺序对互斥体进行加锁，如下所示：<br>清单 24. 按照相同的顺序对互斥体进行加锁<br>.<br>.<br>void * transferAB (void* amount_ptr) {<br><br>int amount = *((int*)amount_ptr);<br><br>pthread_mutex_lock(&amp;AccountA_mutex);<br><br>pthread_mutex_lock(&amp;AccountB_mutex);<br><br>if (accountA.balance &lt; amount)<br>{<br><br>printf("There is not enough memory in Account A!\n");<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br><br>pthread_exit((void *)1);<br><br>}<br><br>accountA.balance -=amount;<br><br>sleep(1);<br><br>accountB.balance +=amount;<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br>}<br>void * transferBA (void* amount_ptr) {<br><br>int amount = *((int*)amount_ptr);<br><br>pthread_mutex_lock(&amp;AccountA_mutex);<br><br>pthread_mutex_lock(&amp;AccountB_mutex);<br><br>if (accountB.balance &lt; amount)<br>{<br><br>printf("There is not enough memory in Account B!\n");<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br><br>pthread_exit((void *)1);<br><br>}<br><br>accountB.balance -=amount;<br><br>sleep(1);<br><br>accountA.balance +=amount;<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br>}<br>.<br>.<br>或者对每个帐号单独进行加锁，如下所示：<br>清单 25. 对每个帐号单独进行加锁<br>.<br>.<br>void * transferAB (void* amount_ptr) {<br><br>int amount = *((int*)amount_ptr);<br><br>pthread_mutex_lock(&amp;AccountA_mutex);<br><br>if (accountA.balance &lt; amount)<br>{<br><br>printf("There is not enough memory in Account A!\n");<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br><br>pthread_exit((void *)1);<br><br>}<br><br>accountA.balance -=amount;<br><br>sleep(1);<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br><br>pthread_mutex_lock(&amp;AccountB_mutex); <br><br>accountB.balance +=amount;<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br>}<br>void * transferBA (void* amount_ptr) {<br><br>int amount = *((int*)amount_ptr);<br><br>pthread_mutex_lock(&amp;AccountB_mutex);<br><br>if (accountB.balance &lt; amount)<br>{<br><br>printf("There is not enough memory in Account B!\n");<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br><br>pthread_exit((void *)1);<br><br>}<br><br>accountB.balance -=amount;<br><br>sleep(1);<br><br>pthread_mutex_unlock(&amp;AccountB_mutex);<br><br>pthread_mutex_lock(&amp;AccountA_mutex); <br><br>accountA.balance +=amount;<br><br>pthread_mutex_unlock(&amp;AccountA_mutex);<br>}<br>.<br>.<br>.</stdio.h></int></int></int></t></int></int></int></t></t></int></int></t></int></int></int></t></int></process_id><img src ="http://www.cppblog.com/elva/aggbug/122338.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-05 18:05 <a href="http://www.cppblog.com/elva/archive/2010/08/05/122338.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gdb使用及原理【转】</title><link>http://www.cppblog.com/elva/archive/2010/08/05/122337.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 05 Aug 2010 10:03:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/05/122337.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/122337.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/05/122337.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/122337.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/122337.html</trackback:ping><description><![CDATA[<span  style="color: rgb(219, 177, 136); font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 22px; "><p style="line-height: 22px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">1、GDB对于基于GNU系统开发的程序员来说是最基本的东西，必须的。所以这篇学习总结中，不打算包括GDB的一般使用方法。因为这些东西必须是随手拈来的。所以也就不花时间来整理，我只把一些比较高级的应用在这里作一个整理。<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">2、在编译链接程序时需要使用"-ggdb"选项来生成可供GDB调试用的信息，否则GDB将失去作用，因此GDB和GCC联系的非常紧密。并且当-g和-O开关同时打开时，调试和优化可能会产生冲突，经常会发现所见和事实不合的情况，所以要选择性地开启优化开关。<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">3、GDB的一些使用技巧：<br style="line-height: 22px; ">&nbsp;1）设置断点的方法包括：函数，行号，if条件断点express，这些前面都可以跟上文件名。另外还可以设置地址断点：b *0x8048424.<br style="line-height: 22px; ">&nbsp;2）GDB用来分析core文件，启动格式：gdb debugme core.xyz<br style="line-height: 22px; ">&nbsp;3）开启core文件生成的方法是: ulimit -c unlimited<br style="line-height: 22px; ">&nbsp;4）在不同函数的调用栈上切换及查看当前信息：bt/frame XX/up/down/info frame/args/locals<br style="line-height: 22px; ">&nbsp;5）调试一正运行的进程：gdb debugme pid或者gdb debugme + attach pid + detach，类似的应用还有：strace/ltrace/truss<br style="line-height: 22px; ">&nbsp;6）如果某个线程/进程处于死锁状态，还可以通过gcore pid来手动生成core文件来分析当前线程/进程的状态，然后利用GDB来分析, gcore使用方法：gcore pid，注意被调试的进程会临时性停止去生成core文件<br style="line-height: 22px; ">&nbsp;7）查看函数的反汇编指令：disassemble fun_name<br style="line-height: 22px; ">&nbsp;8）汇编指令级别的单步执行：ni/si,显示当前执行的汇编指令： x/i $pc<br style="line-height: 22px; ">&nbsp;9）查看寄存器的内容：info registers/all-registers<br style="line-height: 22px; ">&nbsp;10）查看某地址开始的内容：x/num 0xYYYYYYY 查看从0xYYYYYYY开始的num个单元内容；p 输出数组内容<br style="line-height: 22px; ">&nbsp;11）在函数调试中途强制返回：return&nbsp; &lt;expression&gt;;<br style="line-height: 22px; ">&nbsp;12）向被调试程序发送指定信号：在任意一点ctrl+C进入gdb调试命令行，然后：signal 1-15<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">4、用GDB来调试多线程程序：<br style="line-height: 22px; ">&nbsp;1）显示当前可调试的所有线程：info threads，GDB按照线程启动顺序重新安排了一个线程ID，这个ID是供GDB使用的<br style="line-height: 22px; ">&nbsp;2）在调试多线程的程序时，默认调试的是主线程，其他线程也同时处于暂停状态，如果想切换调试其他的线程，则只需要:thread id<br style="line-height: 22px; ">&nbsp;3）在对某一线程进行next/step执行的时候，其他线程也同时在执行，如果要限制其他线程执行，则可以使用：set scheduler-locking on<br style="line-height: 22px; ">&nbsp;4）对指定线程或者所有线程执行同样的操作，比如查看调用栈信息：thread apply ID1 ID2/all bt<br style="line-height: 22px; ">&nbsp;5）另外你也可以利用strace -p pid来显示某个线程当前的系统调用情况。或者利用gdb debugme pid来调试某个线程，但注意该方法会暂停整个进程的执行。对于多线程的程序gdb ./debugme相当于默认调试主线程，而gdb ./debugme pid则相当于默认调试pid线程。<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">5、用GDB来调试多进程程序：<br style="line-height: 22px; ">&nbsp;1）当fork子进程后，继续调试父进程或者调试刚产生的子进程：set follow-fork-mode parent/child，注意调试的时候其他的进程仍然在运行。<br style="line-height: 22px; ">&nbsp;2）如果父进程fork了多个子进程，上面的这种方法也只能跟踪调试到第一个子进程，并且不影响其他子进程的运行。<br style="line-height: 22px; ">&nbsp;3）如果想在调试一个进程的时候，其他进程处于暂停状态，则可以利用：set detach-on-fork off来做到<br style="line-height: 22px; ">&nbsp;4）利用attach来调试子进程。因为父进程fork子进程后，子进程会马上得到执行，如果恰好执行过了你要调试的地方，则来不及查询pid并且attach，所以为了支持直接attach调试，一般会在子进程的代码开始处加上一个sleep，以使得你有时间来查询pid，然后attach进入来调试。<br style="line-height: 22px; ">&nbsp;&nbsp; attach pid + stop + break XXX + continue + n + n ...+ s + s + ....<br style="line-height: 22px; ">&nbsp;5）利用gdb ./debugme pid都可以用来调试进程和线程，但不同的是GDB控制的范围不一样，前者不影响其他的并行单元（进程），而后则会使真个进程暂停。&nbsp;<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">6、调试动态链接库函数：<br style="line-height: 22px; ">&nbsp;我们可能要调试动态库的函数，或者通过调试来学习动态库函数的实现。这个时候，则需要GDB包括该动态库的debug版本，否则在GDB下面只会打印:0xXXXXXX: ??<br style="line-height: 22px; ">&nbsp;比如包括：glibc debug version，如下是一些glibc的debug版本的下载地址：<br style="line-height: 22px; ">&nbsp;<a href="http://linux.maruhn.com/sec/glibc-debug.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://linux.maruhn.com/sec/glibc-debug.html</a><br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">注：GDB的远端调试功能，暂时还没有接触过，现不做学习和总结.<br style="line-height: 22px; ">&nbsp;GDB对于多线程，多进程的调试支持并不强大，但可以利用其他专用调试器，比如TotalView：<br style="line-height: 22px; ">&nbsp;参考地址：<a href="http://www.totalviewtech.com/" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.totalviewtech.com/</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.total-view.com.cn/" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.total-view.com.cn/</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;<br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;<br style="line-height: 22px; ">7、一些辅助的诊断及调试工具：<br style="line-height: 22px; ">&nbsp;1）strace：跟踪系统调用情况<br style="line-height: 22px; ">&nbsp;2）ltrace：跟踪动态库的调用情况<br style="line-height: 22px; ">&nbsp;3）mtrace，pmalloc：跟踪内存使用情况，需要嵌入代码，打印内存使用记录。<br style="line-height: 22px; ">&nbsp;4）Binuitls：Toolchain的工具，参考我的上一篇总结。<br style="line-height: 22px; ">&nbsp;5）Valgrind：非常好的内存泄露检测工具，限于i386<br style="line-height: 22px; ">&nbsp;6）oprofile， NPTL Trace Tool等<br style="line-height: 22px; ">&nbsp;7）ald：汇编语言调试器<br style="line-height: 22px; ">&nbsp;8）Dude：另一个运行linux上的调试器，未使用ptrace实现<br style="line-height: 22px; ">&nbsp;9）Linice（<a href="http://www.linice.com/" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.linice.com/</a>）是SoftIce在Linux中的模拟软件，用于调试没有源代码的二进制文件的内核级调试器。<br style="line-height: 22px; ">&nbsp;10）其他<br style="line-height: 22px; ">关于调试及诊断工具包括许多，估计可以写一系列的文章来说明。</p><p style="line-height: 22px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">其他参考资料：<br style="line-height: 22px; ">0）GDB官方网站：<a href="http://www.gnu.org/software/gdb/gdb.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.gnu.org/software/gdb/gdb.html</a><br style="line-height: 22px; ">1）快速参考GDB支持的所有调试命令：《GDB QUICK REFERENCE》<br style="line-height: 22px; ">2）GDB的使用手册：《Debugging with gdb--The gnu Source-Level Debugger》<br style="line-height: 22px; ">3）《Embedded linux prime》的第13/14/15章可以作为参考。<br style="line-height: 22px; "><a href="http://book.opensourceproject.org.cn/embedded/embeddedprime/index.html?page=opensource/0136130550/ch13lev1sec1.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://book.opensourceproject.org.cn/embedded/embeddedprime/index.html?page=opensource/0136130550/ch13lev1sec1.html</a><br style="line-height: 22px; ">文章出处：飞诺网(<a href="http://www.firnow.com%29:http//dev.firnow.com/course/6_system/linux/Linuxjs/20091209/184488.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">www.firnow.com):http://dev.firnow.com/course/6_system/linux/Linuxjs/20091209/184488.html</a></p><p style="line-height: 22px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;</p><p style="line-height: 22px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">***********************************************************************************************</p><p style="line-height: 22px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">1、GDB基本组成：<br style="line-height: 22px; ">&nbsp;&nbsp; GDB由三个部分组成：<br style="line-height: 22px; ">&nbsp;（1）用户接口user interface，除支持传统的CLI接口还支持mi接口（ddd等工具使用）<br style="line-height: 22px; ">&nbsp;（2）符号处理层symbol handling，当gdb ./debugme后GDB会读取文件的符号信息，之后的原代码，变量/函数/类型的显示都由该部分进行(everything you can do without live process)。<br style="line-height: 22px; ">&nbsp;（3）目标系统处理层target system handling。包括执行控制，断点设置，单步执行，堆栈分析等操作都有该部分来进行。<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">2、GDB各部分的实现：<br style="line-height: 22px; ">&nbsp;（1）用户接口层(CLI)的实现很显然要用到readline/history库，而图形界面mi则需要用到:GNU ncurses库。<br style="line-height: 22px; ">&nbsp;&nbsp; 参考资料：&nbsp;<a href="http://www.gnu.org/software/ncurses/" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.gnu.org/software/ncurses/</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://tiswww.case.edu/php/chet/readline/rltop.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://tiswww.case.edu/php/chet/readline/rltop.html</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br style="line-height: 22px; ">&nbsp;（2）符号处理层则需要使用到：BFD/Opcodes库，分别用来读取分析ELF/Core文件，反汇编.<br style="line-height: 22px; ">&nbsp; 参考资料：&nbsp;<a href="http://www.xfocus.net/articles/200109/265.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.xfocus.net/articles/200109/265.html</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://sourceware.org/binutils/docs/bfd/index.html#Top" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://sourceware.org/binutils/docs/bfd/index.html#Top</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.linuxselfhelp.com/gnu/bfd/html_chapter/bfd_toc.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://www.linuxselfhelp.com/gnu/bfd/html_chapter/bfd_toc.html</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;<br style="line-height: 22px; ">&nbsp;（3）目标系统控制层：用ptrace系统调用来实现对其他进程的执行控制，检查和改变其核心映像以及寄存器等操作。<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">&nbsp;&nbsp;<br style="line-height: 22px; ">3、后端（目标系统控制层）实现：<br style="line-height: 22px; ">&nbsp;（1）内核在执行用户请求的系统调用之前回检查当前进程是否处于被&#8220;跟踪&#8221;状态，如果是的话内核暂停当前进程并将控制权交给调试进程，使跟踪调试进程可以查看甚至修改被调试进程的内存，寄存器等数据。而ptrace函数的作用就是告诉内核在执行子进程的系统调用之前做的动作。所有的动作都可以通过request进行传入。<br style="line-height: 22px; ">&nbsp;（2）设置断点原理：通过查找输入的断点和具体代码位置对应起来，并在该位置替换为一条断点指令，并且保存以前的指令，到目标程序运行到该断点处时，产生SIGTRAP信号，该信号被GDB捕获，GDB查找断点列表来确定是否命中断点。继续执行的时候则会把保存的指令重新放回并执行。n/s/ni/si/finish/uitil也会自动设置断点。<br style="line-height: 22px; ">&nbsp;（3）内核传递给被调试进程所有的信号，都会先传递给GDB再由gdb采取定义的动作来和被调试进程之间进行相互协调操作。gdb暂停目标程序运行的方法是向其发送SIGSTOP信号，GDB对于随机信号（非GDB产生的）的处理包括，可以通过handle signals命令来预定义<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">4、 ptrace函数简单介绍：long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);其中第一个参数代表告诉给kernel要做的动作。<br style="line-height: 22px; ">&nbsp;PTRACE_ME：设置自己的被跟踪标志，在被调试进程中使用。<br style="line-height: 22px; ">&nbsp;PTRACE_PEEKUSER：可以得到系统调用号及参数信息<br style="line-height: 22px; ">&nbsp;PTRACE_CONT：使被跟踪进程继续执行<br style="line-height: 22px; ">&nbsp;PRACE_GETREGS：一次性得到所有寄存器相关的值，提供输出参数<br style="line-height: 22px; ">&nbsp;PTRACE_POKEDATA：可用来改变子进程中变量的值<br style="line-height: 22px; ">&nbsp;PTRACE_SINGLESTEP：会使内核在子进程的每一条指令执行前先将其阻塞，然后将控制权交给父进程<br style="line-height: 22px; ">&nbsp;PTRACE_ATTACH：向运行着的子进程置上跟踪标志为。<br style="line-height: 22px; ">&nbsp;PTRACE_DETACH：和上面的行为相反。<br style="line-height: 22px; ">很多工具strace/ltrace/stuss等工具都用到了ptrace，学习ptrace的最好的资料是这些工具的原代码和kernel相关代码。<br style="line-height: 22px; ">&nbsp;<br style="line-height: 22px; ">其他参考资料：<br style="line-height: 22px; ">1）Ptrace相关资料:&nbsp;<a href="http://linuxgazette.net/issue81/sandeep.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://linuxgazette.net/issue81/sandeep.html</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://blog.chinaunix.net/u/19651/showart_362901.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://blog.chinaunix.net/u/19651/showart_362901.html</a>&nbsp;//玩转ptrace系列<br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://blog.chinaunix.net/u/19651/showart_362921.html" style="line-height: 22px; text-decoration: none; color: rgb(255, 204, 0); ">http://blog.chinaunix.net/u/19651/showart_362921.html</a><br style="line-height: 22px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br style="line-height: 22px; ">2）GDB的实现说明： 《gdb Internals》&nbsp;</p></span>
<img src ="http://www.cppblog.com/elva/aggbug/122337.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-05 18:03 <a href="http://www.cppblog.com/elva/archive/2010/08/05/122337.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux下，多线程程序死循环问题调试</title><link>http://www.cppblog.com/elva/archive/2010/08/02/121943.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 02 Aug 2010 04:08:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/08/02/121943.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/121943.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/08/02/121943.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/121943.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/121943.html</trackback:ping><description><![CDATA[当你的软件在某个时刻停止服务，CPU占用达到100%+，这种问题一个可能的原因是产生了死循环，假设程序某处存在潜在的死循环，并在某种条件下会引发，本文以一个示例来定位出现死循环的位置。<br>当程序某处存在死循环，通常定位问题及缩小范围的方法是，在可疑的代码处加log，或者注释掉可疑代码，这对于容易重现问题的程序来说还好，但对于&#8220;偶尔&#8221;才会产生问题程序却很难调试，因为我们很难重现程序故障。本文所述的调试过程正是在这种情况下，假设问题已经出现，我们要求环境保护现场，即出问题的程序还在运行中。<br><br>1.我们首先要知道是哪个线程出了问题：<br>首先查一下出问题进程的pid，例如<br>
<div style="PADDING-BOTTOM: 4px; BACKGROUND-COLOR: rgb(238,238,238); PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); WORD-BREAK: break-all; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">ovtsvn@ovtsvn:</span><span style="COLOR: #000000">~/</span><span style="COLOR: #000000">MASS4</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">icdn</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src$&nbsp;ps&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">ef&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;grep&nbsp;icdn<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">ovtsvn&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">11065</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">50</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">11</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">57</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">?</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">07</span><span style="COLOR: #000000">&nbsp;.</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">icdn<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">ovtsvn&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">11076</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">10971</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">11</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">57</span><span style="COLOR: #000000">&nbsp;pts</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">&nbsp;grep&nbsp;icdn<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">ovtsvn@ovtsvn:</span><span style="COLOR: #000000">~/</span><span style="COLOR: #000000">MASS4</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">icdn</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src$&nbsp;</span></div>
然后top命令查看线程信息：<br>top -H -p 11065<br>
<div style="PADDING-BOTTOM: 4px; BACKGROUND-COLOR: rgb(238,238,238); PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); WORD-BREAK: break-all; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;PID&nbsp;USER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PR&nbsp;&nbsp;NI&nbsp;&nbsp;VIRT&nbsp;&nbsp;RES&nbsp;&nbsp;SHR&nbsp;S&nbsp;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">CPU&nbsp;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">MEM&nbsp;&nbsp;&nbsp;&nbsp;TIME</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;&nbsp;COMMAND&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11073</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">25</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;R&nbsp;&nbsp;</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">40.84</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11065</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.01</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11066</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11067</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11068</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11069</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11070</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11071</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">22</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;S&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">11072</span><span style="COLOR: #000000">&nbsp;ovtsvn&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;325m&nbsp;</span><span style="COLOR: #000000">3980</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2236</span><span style="COLOR: #000000">&nbsp;R&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0.4</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00.00</span><span style="COLOR: #000000">&nbsp;icdn</span></div>
从上面可以看出，出问题线程PID为11073<br><br>2.接下来，我们用gdb来attach目标进程<br>执行: gdb icdn 11065<br>在gdb中，列出线程状态：<br>
<div style="PADDING-BOTTOM: 4px; BACKGROUND-COLOR: rgb(238,238,238); PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); WORD-BREAK: break-all; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">(gdb)&nbsp;info&nbsp;threads<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056948181264</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11066</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a3dec91</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;nanosleep&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056956573968</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11067</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a406fc2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;select&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">7</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056964966672</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11068</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a3dec91</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;nanosleep&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056973359376</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11069</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a3dec91</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;nanosleep&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056981752080</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11070</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a3dec91</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;nanosleep&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056990144784</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11071</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a40e63c</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;recvfrom&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47057194060048</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11072</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a406fc2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;select&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47057226893584</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11073</span><span style="COLOR: #000000">)&nbsp;&nbsp;CSendFile::SendFile&nbsp;(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0x2acc5d4aff40</span><span style="COLOR: #000000">,&nbsp;pathname</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">@</span><span style="COLOR: #000000">0x2acc5d4afee0</span><span style="COLOR: #000000">)<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;..</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">csendfile.cpp:</span><span style="COLOR: #000000">101</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;Thread&nbsp;</span><span style="COLOR: #000000">47056939784832</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11065</span><span style="COLOR: #000000">)&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a3dec91</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;nanosleep&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">(gdb)&nbsp;</span></div>
<br>gdb已经列出了各线程正在执行的函数，我们需要更多信息，记住11073对应的行首标号，这是gdb为线程分配的id，这里为2，然后执行切换：<br>
<div style="PADDING-BOTTOM: 4px; BACKGROUND-COLOR: rgb(238,238,238); PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); WORD-BREAK: break-all; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">(gdb)&nbsp;thread&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">[Switching&nbsp;to&nbsp;thread&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;(Thread&nbsp;</span><span style="COLOR: #000000">47057226893584</span><span style="COLOR: #000000">&nbsp;(LWP&nbsp;</span><span style="COLOR: #000000">11073</span><span style="COLOR: #000000">))]#</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;CSendFile::SendFile&nbsp;(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0x2acc5d4aff40</span><span style="COLOR: #000000">,&nbsp;pathname</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">@</span><span style="COLOR: #000000">0x2acc5d4afee0</span><span style="COLOR: #000000">)<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;..</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">csendfile.cpp:</span><span style="COLOR: #000000">101</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">101</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">(gdb)&nbsp;</span></div>
<br><br>bt一下：<br>
<div style="PADDING-BOTTOM: 4px; BACKGROUND-COLOR: rgb(238,238,238); PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); WORD-BREAK: break-all; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">(gdb)&nbsp;bt<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;&nbsp;CSendFile::SendFile&nbsp;(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0x2acc5d4aff40</span><span style="COLOR: #000000">,&nbsp;pathname</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">@</span><span style="COLOR: #000000">0x2acc5d4afee0</span><span style="COLOR: #000000">)&nbsp;at&nbsp;..</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">csendfile.cpp:</span><span style="COLOR: #000000">101</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0x000000000040592e</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;CIcdn::TaskThread&nbsp;(pParam</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0x7fff617eafe0</span><span style="COLOR: #000000">)&nbsp;at&nbsp;..</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">src</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">cicdn.cpp:</span><span style="COLOR: #000000">128</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a90b73a</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;start_thread&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libpthread.so.</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0x00002acc4a40d6dd</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;clone&nbsp;()&nbsp;from&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">lib</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">libc.so.</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0x0000000000000000</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">??</span><span style="COLOR: #000000">&nbsp;()</span></div>
<br>来看一下101行的代码：<br>
<div style="PADDING-BOTTOM: 4px; BACKGROUND-COLOR: rgb(238,238,238); PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-LEFT-COLOR: rgb(204,204,204); WORD-BREAK: break-all; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">(gdb)&nbsp;l<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">96</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">97</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">98</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;CSendFile::SendFile(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;pathname)<br><img id=Codehighlighter1_85_237_Open_Image onclick="this.style.display='none'; Codehighlighter1_85_237_Open_Text.style.display='none'; Codehighlighter1_85_237_Closed_Image.style.display='inline'; Codehighlighter1_85_237_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_85_237_Closed_Image onclick="this.style.display='none'; Codehighlighter1_85_237_Closed_Text.style.display='none'; Codehighlighter1_85_237_Open_Image.style.display='inline'; Codehighlighter1_85_237_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #000000">99</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_85_237_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_85_237_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;n;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">101</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_151_198_Open_Image onclick="this.style.display='none'; Codehighlighter1_151_198_Open_Text.style.display='none'; Codehighlighter1_151_198_Closed_Image.style.display='inline'; Codehighlighter1_151_198_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_151_198_Closed_Image onclick="this.style.display='none'; Codehighlighter1_151_198_Closed_Text.style.display='none'; Codehighlighter1_151_198_Open_Image.style.display='inline'; Codehighlighter1_151_198_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="COLOR: #000000">102</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_151_198_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_151_198_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">103</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif"></span><span style="COLOR: #000000">104</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">105</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">read&nbsp;file&nbsp;and&nbsp;send&nbsp;</span></span></div>
<br><br>现在我们定位到了出问题的代码位置，这里的循环只用来演示的。 <br>最后别忘了detach
<img src ="http://www.cppblog.com/elva/aggbug/121943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-08-02 12:08 <a href="http://www.cppblog.com/elva/archive/2010/08/02/121943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++：在迭代中删除map的成员</title><link>http://www.cppblog.com/elva/archive/2010/07/20/120854.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 20 Jul 2010 02:47:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/07/20/120854.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/120854.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/07/20/120854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/120854.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/120854.html</trackback:ping><description><![CDATA[<strong> C++：在迭代中删除map的成员</strong> <br><br>首先要清楚一点，迭代器相当于是容器上的指针，容器可以自己管理内
存，因此迭代器可能失效。<br>如果你在不知情的情况下使用了失效的迭代器，后果是不可预料的。可能程序立即崩掉，也可能什么事都没有发生。崩掉了算你
幸运，因为你至少知道出了问题，不然有你受的。<br><br>回到正题，我想说什么呢？<br>比如：<br>
<div class="UBBPanel codePanel">
<div class="UBBTitle"><img src="http://whumstc.com/users/sandy/pblog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent"><br>map&lt;string,int&gt; theMap;<br>// add something
to theMap...<br><br>for(auto iter1 = theMap.begin(); iter1 !=
theMap.end(); ++iter1)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;if(iter1-&gt;second == xxx)<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;theMap.erase(iter1);&nbsp;&nbsp;//#1
erase the element ??!!<br>&nbsp;&nbsp; }<br>} <br></div>
</div>
<br><br>看样子貌似非常正常的一
段代码。在一个map中寻找值为xxx的项并删除。<br>但是实际上这个代码是完全错误的，会导致无法预料的结果。<br><br>问题就在#1处。一
旦你erase了一个iterator指向的内容，这个iterator就无效了。<br>这时候你再对这个iterator做任何操作其结果都是未定义
的。<br><br>那么该怎么办呢？<br>还好，对于map这种以指针构建起来的容器来说，可以保证一个元素删除了，不影响指向其它元素的迭代器。<br>因
此就可以这样做（《C++Standard Library》上建议的正确做法）：<br>
<div class="UBBPanel
codePanel">
<div class="UBBTitle"><img src="http://whumstc.com/users/sandy/pblog/images/code.gif" style="margin: 0px 2px -3px 0px;" alt="程序代码"> 程序代码</div>
<div class="UBBContent"><br>for(auto iter1 = theMap.begin(); iter1 !=
theMap.end(); )<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;if(iter1-&gt;second == xxx)<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;theMap.erase(iter1++);&nbsp;&nbsp;//#1
<br>&nbsp;&nbsp; }else<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++iter1;<br>&nbsp;&nbsp; }<br>} <br></div>
</div>
<br>这
个遍历把迭代器的自增从for头部中取出，丢到循环体中去。#1处，iter1++这个运算先自增，但是却返回了自增前的迭代器的一个临时拷贝。然后这个
临时迭代器指向的内容被删除了，但是iter1本身已经自增到下一个位置了，不受影响。
<br><img src ="http://www.cppblog.com/elva/aggbug/120854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-07-20 10:47 <a href="http://www.cppblog.com/elva/archive/2010/07/20/120854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么静态成员变量要通过类外初始化赋值</title><link>http://www.cppblog.com/elva/archive/2010/05/06/114577.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 06 May 2010 03:35:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/05/06/114577.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/114577.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/05/06/114577.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/114577.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/114577.html</trackback:ping><description><![CDATA[<p>当将类的某个数据成员声明为static时，该静态数据成员只能被定义一次，而且要被同类的所有对象共享。<br>各个对象都拥有类中每一个普通数据成员的副本，但静态数据成员只有一个实例存在，与定义了多少类对象无关。<br>静态数据成员的用途之一是统计有多少个对象实际存在。<br>静态数据成员不能在类中初始化，实际上类定义只是在描述对象的蓝图，在其中指定初值是不允许的。也不能在够造函数中初始化该成员，<br>因为静态数据成员为类的各个对象共享，那么每次创建一个类的对象则静态数据成员都要被重新初始化。 </p>
<br>  <img src ="http://www.cppblog.com/elva/aggbug/114577.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-05-06 11:35 <a href="http://www.cppblog.com/elva/archive/2010/05/06/114577.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc6.0,vs2003中，ado代码移植到vs2005，2008时遇到重定义问题的解决办法</title><link>http://www.cppblog.com/elva/archive/2010/04/27/113704.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 27 Apr 2010 06:03:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2010/04/27/113704.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/113704.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2010/04/27/113704.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/113704.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/113704.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span>vs2003中正常访问数据库的代码在vs2005或vs2008中编译报错如：<br><br><br><br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;wireHWND&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_RemotableHandle&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;__MIDL_IWinTypes_0009&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_COSERVERINFO&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_COAUTHINFO&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_COAUTHIDENTITY&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;IPersistFile&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;IPersist&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;IAuthenticate&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;IErrorInfo&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;IMarshal&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;IStream&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;ISequentialStream&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_LARGE_INTEGER&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_ULARGE_INTEGER&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;tagSTATSTG&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\stdafx.h(</span><span style="COLOR: #000000">69</span><span style="COLOR: #000000">)&nbsp;:&nbsp;warning&nbsp;C4192:&nbsp;导入类型库&#8220;_FILETIME&#8221;时自动排除&#8220;C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">251</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;IBindResource&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">13883</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IBindResource&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">289</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;ICreateRow&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14271</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;ICreateRow&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">329</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;IRegisterProvider&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14637</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IRegisterProvider&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">369</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;tagDBPROPIDSET&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">2295</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;tagDBPROPIDSET&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">400</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;tagDBID&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">695</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;tagDBID&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">411</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;tagDBPROP&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">2394</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;tagDBPROP&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">424</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;tagDBPROPSET&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">2403</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;tagDBPROPSET&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">435</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;tagDBPROPINFO&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">2345</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;tagDBPROPINFO&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">448</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;tagDBPROPINFOSET&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">2356</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;tagDBPROPINFOSET&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">457</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;IDBProperties&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">7883</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IDBProperties&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tlh(</span><span style="COLOR: #000000">515</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2011:&nbsp;&#8220;IDBBinderProperties&#8221;:&nbsp;&#8220;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&#8221;类型重定义<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14390</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IDBBinderProperties&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IBindResource&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">13883</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IBindResource&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">101</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_RemoteBind&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">102</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteBind&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">102</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteBind&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">110</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;ICreateRow&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14271</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;ICreateRow&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">111</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_RemoteCreateRow&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">112</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteCreateRow&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">112</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteCreateRow&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">120</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IRegisterProvider&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14637</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IRegisterProvider&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">121</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_RemoteGetURLMapping&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">122</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteGetURLMapping&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">122</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteGetURLMapping&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">126</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IRegisterProvider&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14637</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IRegisterProvider&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">127</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_SetURLMapping&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">128</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;SetURLMapping&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">128</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;SetURLMapping&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">132</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IRegisterProvider&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14637</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IRegisterProvider&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">133</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_UnregisterProvider&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">134</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;UnregisterProvider&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">134</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;UnregisterProvider&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">142</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IDBProperties&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">7883</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IDBProperties&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">143</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_RemoteGetProperties&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">144</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteGetProperties&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">144</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteGetProperties&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">148</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IDBProperties&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">7883</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IDBProperties&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">149</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_RemoteGetPropertyInfo&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">150</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteGetPropertyInfo&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">150</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteGetPropertyInfo&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">154</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IDBProperties&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">7883</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IDBProperties&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">155</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_RemoteSetProperties&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">156</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteSetProperties&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">156</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;RemoteSetProperties&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">164</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2027:&nbsp;使用了未定义类型&#8220;IDBBinderProperties&#8221;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d:\program&nbsp;files\microsoft&nbsp;visual&nbsp;studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\vc\platformsdk\include\oledb.h(</span><span style="COLOR: #000000">14390</span><span style="COLOR: #000000">)&nbsp;:&nbsp;参见&#8220;IDBBinderProperties&#8221;的声明<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">165</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C3861:&nbsp;&#8220;raw_Reset&#8221;:&nbsp;找不到标识符<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">166</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;Reset&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">c:\users\elva\desktop\serialnumberwriter\trunk\debug\oledb32.tli(</span><span style="COLOR: #000000">166</span><span style="COLOR: #000000">)&nbsp;:&nbsp;error&nbsp;C2673:&nbsp;&#8220;Reset&#8221;:&nbsp;全局函数没有&#8220;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&#8221;指针</span></div>
<br><br>该错误由以下语句导致：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;_WIN32_DCOM&nbsp;</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#import&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\ado\\msado15.dll</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;no_namespace&nbsp;rename(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">EOF</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ADOEOF</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#import&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;no_namespace</span></div>
</span><br>解决办法是去掉no_namespace,在用到的地方单独加namespace<br><br>using namespace ADODB;<br>另一个不知道是什么，<br>我只好将他改名：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">#import&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C:\\Program&nbsp;Files\\Common&nbsp;Files\\System\\Ole&nbsp;DB\\oledb32.dll</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;rename_namespace(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">OLEDB</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;no_namespace</span></div>
<img src ="http://www.cppblog.com/elva/aggbug/113704.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2010-04-27 14:03 <a href="http://www.cppblog.com/elva/archive/2010/04/27/113704.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]内存分配 知识,全局，局部，静态变量</title><link>http://www.cppblog.com/elva/archive/2009/10/30/99811.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 30 Oct 2009 02:56:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/10/30/99811.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/99811.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/10/30/99811.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/99811.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/99811.html</trackback:ping><description><![CDATA[<span  style="font-family: Arial; color: rgb(51, 51, 51); font-size: 13px; line-height: 20px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "><p style="line-height: normal; ">内存分配 知识,全局，局部，静态变量</p><p style="line-height: normal; ">预备知识—程序的内存分配&nbsp;<br style="line-height: normal; ">一个由C/C++编译的程序占用的内存分为以下几个部分&nbsp;<br style="line-height: normal; ">1、栈区（stack）— 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。&nbsp;<br style="line-height: normal; ">2、堆区（heap） — 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。<br style="line-height: normal; ">3、全局区（静态区）（static）—，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放&nbsp;<br style="line-height: normal; ">4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放&nbsp;<br style="line-height: normal; ">5、程序代码区—存放函数体的二进制代码。<br style="line-height: normal; "><br style="line-height: normal; ">一个正常的程序在内存中通常分为程序段，数据端和堆栈三部分。程序段里放着程序的机器码和只读数据，这个段通常是只读，对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。在内存中，它们的位置如下：&nbsp;<br style="line-height: normal; ">+------------------+ 内存低端&nbsp;<br style="line-height: normal; ">| 程序段 |&nbsp;<br style="line-height: normal; ">|------------------|&nbsp;<br style="line-height: normal; ">| 数据段 |&nbsp;<br style="line-height: normal; ">|------------------|&nbsp;<br style="line-height: normal; ">| 堆栈 |&nbsp;<br style="line-height: normal; ">+------------------+ 内存高端&nbsp;<br style="line-height: normal; ">堆栈是内存中的一个连续的块。一个叫堆栈指针的寄存器（SP）指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是，后进先出。也就是说，后放入的数据第一个取出。它支持两个操作，PUSH和POP。PUSH是将数据放到栈的顶端，POP是将栈顶的数据取出。<br style="line-height: normal; ">在高级语言中，程序函数调用和函数中的临时变量都用到堆栈。为什么呢？因为在调用一个函数时，我们需要对当前的操作进行保护，也为了函数执行后，程序可以正确的找到地方继续执行，所以参数的传递和返回值也用到了堆栈。通常对局部变量的引用是通过给出它们对SP的偏移量来实现的。另外还有一个基址指针（FP，在Intel芯片中是BP），许多编译器实际上是用它来引用本地变量和参数的。通常，参数的相对FP的偏移是正的，局部变量是负的。&nbsp;<br style="line-height: normal; ">当程序中发生函数调用时，计算机做如下操作：首先把参数压入堆栈；然后保存指令寄存器(IP)中的内容，做为返回地址(RET)；第三个放入堆栈的是基址寄存器(FP)；然后把当前的栈指针(SP)拷贝到FP，做为新的基地址；最后为本地变量留出一定空间，把SP减去适当的数值。&nbsp;<br style="line-height: normal; "><br style="line-height: normal; ">在函数体中定义的变量通常是在栈上，用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量，加了static修饰符后不管在哪里都存放在全局区（静态区）,在所有函数体外定义的static变量表示在该文件中有效，不能extern到别的文件用，在函数体内定义的static表示只在该函数体内有效。另外，函数中的"adgfdf"这样的字符串存放在常量区。<br style="line-height: normal; "><br style="line-height: normal; ">对比：<br style="line-height: normal; ">1 性能<br style="line-height: normal; ">栈：栈存在于RAM中。栈是动态的，它的存储速度是第二快的。stack<br style="line-height: normal; ">堆：堆位于RAM中，是一个通用的内存池。所有的对象都存储在堆中。heap<br style="line-height: normal; "><br style="line-height: normal; ">2 申请方式<br style="line-height: normal; ">stack: 由系统自动分配。 例如，声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间&nbsp;<br style="line-height: normal; ">heap: 需要程序员自己申请，并指明大小，在c中malloc函数 如p1 = (char *)malloc(10);&nbsp;<br style="line-height: normal; ">在C++中用new运算符 如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。<br style="line-height: normal; "><br style="line-height: normal; ">3 申请后系统的响应<br style="line-height: normal; ">栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。&nbsp;<br style="line-height: normal; ">堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时，&nbsp;<br style="line-height: normal; ">会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。<br style="line-height: normal; "><br style="line-height: normal; ">4 申请大小的限制<br style="line-height: normal; ">栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在WINDOWS下，栈的大小是2M（也有的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因此，能从栈获得的空间较小。&nbsp;<br style="line-height: normal; ">堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。<br style="line-height: normal; "><br style="line-height: normal; ">5 申请效率的比较<br style="line-height: normal; ">栈由系统自动分配，速度较快。但程序员是无法控制的。&nbsp;<br style="line-height: normal; ">堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便.&nbsp;<br style="line-height: normal; ">另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活。<br style="line-height: normal; "><br style="line-height: normal; ">6 堆和栈中的存储内容<br style="line-height: normal; ">栈：在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈的，然后是函数中的局部变量。注意静态变量是不入栈的。&nbsp;<br style="line-height: normal; ">当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。&nbsp;<br style="line-height: normal; ">堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。<br style="line-height: normal; "><br style="line-height: normal; ">7 存取效率的比较<br style="line-height: normal; ">char s1[] = "aaaaaaaaaaaaaaa";&nbsp;<br style="line-height: normal; ">char *s2 = "bbbbbbbbbbbbbbbbb";&nbsp;<br style="line-height: normal; ">aaaaaaaaaaa是在运行时刻赋值的；&nbsp;<br style="line-height: normal; ">而bbbbbbbbbbb是在编译时就确定的；&nbsp;<br style="line-height: normal; ">但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。&nbsp;<br style="line-height: normal; ">比如：&nbsp;<br style="line-height: normal; ">#include&nbsp;<br style="line-height: normal; ">void main()&nbsp;<br style="line-height: normal; ">{&nbsp;<br style="line-height: normal; ">char a = 1;&nbsp;<br style="line-height: normal; ">char c[] = "1234567890";&nbsp;<br style="line-height: normal; ">char *p ="1234567890";&nbsp;<br style="line-height: normal; ">a = c[1];&nbsp;<br style="line-height: normal; ">a = p[1];&nbsp;<br style="line-height: normal; ">return;&nbsp;<br style="line-height: normal; ">}&nbsp;<br style="line-height: normal; ">对应的汇编代码&nbsp;<br style="line-height: normal; ">10: a = c[1];&nbsp;<br style="line-height: normal; ">00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]&nbsp;<br style="line-height: normal; ">0040106A 88 4D FC mov byte ptr [ebp-4],cl&nbsp;<br style="line-height: normal; ">11: a = p[1];&nbsp;<br style="line-height: normal; ">0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]&nbsp;<br style="line-height: normal; ">00401070 8A 42 01 mov al,byte ptr [edx+1]&nbsp;<br style="line-height: normal; ">00401073 88 45 FC mov byte ptr [ebp-4],al&nbsp;<br style="line-height: normal; ">第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。&nbsp;<br style="line-height: normal; "><br style="line-height: normal; ">小结：&nbsp;<br style="line-height: normal; ">堆和栈的区别可以用如下的比喻来看出：&nbsp;<br style="line-height: normal; ">使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自由度小。&nbsp;<br style="line-height: normal; ">使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。</p><p style="line-height: normal; "><font color="#ff0000" style="line-height: normal; ">全局变量、静态数据、常量存放在全局数据区，所有函数的代码存放在代码区，为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区。&nbsp;&nbsp;&nbsp;<br style="line-height: normal; ">所以在同一个进程里，多个任务（线程）的全局变量和静态变量都应该是共享同一块内存（全局数据区）&nbsp;&nbsp;&nbsp;<br style="line-height: normal; ">而在不同的进程里，重新加载了代码，各个进程间的全局变量和静态变量当然不是拥有同一块内存。&nbsp;&nbsp;&nbsp;<br style="line-height: normal; ">在psos下，各个任务是不同的线程，所以各个任务的全局变量和静态变量是在同一块内存。而我的另一个程序中（在sco unix），是每次运行都是一个新的进程，所以各个进程的全局变量和静态变量拥有不同的内存</font></p></span>
<img src ="http://www.cppblog.com/elva/aggbug/99811.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-10-30 10:56 <a href="http://www.cppblog.com/elva/archive/2009/10/30/99811.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转:全局变量、静态变量和局部变量</title><link>http://www.cppblog.com/elva/archive/2009/10/30/99810.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Fri, 30 Oct 2009 02:55:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/10/30/99810.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/99810.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/10/30/99810.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/99810.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/99810.html</trackback:ping><description><![CDATA[<span  style="font-family: song; border-collapse: collapse; font-size: 12px; "><div align="center"><table cellspacing="0" cellpadding="0" width="90%" border="0"><tbody><tr style="font: normal normal normal 12px/normal song, Verdana; "><td style="font: normal normal normal 12px/normal song, Verdana; "><div align="left"><a href="http://blogger.org.cn/blog/more.asp?name=zhu_ruixian&amp;id=23460" style="text-decoration: underline; color: rgb(0, 68, 182); "><font color="#0000ff">全局变量和局部变量在内存里的区别？</font></a></div></td></tr><tr style="font: normal normal normal 12px/normal song, Verdana; "><td style="font: normal normal normal 12px/normal song, Verdana; "><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr style="font: normal normal normal 12px/normal song, Verdana; "><td style="font: normal normal normal 12px/normal song, Verdana; "><div align="right">&nbsp;</div></td></tr></tbody></table><div align="left">一、预备知识—程序的内存分配</div><div align="left">一个由c/C++编译的程序占用的内存分为以下几个部分</div><div align="left">1、栈区（stack）— 由编译器自动分配释放，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。</div><div align="left">2、堆区（heap） — 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表。</div><div align="left">3、全局区（静态区）（static）—，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域(.data)，未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(.bss)。 - 程序结束后由系统释放。</div><div align="left">4、文字常量区 —常量字符串就是放在这里的(.rodata)。 程序结束后由系统释放。</div><div align="left">5、程序代码区—存放函数体的二进制代码(.text)。</div><div align="left">&nbsp;</div><div align="left">二、例子程序</div><div align="left">这是一个前辈写的，非常详细</div><div align="left">//main.cpp</div><div align="left">int a = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 全局初始化区</div><div align="left">char *p1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 全局未初始化区</div><div align="left">main()</div><div align="left">{</div><div align="left">&nbsp; int b;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 栈区</div><div align="left">&nbsp; char s[] = "abc"; // 栈区</div><div align="left">&nbsp; char *p2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 栈区</div><div align="left">&nbsp; char *p3 = "123456";&nbsp;&nbsp;&nbsp;&nbsp; // "123456\0" 在常量区，p3在栈区</div><div align="left">&nbsp; static int c =0;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; // 全局（静态）初始化区</div><div align="left">&nbsp;</div><div align="left">&nbsp; p1 = (char *)malloc(10);</div><div align="left">&nbsp; p2 = (char *)malloc(20); // 分配得来的10和20字节的区域就在堆区</div><div align="left">&nbsp;</div><div align="left">&nbsp; strcpy(p1, "123456");&nbsp;&nbsp;&nbsp; // "123456\0" 放在常量区，编译器可能会将它</div><div align="left">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 与p3所指向的"123456"优化成一个地方。</div><div align="left">}&nbsp;</div><div align="left">&nbsp;</div></td></tr></tbody></table></div><div><font face="Times New Roman" size="3">&nbsp;==============================================================</font><font face="Times New Roman" size="3">&nbsp;</font></div><div align="left"><font size="3"><strong>static</strong><strong>全局变量与普通的全局变量有什么区别？</strong><strong>static</strong><strong>局部变量和普通局部变量有什么区别？</strong><strong>static</strong><strong>函数与普通函数有什么区别？</strong></font><strong></strong></div><div align="left"><font size="3"><font face="Times New Roman">static</font>全局变量与普通的全局变量有什么区别？<font face="Times New Roman">static</font>局部变量和普通局部变量有什么区别？<font face="Times New Roman">static</font>函数与普通函数有什么区别？<font face="Times New Roman">&nbsp;</font>　　</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font size="3">答</font><font size="3"><font face="Times New Roman">:<br style="font: normal normal normal 12px/normal song, Verdana; ">1)&nbsp;</font>全局变量<font face="Times New Roman">(</font>外部变量<font face="Times New Roman">)</font>的说明之前再冠以<font face="Times New Roman">static&nbsp;</font>就构成了静态的全局变量。全局变量本身就是静态存储方式，<font face="Times New Roman">&nbsp;</font>静态全局变量当然也是静态存储方式。<font face="Times New Roman">&nbsp;</font>这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序，<font face="Times New Roman">&nbsp;</font>当一个源程序由多个源文件组成时，非静态的全局变量在各个源文件中都是有效的。<font face="Times New Roman">&nbsp;</font>而静态全局变量则限制了其作用域，<font face="Times New Roman">&nbsp;</font>即只在定义该变量的源文件内有效，<font face="Times New Roman">&nbsp;</font>在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内，只能为该源文件内的函数公用，<font face="Times New Roman"></font>因此可以避免在其它源文件中引起错误。</font></div><div align="left"><font size="3"><font face="Times New Roman">2)&nbsp;</font>从以上分析可以看出，<font face="Times New Roman">&nbsp;</font>把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域，限制了它的使用范围。　　</font><font size="3"><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">3) static</font>函数与普通函数作用域不同<font face="Times New Roman">,</font>仅在本文件。只在当前源文件中使用的函数应该说明为内部函数<font face="Times New Roman">(static)</font>，内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数，应该在一个头文件中说明，要使用这些函数的源文件要包含这个头文件<font face="Times New Roman">&nbsp;</font>　　</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font size="3"></font></div><div align="left"><font size="3">综上所述</font><font size="3"><font face="Times New Roman">:<br style="font: normal normal normal 12px/normal song, Verdana; ">static</font>全局变量与普通的全局变量有什么区别：</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font face="Times New Roman" size="3">static</font><font size="3">全局变量只初使化一次，防止在其他文件单元中被引用<font face="Times New Roman">;&nbsp;</font>　　</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font face="Times New Roman" size="3">static</font><font size="3">局部变量和普通局部变量有什么区别：</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font face="Times New Roman" size="3">static</font><font size="3">局部变量只被初始化一次，下一次依据上一次结果值；<font face="Times New Roman">&nbsp;</font>　　</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font face="Times New Roman" size="3">static</font><font size="3">函数与普通函数有什么区别：</font><br style="font: normal normal normal 12px/normal song, Verdana; "><font face="Times New Roman" size="3">static</font><font size="3">函数在内存中只有一份，普通函数在每个被调用中维持一份拷贝</font></div><div><font face="Times New Roman" size="3"></font>&nbsp;</div><div><font face="Times New Roman" size="3">&nbsp;==============================================================</font></div><div><font face="Times New Roman" size="3">一个C语言变量分配的实际例子：</font></div><div>&nbsp;</div><div><font face="宋体" size="3">&nbsp; 我们来看看在可执行文件中,变量们会被分配在哪些区里.这里以可执行文件为例子，可执行文件有固定的内存加载地址，符号(函数/变量的名字)将来在内存里的地址连接器是可以提前确定的。</font></div><div><font face="宋体" size="3"></font>&nbsp;</div><font face="Times New Roman"><div><font face="宋体" size="3">&nbsp; 源程序编译连接的结果是形成1堆汇编指令代码，大致分为.text .data .bss等几个节区(section)。对于.exe文件和.so文件，全局和静态变量都放在.data 或.bss段(gas把源文件从头到尾扫描1遍，才知道一个变量的全部情况：是否定义；类型；是否初始化。然后把初始化的变量在.data段里分配位置和空间，把没初始化的变量在.bss段里分配位置和空间，没定义的变量分配在.undef段)。汇编指令代码里全局变量表现为一个内存地址(全局变量在目标文件里是一个偏移值，加载进内存里是一个内存地址)。临时变量在汇编代码里变成ebp/esp+n，表现为一个堆栈地址，化为程序正文(.text)的一部分。有些变量的最终内存地址在加载进内存之前还不能确定，需要加载进内存才可以计算出来.</font></div><div><font face="宋体" size="3">&nbsp; 全局变量 作用域是跨越多个源程序的。因此全局变量不能重名。静态变量作用域是位于单个源程序内。多个源程序可以有同名的全局静态变量。本例中，为了区分多个同名的静态变量，gcc 用 c444和c444.0 来加以区别。</font></div></font><div>&nbsp;</div><div>[test@redhat]# more aaa.c<br style="font: normal normal normal 12px/normal song, Verdana; "># include &lt;stdio.h&gt;</div><div>int a111 = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 全局变量 已初始化<br style="font: normal normal normal 12px/normal song, Verdana; ">char *p111 = "654321";&nbsp;&nbsp;&nbsp;&nbsp; # 全局指针变量 已经初始化<br style="font: normal normal normal 12px/normal song, Verdana; ">static int c444 = 9;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 静态全局变量 已经初始化<br style="font: normal normal normal 12px/normal song, Verdana; ">static int c555;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 静态全局变量 未初始化<br style="font: normal normal normal 12px/normal song, Verdana; ">main()&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">{&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; int b222;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 局部变量<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; char s333[] = "abc";&nbsp;&nbsp; # 局部变量<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; char *p222;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 局部变量<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; char *p333 = "123456";&nbsp;&nbsp;&nbsp; # 局部变量<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; static int c444 =0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 已初始化静态局部变量,与前面静态全局变量重名<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; p111 = (char *)malloc(10);&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; p222 = (char *)malloc(20);</div><div>&nbsp;&nbsp;&nbsp; strcpy(p111, "123456");<br style="font: normal normal normal 12px/normal song, Verdana; ">}</div><div><br style="font: normal normal normal 12px/normal song, Verdana; ">[test@redhat]# gcc -o aaa ./aaa.c<br style="font: normal normal normal 12px/normal song, Verdana; "></div><div>&nbsp;</div><div>[test@redhat]# readelf -a ./aaa<br style="font: normal normal normal 12px/normal song, Verdana; ">ELF Header:<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Magic:&nbsp;&nbsp; 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Class:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELF32<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Data:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2's complement, little endian<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Version:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 (current)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; OS/ABI:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNIX - System V<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; ABI Version:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Type:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EXEC (Executable file)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Machine:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Intel 80386<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Version:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Entry point address:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x80482d0<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Start of program headers:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 52 (bytes into file)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Start of section headers:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2040 (bytes into file)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Flags:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x0<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Size of this header:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 52 (bytes)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Size of program headers:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32 (bytes)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Number of program headers:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Size of section headers:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40 (bytes)<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Number of section headers:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 27<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Section header string table index: 24</div><div>Section Headers:&nbsp;&nbsp;&nbsp;<font color="#0080ff">Addr是文件加载进内存时，每个section在内存中的虚拟地址</font><br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [Nr] Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Addr&nbsp;&nbsp;&nbsp;&nbsp; Off&nbsp;&nbsp;&nbsp; Size&nbsp;&nbsp; ES Flg Lk Inf Al<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000000 000000 000000 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp; 0<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 1] .interp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048114 000114 000013 00&nbsp;&nbsp; A&nbsp; 0&nbsp;&nbsp; 0&nbsp; 1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 2] .note.ABI-tag&nbsp;&nbsp;&nbsp;&nbsp; NOTE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048128 000128 000020 00&nbsp;&nbsp; A&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 3] .hash&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HASH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048148 000148 00002c 04&nbsp;&nbsp; A&nbsp; 4&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 4] .dynsym&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DYNSYM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048174 000174 000060 10&nbsp;&nbsp; A&nbsp; 5&nbsp;&nbsp; 1&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 5] .dynstr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STRTAB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080481d4 0001d4 000053 00&nbsp;&nbsp; A&nbsp; 0&nbsp;&nbsp; 0&nbsp; 1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 6] .gnu.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VERSYM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048228 000228 00000c 02&nbsp;&nbsp; A&nbsp; 4&nbsp;&nbsp; 0&nbsp; 2<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 7] .gnu.version_r&nbsp;&nbsp;&nbsp; VERNEED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048234 000234 000020 00&nbsp;&nbsp; A&nbsp; 5&nbsp;&nbsp; 1&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 8] .rel.dyn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048254 000254 000008 08&nbsp;&nbsp; A&nbsp; 4&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [ 9] .rel.plt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0804825c 00025c 000018 08&nbsp;&nbsp; A&nbsp; 4&nbsp;&nbsp; b&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [10] .init&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08048274 000274 000017 00&nbsp; AX&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [11] .plt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0804828c 00028c 000040 04&nbsp; AX&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [12] .text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080482d0 0002d0 0001e4 00&nbsp; AX&nbsp; 0&nbsp;&nbsp; 0 16<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [13] .fini&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080484b4 0004b4 00001b 00&nbsp; AX&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [14] .rodata&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080484d0 0004d0 00001a 00&nbsp;&nbsp; A&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [15] .eh_frame&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080484ec 0004ec 000004 00&nbsp;&nbsp; A&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [16] .data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080494f0 0004f0 00001c 00&nbsp; WA&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [17] .dynamic&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DYNAMIC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0804950c 00050c 0000c8 08&nbsp; WA&nbsp; 5&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [18] .ctors&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080495d4 0005d4 000008 00&nbsp; WA&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [19] .dtors&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080495dc 0005dc 000008 00&nbsp; WA&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [20] .jcr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080495e4 0005e4 000004 00&nbsp; WA&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [21] .got&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 080495e8 0005e8 00001c 04&nbsp; WA&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [22] .bss&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NOBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 08049604 000604 000008 00&nbsp; WA&nbsp; 0&nbsp;&nbsp; 0&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [23] .comment&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROGBITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000000 000604 000126 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp; 1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [24] .shstrtab&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STRTAB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000000 00072a 0000ce 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp; 1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [25] .symtab&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SYMTAB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000000 000c30 0004c0 10&nbsp;&nbsp;&nbsp;&nbsp; 26&nbsp; 2f&nbsp; 4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; [26] .strtab&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STRTAB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000000 0010f0 000275 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 0&nbsp; 1<br style="font: normal normal normal 12px/normal song, Verdana; "></div><div>Program Headers:<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Offset&nbsp;&nbsp; VirtAddr&nbsp;&nbsp; PhysAddr&nbsp;&nbsp; FileSiz MemSiz&nbsp; Flg Align<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; PHDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; INTERP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x000114 0x08048114 0x08048114 0x00013 0x00013 R&nbsp;&nbsp; 0x1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Requesting program interpreter: /lib/ld-linux.so.2]<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; LOAD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x000000 0x08048000 0x08048000 0x004f0 0x004f0 R E 0x1000<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; LOAD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x0004f0 0x080494f0 0x080494f0 0x00114 0x0011c RW&nbsp; 0x1000<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; DYNAMIC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00050c 0x0804950c 0x0804950c 0x000c8 0x000c8 RW&nbsp; 0x4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; NOTE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x000128 0x08048128 0x08048128 0x00020 0x00020 R&nbsp;&nbsp; 0x4<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp; STACK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW&nbsp; 0x4</div><div>&nbsp;</div><div>Symbol table '.symtab' contains 76 entries:</div><div><font color="#0080ff">对于.exe文件，符号的Value 是将来加载进内存中的真实地址；对于.so文件Value需要重定位.<br style="font: normal normal normal 12px/normal song, Verdana; "></font>&nbsp;&nbsp; Num:&nbsp;&nbsp;&nbsp; Value&nbsp; Size Type&nbsp;&nbsp;&nbsp; Bind&nbsp;&nbsp; Vis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ndx Name<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 0: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; LOCAL&nbsp; DEFAULT&nbsp; UND&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 1: 08048114&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 1&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 2: 08048128&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 2&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 3: 08048148&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 3&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 4: 08048174&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 4&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 5: 080481d4&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 5&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 6: 08048228&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 6&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 7: 08048234&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 7&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 8: 08048254&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 8&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp;&nbsp; 9: 0804825c&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 9&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 10: 08048274&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 10&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 11: 0804828c&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 11&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 12: 080482d0&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 12&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 13: 080484b4&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 13&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 14: 080484d0&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 14&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 15: 080484ec&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 15&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 16: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 16&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 17: 0804950c&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 17&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 18: 080495d4&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 18&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 19: 080495dc&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 19&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 20: 080495e4&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 20&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 21: 080495e8&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 21&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 22: 08049604&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 22&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 23: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 23&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 24: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 24&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 25: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 25&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 26: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 26&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 27: 080482f4&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 12 call_gmon_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 28: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS crtstuff.c<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 29: 080495d4&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 18 __CTOR_LIST__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 30: 080495dc&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 19 __DTOR_LIST__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 31: 080484ec&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 15 __EH_FRAME_BEGIN__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 32: 080495e4&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 20 __JCR_LIST__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 33: 080494f8&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 16 p.0<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 34: 08049604&nbsp;&nbsp;&nbsp;&nbsp; 1 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 22 completed.1<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 35: 08048320&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 12 __do_global_dtors_aux<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 36: 08048360&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 12 frame_dummy<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 37: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS crtstuff.c<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 38: 080495d8&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 18 __CTOR_END__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 39: 080495e0&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 19 __DTOR_END__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 40: 080484ec&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 15 __FRAME_END__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 41: 080495e4&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 20 __JCR_END__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 42: 08048490&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 12 __do_global_ctors_aux<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 43: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS aaa.c<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 44: 08049504&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 16 c444&nbsp;&nbsp;&nbsp;<font color="#0080ff"># static变量为LOCAL绑定属性(也即作用域) 已初始化静态变量存放在.data</font><br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 45: 08049508&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 16 c444.0&nbsp;<font color="#0080ff"># 已初始化静态变量存放在.data (多个源文件可以定义同名的静态变量)</font><br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 46: 08049608&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 22 c555&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 未初始化静态变量存放在.bss</font><br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 47: 080494fc&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 16 a111&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 全局变量为GLOBAL绑定属性&nbsp; 已初始全局变量存放在.data</font><br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 48: 0804950c&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 17 _DYNAMIC<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 49: 080484d0&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 14 _fp_hw<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 50: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL HIDDEN&nbsp; ABS __fini_array_end<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 51: 080494f4&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; GLOBAL HIDDEN&nbsp;&nbsp; 16 __dso_handle<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 52: 08048440&nbsp;&nbsp;&nbsp; 66 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 12 __libc_csu_fini<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 53: 08048274&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 10 _init<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 54: 0804829c&nbsp;&nbsp; 427 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND&nbsp;<a href="mailto:malloc@@GLIBC_2.0" style="text-decoration: underline; color: rgb(0, 68, 182); ">malloc@@GLIBC_2.0</a>&nbsp;&nbsp;&nbsp; 55: 080482d0&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 12 _start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 56: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL HIDDEN&nbsp; ABS __fini_array_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 57: 080483f0&nbsp;&nbsp;&nbsp; 71 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 12 __libc_csu_init<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 58: 08049500&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 16 p111<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 59: 08049604&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL DEFAULT&nbsp; ABS __bss_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 60: 0804838c&nbsp;&nbsp;&nbsp; 89 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 12 main<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 61: 080482ac&nbsp;&nbsp; 251 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND&nbsp;<a href="mailto:__libc_start_main@@GLIBC" style="text-decoration: underline; color: rgb(0, 68, 182); ">__libc_start_main@@GLIBC</a>_<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 62: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL HIDDEN&nbsp; ABS __init_array_end<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 63: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; WEAK&nbsp;&nbsp; DEFAULT&nbsp;&nbsp; 16 data_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 64: 080484b4&nbsp;&nbsp;&nbsp;&nbsp; 0 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 13 _fini<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 65: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL HIDDEN&nbsp; ABS __preinit_array_end<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 66: 08049604&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL DEFAULT&nbsp; ABS _edata<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 67: 080495e8&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 21 _GLOBAL_OFFSET_TABLE_<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 68: 0804960c&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL DEFAULT&nbsp; ABS _end<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 69: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL HIDDEN&nbsp; ABS __init_array_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 70: 080484d4&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 14 _IO_stdin_used<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 71: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 16 __data_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 72: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; WEAK&nbsp;&nbsp; DEFAULT&nbsp; UND _Jv_RegisterClasses<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 73: 080494f0&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; GLOBAL HIDDEN&nbsp; ABS __preinit_array_start<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 74: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp; WEAK&nbsp;&nbsp; DEFAULT&nbsp; UND __gmon_start__<br style="font: normal normal normal 12px/normal song, Verdana; ">&nbsp;&nbsp;&nbsp; 75: 080482bc&nbsp;&nbsp;&nbsp; 48 FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND&nbsp;<a href="mailto:strcpy@@GLIBC_2.0" style="text-decoration: underline; color: rgb(0, 68, 182); ">strcpy@@GLIBC_2.0</a></div><div>&nbsp;</div><div>&nbsp;</div><div>文件./aaa加载进内存后,再看看变量的地址以及所在的区:<br style="font: normal normal normal 12px/normal song, Verdana; ">[test@redhat]# gdb ./aaa<br style="font: normal normal normal 12px/normal song, Verdana; ">GNU gdb 6.1.1<br style="font: normal normal normal 12px/normal song, Verdana; ">(gdb) disassemble main<br style="font: normal normal normal 12px/normal song, Verdana; ">Dump of assembler code for function main:<br style="font: normal normal normal 12px/normal song, Verdana; ">0x0804838c &lt;main+0&gt;:&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp; %ebp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x0804838d &lt;main+1&gt;:&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %esp,%ebp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x0804838f &lt;main+3&gt;:&nbsp;&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; $0x18,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x08048392 &lt;main+6&gt;:&nbsp;&nbsp;&nbsp; and&nbsp;&nbsp;&nbsp; $0xfffffff0,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x08048395 &lt;main+9&gt;:&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; $0x0,%eax<br style="font: normal normal normal 12px/normal song, Verdana; ">0x0804839a &lt;main+14&gt;:&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; %eax,%esp</div><div><font color="#0000ff"># char s333[] = "abc";</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x0804839c &lt;main+16&gt;:&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; 0x80484df,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 0x80484df处为"abc"，位于.rodata</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483a1 &lt;main+21&gt;:&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %eax,0xfffffff8(%ebp)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 0xfffffff8(%ebp) 为局部变量 char s333[]</font></div><div><font color="#0080ff"># char *p333 = "123456";</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483a4 &lt;main+24&gt;:&nbsp;&nbsp; movl&nbsp;&nbsp; $0x80484e3,0xfffffff0(%ebp)&nbsp;&nbsp;<font color="#0080ff"># 0x80484e3处为"123456/0"，位于.rodata; 0xfffffff0(%ebp) 为局部变量 char *p333</font></div><div><font color="#0080ff"># p111 = (char *)malloc(10);</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ab &lt;main+31&gt;:&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; $0xc,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ae &lt;main+34&gt;:&nbsp;&nbsp; push&nbsp;&nbsp; $0xa&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 0xa=10 ; push $0xa后，此时堆栈esp值又减去4字节，相当于sub $0x10,%esp</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483b0 &lt;main+36&gt;:&nbsp;&nbsp; call&nbsp;&nbsp; 0x804829c &lt;malloc&gt;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483b5 &lt;main+41&gt;:&nbsp;&nbsp; add&nbsp;&nbsp;&nbsp; $0x10,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483b8 &lt;main+44&gt;:&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %eax,0x8049500&nbsp;&nbsp;<font color="#0080ff"># 0x8049500 为全局变量p111，位于.data</font></div><div><font color="#0080ff"># p222 = (char *)malloc(20);</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483bd &lt;main+49&gt;:&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; $0xc,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483c0 &lt;main+52&gt;:&nbsp;&nbsp; push&nbsp;&nbsp; $0x14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 0x14=20 ; push $0xa后，此时堆栈esp值又减去4字节，相当于sub $0x10,%esp</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483c2 &lt;main+54&gt;:&nbsp;&nbsp; call&nbsp;&nbsp; 0x804829c &lt;malloc&gt;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483c7 &lt;main+59&gt;:&nbsp;&nbsp; add&nbsp;&nbsp;&nbsp; $0x10,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ca &lt;main+62&gt;:&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %eax,0xfffffff4(%ebp)&nbsp;&nbsp;<font color="#0080ff"># 0xfffffff4(%ebp) 为局部变量p222</font></div><div><font color="#0080ff"># strcpy(p111, "123456");</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483cd &lt;main+65&gt;:&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; $0x8,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483d0 &lt;main+68&gt;:&nbsp;&nbsp; push&nbsp;&nbsp; $0x80484e3&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 0x80484e3处内容为"123456/0"，位于.rodata;</font>&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483d5 &lt;main+73&gt;:&nbsp;&nbsp; pushl&nbsp; 0x8049500&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff"># 0x8049500 为全局变量p111，位于.data</font><br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483db &lt;main+79&gt;:&nbsp;&nbsp; call&nbsp;&nbsp; 0x80482bc &lt;strcpy&gt;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e0 &lt;main+84&gt;:&nbsp;&nbsp; add&nbsp;&nbsp;&nbsp; $0x10,%esp<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e3 &lt;main+87&gt;:&nbsp;&nbsp; leave&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e4 &lt;main+88&gt;:&nbsp;&nbsp; ret&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e5 &lt;main+89&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e6 &lt;main+90&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e7 &lt;main+91&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e8 &lt;main+92&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483e9 &lt;main+93&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ea &lt;main+94&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483eb &lt;main+95&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ec &lt;main+96&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ed &lt;main+97&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ee &lt;main+98&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">0x080483ef &lt;main+99&gt;:&nbsp;&nbsp; nop&nbsp;&nbsp;&nbsp;&nbsp;<br style="font: normal normal normal 12px/normal song, Verdana; ">End of assembler dump.<br style="font: normal normal normal 12px/normal song, Verdana; ">(gdb) q<br style="font: normal normal normal 12px/normal song, Verdana; ">[test@redhat]#</div><div>&nbsp;</div></span>
<img src ="http://www.cppblog.com/elva/aggbug/99810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-10-30 10:55 <a href="http://www.cppblog.com/elva/archive/2009/10/30/99810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C 语言常用的排序算法</title><link>http://www.cppblog.com/elva/archive/2009/10/26/99507.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 26 Oct 2009 10:05:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/10/26/99507.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/99507.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/10/26/99507.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/99507.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/99507.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自：http://blog.csdn.net/chenqiang35/archive/2009/02/19/3909699.aspxview plaincopy to clipboardprint?/********************************************************************************************&nbsp;&...&nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2009/10/26/99507.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/99507.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-10-26 18:05 <a href="http://www.cppblog.com/elva/archive/2009/10/26/99507.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++常识之——内联函数和宏的区别</title><link>http://www.cppblog.com/elva/archive/2009/08/19/93778.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 19 Aug 2009 01:57:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/08/19/93778.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/93778.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/08/19/93778.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/93778.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/93778.html</trackback:ping><description><![CDATA[先说宏和函数的区别：<br>1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.<br>2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.<br>3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.<br>4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.<br>5. 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的. <br><br>  现在来看内联函数:<br>所谓"内联函数"就是将很简单的函数"内嵌"到调用他的程序代码中,只样做的目的是为了避免上面说到的第5点,目的旨在节约下原本函数调用时的时空开销.但必须注意的是:作为内联函数,函数体必须十分简单,不能含有循环、条件、选择等复杂的结构，否则就不能做为内联函数了。事实上，即便你没有指定函数为内联函数，有的编译系统也会自动将很简单的函数作为内联函数处理；而对于复杂的函数，即便你指定他为内联函数，系统也不会理会的。<br>
<img src ="http://www.cppblog.com/elva/aggbug/93778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-08-19 09:57 <a href="http://www.cppblog.com/elva/archive/2009/08/19/93778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++常识之——多态与重载</title><link>http://www.cppblog.com/elva/archive/2009/08/19/93777.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 19 Aug 2009 01:56:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/08/19/93777.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/93777.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/08/19/93777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/93777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/93777.html</trackback:ping><description><![CDATA[一.多态<br><br>多态（Polymorphism）按字面的意思就是&#8220;多种形状&#8221;。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术，赋值之后，父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作（摘自&#8220;Delphi4 编程技术内幕&#8221;）。简单的说，就是一句话：允许将子类类型的指针赋值给父类类型的指针。多态性在Object Pascal和C++中都是通过虚函数（Virtual Function） 实现的。<br><br>　　多态性是允许将父对象设置成为和一个和多个它的子对象相等的技术，比如Parent:=Child； 多态性使得能够利用同一类(基类)类型的指针来引用不同类的对象,以及根据所引用对象的不同,以不同的方式执行相同的操作.<br>　　多态的作用：把不同的子类对象都当作父类来看，可以屏蔽不同子类对象之间的差异，写出通用的代码，做出通用的编程，以适应需求的不断变化。<br>　　赋值之后，父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说，父亲的行为像儿子，而不是儿子的行为像父亲。 <br>　　举个例子：从一个基类中派生，响应一个虚命令，产生不同的结果。 <br>　　比如从某个基类继承出多个对象，其基类有一个虚方法Tdoit，然后其子类也有这个方法，但行为不同，然后这些子对象中的任何一个可以附给其基类的对象，这样其基类的对象就可以执行不同的操作了。实际上你是在通过其基类来访问其子对象的，你要做的就是一个赋值操作。<br>　　使用继承性的结果就是可以创建一个类的家族，在认识这个类的家族时，就是把导出类的对象 当作基类的的对象，这种认识又叫作upcasting。这样认识的重要性在于：我们可以只针对基类写出一段程序，但它可以适 应于这个类的家族，因为编译器会自动就找出合适的对象来执行操作。这种现象又称为多态性。而实现多态性的手段又叫称动态绑定(dynamic binding)。 <br>　　简单的说，建立一个父类的变量，它的内容可以是这个父类的，也可以是它的子类的,当子类拥有和父类同样的函数，当使用这个变量调用这个函数的时候，定义这个变量的类，也就是父类，里的同名函数将被调用，当在父类里的这个函数前加virtual关键字，那么子类的同名函数将被调用<br>　　class A {<br>　　public:<br>　　A() {}<br>　　virtual void foo() {<br>　　cout &lt;&lt; "This is A." &lt;&lt; endl;<br>　　}<br>　　};<br>　　class B : public A {<br>　　public:<br>　　B() {}<br>　　void foo() {<br>　　cout &lt;&lt; "This is B." &lt;&lt; endl;<br>　　}<br>　　};<br>　　int main(int argc, char* argv[]) {<br>　　A *a = new B();<br>　　a-&gt;foo();<br>　　return 0;<br>　　}<br>　　这将显示：<br>　　This is B.<br>　　如果把virtual去掉，将显示：<br>　　This is A. <br>　　前面的多态实现使用抽象类,并定义了虚方法.<br><br>二.重载<br><br>重载决策是一种编译时机制，用于在给定了参数列表和一组候选函数成员的情况下，选择一个最佳函数成员来实施调用。函数重载就是一个类中有几个同名函数但参数表不同：<br><br>重载分为普通方法重载和基类(也就是父类)虚方法的重载！<br><br>普通方法的重载指的是：类中两个以上的方法(包括隐藏的继承而来的方法)，取的名字相同，但使用的参数类型或者参数个数不同!<br><br>对基类方法的重载是函数重载的另一种特殊形式。在派生类中重新定义此虚函数！方法名称，返回值类型，参数表中的参数个数，类型，顺序都必须和基类中的虚函数完全一致！在派生类中声明对虚方法的重载，要求在声明中加上override关键字，而且不能有new，static或virtual修饰符！(这是转载别人的,其实这个是重写override)
<img src ="http://www.cppblog.com/elva/aggbug/93777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-08-19 09:56 <a href="http://www.cppblog.com/elva/archive/2009/08/19/93777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++常识之——静态成员与静态成员函数</title><link>http://www.cppblog.com/elva/archive/2009/08/19/93776.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 19 Aug 2009 01:56:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/08/19/93776.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/93776.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/08/19/93776.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/93776.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/93776.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; &nbsp;之所以需要定义静态变量or静态函数，是为了完成某些全局变量或函数才能完成的功能，而又不会破坏类的封装性同时也解决了对命名空间的污染。<br>静态可分为全局静态与局部静态：全局静态与普通变量的区别在于解决他的作用域，普通全局变量可以通过extern关键词被其他某块访问，而全局静态不可以，所以不会有命名冲突问题。<br>局部静态与普通局部变量的区别在于解决变量的生存期：因为静态成员在内存中只有一份（属于类而不属于对象），所以他的生存期和类的生存期是一样的，也就使得它可以记录下每个对象对他的操作结果。<br>下面再说说静态函数：<br>类的静态函数同样有静态变量的特性，同时静态函数只能调用类的静态成员变量或静态成员函数，因为其不属于任何对象，所以不能通过对象来调用。调用方式：类名：：function(); function可声明为private 或protected（这一点和普通成员函数是一样的）<br>
<img src ="http://www.cppblog.com/elva/aggbug/93776.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-08-19 09:56 <a href="http://www.cppblog.com/elva/archive/2009/08/19/93776.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++常识之——C++中堆和栈的区别，自由存储区、全局/静态存储区和常量存储区</title><link>http://www.cppblog.com/elva/archive/2009/08/19/93774.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 19 Aug 2009 01:54:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/08/19/93774.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/93774.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/08/19/93774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/93774.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/93774.html</trackback:ping><description><![CDATA[<div>文章来自一个论坛里的回帖，哪个论坛记不得了！<br><br>    在C++中，内存分成5个区，他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。<br>    栈，就是那些由编译器在需要的时候分配，在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。<br>    堆，就是那些由new分配的内存块，他们的释放编译器不去管，由我们的应用程序去控制，一般一个new就要对应一个delete。如果程序员没有释放掉，那么在程序结束后，操作系统会自动回收。<br>    自由存储区，就是那些由malloc等分配的内存块，他和堆是十分相似的，不过它是用free来结束自己的生命的。<br>    全局/静态存储区，全局变量和静态变量被分配到同一块内存中，在以前的C语言中，全局变量又分为初始化的和未初始化的（初始化的全局变量和静态变量在一块区域，未初始化的全局变量与静态变量在相邻的另一块区域，同时未被初始化的对象存储区可以通过void*来访问和操纵，程序结束后由系统自行释放），在C++里面没有这个区分了，他们共同占用同一块内存区。<br>    常量存储区，这是一块比较特殊的存储区，他们里面存放的是常量，不允许修改（当然，你要通过非正当手段也可以修改，而且方法很多）<br>明确区分堆与栈<br>    在bbs上，堆与栈的区分问题，似乎是一个永恒的话题，由此可见，初学者对此往往是混淆不清的，所以我决定拿他第一个开刀。<br>    首先，我们举一个例子：<br>    void f() { int* p=new int[5]; } <br>    这条短短的一句话就包含了堆与栈，看到new，我们首先就应该想到，我们分配了一块堆内存，那么指针p呢？他分配的是一块栈内存，所以这句话的意思就是：在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小，然后调用operator new分配内存，然后返回这块内存的首地址，放入栈中，他在VC6下的汇编代码如下：<br>    00401028   push        14h<br>    0040102A   call        operator new (00401060)<br>    0040102F   add         esp,4<br>    00401032   mov         dword ptr [ebp-8],eax<br>    00401035   mov         eax,dword ptr [ebp-8]<br>    00401038   mov         dword ptr [ebp-4],eax<br>    这里，我们为了简单并没有释放内存，那么该怎么去释放呢？是delete p么？澳，错了，应该是delete []p，这是为了告诉编译器：我删除的是一个数组，VC6就会根据相应的Cookie信息去进行释放内存的工作。<br>    好了，我们回到我们的主题：堆和栈究竟有什么区别？ <br>    主要的区别由以下几点：<br>    1、管理方式不同；<br>    2、空间大小不同；<br>    3、能否产生碎片不同；<br>    4、生长方向不同；<br>    5、分配方式不同；<br>    6、分配效率不同；<br>    管理方式：对于栈来讲，是由编译器自动管理，无需我们手工控制；对于堆来说，释放工作由程序员控制，容易产生memory leak。<br>    空间大小：一般来讲在32位系统下，堆内存可以达到4G的空间，从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲，一般都是有一定的空间大小的，例如，在VC6下面，默认的栈空间大小是1M（好像是，记不清楚了）。当然，我们可以修改：    <br>    打开工程，依次操作菜单如下：Project-&gt;Setting-&gt;Link，在Category 中选中Output，然后在Reserve中设定堆栈的最大值和commit。<br>注意：reserve最小值为4Byte；commit是保留在虚拟内存的页文件里面，它设置的较大会使栈开辟较大的值，可能增加内存的开销和启动时间。<br>    碎片问题：对于堆来讲，频繁的new/delete势必会造成内存空间的不连续，从而造成大量的碎片，使程序效率降低。对于栈来讲，则不会存在这个问题，因为栈是先进后出的队列，他们是如此的一一对应，以至于永远都不可能有一个内存块从栈中间弹出，在他弹出之前，在他上面的后进的栈内容已经被弹出，详细的可以参考数据结构，这里我们就不再一一讨论了。<br>    生长方向：对于堆来讲，生长方向是向上的，也就是向着内存地址增加的方向；对于栈来讲，它的生长方向是向下的，是向着内存地址减小的方向增长。<br>    分配方式：堆都是动态分配的，没有静态分配的堆。栈有2种分配方式：静态分配和动态分配。静态分配是编译器完成的，比如局部变量的分配。动态分配由alloca函数进行分配，但是栈的动态分配和堆是不同的，他的动态分配是由编译器进行释放，无需我们手工实现。<br>    分配效率：栈是机器系统提供的数据结构，计算机会在底层对栈提供支持：分配专门的寄存器存放栈的地址，压栈出栈都有专门的指令执行，这就决定了栈的效率比较高。堆则是C/C++函数库提供的，它的机制是很复杂的，例如为了分配一块内存，库函数会按照一定的算法（具体的算法可以参考数据结构/操作系统）在堆内存中搜索可用的足够大小的空间，如果没有足够大小的空间（可能是由于内存碎片太多），就有可能调用系统功能去增加程序数据段的内存空间，这样就有机会分到足够大小的内存，然后进行返回。显然，堆的效率比栈要低得多。<br>    从这里我们可以看到，堆和栈相比，由于大量new/delete的使用，容易造成大量的内存碎片；由于没有专门的系统支持，效率很低；由于可能引发用户态和核心态的切换，内存的申请，代价变得更加昂贵。所以栈在程序中是应用最广泛的，就算是函数的调用也利用栈去完成，函数调用过程中的参数，返回地址，EBP和局部变量都采用栈的方式存放。所以，我们推荐大家尽量用栈，而不是用堆。<br>    虽然栈有如此众多的好处，但是由于和堆相比不是那么灵活，有时候分配大量的内存空间，还是用堆好一些。<br>    无论是堆还是栈，都要防止越界现象的发生（除非你是故意使其越界），因为越界的结果要么是程序崩溃，要么是摧毁程序的堆、栈结构，产生以想不到的结果,就算是在你的程序运行过程中，没有发生上面的问题，你还是要小心，说不定什么时候就崩掉，那时候debug可是相当困难的：）<br>    对了，还有一件事，如果有人把堆栈合起来说，那它的意思是栈，可不是堆，呵呵，清楚了？<br><br>static用来控制变量的存储方式和可见性<br>    函数内部定义的变量，在程序执行到它的定义处时，编译器为它在栈上分配空间，函数在栈上分配的空间在此函数执行结束时会释放掉，这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时，如何实现？ 最容易想到的方法是定义一个全局的变量，但定义为一个全局变量有许多缺点，最明显的缺点是破坏了此变量的访问范围（使得在此函数中定义的变量，不仅仅受此 函数控制）。<br><br>需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部，对外不可见。<br><br>static的内部机制：<br>    静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用，所以静态数据成员不能在任何函数内分配空间和初始化。这样，它的空间分配有三个可能的地方，一是作为类的外部接口的头文件，那里有类声明；二是类定义的内部实现，那里有类的成员函数定义；三是应用程序的main（）函数前的全局数据声明和定义处。<br>    静态数据成员要实际地分配空间，故不能在类的声明中定义（只能声明数据成员）。类声明只声明一个类的&#8220;尺寸和规格&#8221;，并不进行实际的内存分配，所以在类声 明中写成定义是错误的。它也不能在头文件中类声明的外部定义，因为那会造成在多个使用该类的源文件中，对其重复定义。<br>    static被引入以告知编译器，将变量存储在程序的静态存储区而非栈上空间，静态<br>数据成员按定义出现的先后顺序依次初始化，注意静态成员嵌套时，要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。<br><br>static的优势：<br>    可以节省内存，因为它是所有对象所公有的，因此，对多个对象来说，静态数据成员只存储一处，供所有对象共用。静态数据成员的值对每个对象都是一样，但它的 值是可以更新的。只要对静态数据成员的值更新一次，保证所有对象存取更新后的相同的值，这样可以提高时间效率。引用静态数据成员时，采用如下格式：<br>    &lt;类名&gt;::&lt;静态成员名&gt;<br>    如果静态数据成员的访问权限允许的话(即public的成员)，可在程序中，按上述格式<br>来引用静态数据成员。<br><br>ps:<br>    (1)类的静态成员函数是属于整个类而非类的对象，所以它没有this指针，这就导致了它仅能访问类的静态数据和静态成员函数。<br>    (2)不能将静态成员函数定义为虚函数。<br>    (3)由于静态成员声明于类中，操作于其外，所以对其取地址操作，就多少有些特殊，变量地址是指向其数据类型的指针 ，函数地址类型是一个&#8220;nonmember函数指针&#8221;。<br>    (4)由于静态成员函数没有this指针，所以就差不多等同于nonmember函数，结果就产生了一个意想不到的好处：成为一个callback函数，使得我们得以将c++和c-based x window系统结合，同时也成功的应用于线程函数身上。<br>    (5)static并没有增加程序的时空开销，相反她还缩短了子类对父类静态成员的访问时间，节省了子类的内存空间。<br>    (6)静态数据成员在&lt;定义或说明&gt;时前面加关键字static。<br>    (7)静态数据成员是静态存储的，所以必须对它进行初始化。<br>    (8)静态成员初始化与一般数据成员初始化不同:<br>    初始化在类体外进行，而前面不加static，以免与一般静态变量或对象相混淆；<br>    初始化时不加该成员的访问权限控制符private，public等；<br>    初始化时使用作用域运算符来标明它所属类；<br>    所以我们得出静态数据成员初始化的格式：<br>    &lt;数据类型&gt;&lt;类名&gt;::&lt;静态数据成员名&gt;=&lt;值&gt;<br>    (9)为了防止父类的影响，可以在子类定义一个与父类相同的静态变量，以屏蔽父类的影响。这里有一点需要注意：我们说静态成员为父类和子类共享，但我们有 重复定义了静态成员，这会不会引起错误呢？不会，我们的编译器采用了一种绝妙的手法：name-mangling 用以生成唯一的标志。<br><br>－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br><br>【转】全局变量静态变量<br><br>static 声明的变量在C语言中有两方面的特征：<br>　　1)、变量会被放在程序的全局存储区中，这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。<br>　　2)、变量用static告知编译器，自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。<br>Tips:<br>　　A.若全局变量仅在单个C文件中访问，则可以将这个变量修改为静态全局变量，以降低模块间的耦合度；<br>　　B.若全局变量仅由单个函数访问，则可以将这个变量改为该函数的静态局部变量，以降低模块间的耦合度；<br>　　C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时，需要考虑重入问题；<br>         D.如果我们需要一个可重入的函数，那么，我们一定要避免函数中使用static变量(这样的函数被称为：带&#8220;内部存储器&#8221;功能的的函数)<br>         E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时，则必须是static的局部变量的地址作为返回值，若为auto类型，则返回为错指针。<br><br>函数前加static使得函数成为静态函数。但此处&#8220;static&#8221;的含义不是指存储方式，而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是：不同的人编写不同的函数时，不用担心自己定义的函数，是否会与其它文件中的函数同名。<br><br>扩展分析:术语static有着不寻常的历史.起初，在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量。随后，static在C中有了第二种含义：用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字，所以仍使用static关键字来表示这第二种含义。最后，C++重用了这个关键字，并赋予它与前面不同的第三种含义：表示属于一个类而不是属于此类的任何特定对象的变量和函数(与Java中此关键字的含义相同)。<br><br>全局变量、静态全局变量、静态局部变量和局部变量的区别<br>变量可以分为：全局变量、静态全局变量、静态局部变量和局部变量。<br>           按存储区域分，全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域，局部变量存放在内存的栈区。<br>           按作用域分，全局变量在整个工程文件内都有效；静态全局变量只在定义它的文件内有效；静态局部变量只在定义它的函数内有效，只是程序仅分配一次内存，函数返回后，该变量不会消失；局部变量在定义它的函数内有效，但是函数返回后失效。<br>全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式， 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序， 当一个源程序由多个源文件组成时，非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域， 即只在定义该变量的源文件内有效， 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内，只能为该源文件内的函数公用， 因此可以避免在其它源文件中引起错误。<br>　　从以上分析可以看出， 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域， 限制了它的使用范围。<br><br>　　static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static)，内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数，应该在一个头文件中说明，要使用这些函数的源文件要包含这个头文件<br><br>　　static全局变量与普通的全局变量有什么区别：static全局变量只初使化一次，防止在其他文件单元中被引用;<br>　　static局部变量和普通局部变量有什么区别：static局部变量只被初始化一次，下一次依据上一次结果值；<br>        static函数与普通函数有什么区别：static函数在内存中只有一份，普通函数在每个被调用中维持一份拷贝<br>        全局变量和静态变量如果没有手工初始化，则由编译器初始化为0。局部变量的值不可知。<br><br></div>
<img src ="http://www.cppblog.com/elva/aggbug/93774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-08-19 09:54 <a href="http://www.cppblog.com/elva/archive/2009/08/19/93774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CToolTipCtrl使用详细解说</title><link>http://www.cppblog.com/elva/archive/2009/07/06/89370.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 06 Jul 2009 07:25:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/07/06/89370.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/89370.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/07/06/89370.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/89370.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/89370.html</trackback:ping><description><![CDATA[<span class=Apple-style-span style="WORD-SPACING: 0px; FONT: 16px simsun; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate; orphans: 2; widows: 2; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span class=Apple-style-span style="FONT-SIZE: 12px; LINE-HEIGHT: 18px; FONT-FAMILY: arial">
<p><font size=-1>摘要：CToolTipCtrl的一般用法和动态改变ToolTip的显示内容的方法及步骤。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;链接：VCHelp:<span class=Apple-converted-space>&nbsp;</span><a href="http://www.vchelp.net/" target=_blank><u><font color=#0000ff>http://www.vchelp.net</font></u></a><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>CToolTipCtrl使用详细解说</strong><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;by 闻怡洋<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;ToolTip是Win32中一个通用控件，MFC中为其生成了一个类CToolTipCtrl，总的说来其使用方法是较简单的，下面讲一下它的一般用法和高级用法。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;一般用法步骤：<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;1.添加CToolTipCtrl成员变量 m_tt。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;2.在父窗口中调用EnableToolTips(TRUE);<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;3.在窗口的OnCreate（或者其他适当的位置）中向ToolTip中添加需要显示Tip的子窗口，并同时指定相应的显示字串CToolTipCtrl::AddTool(pWnd,"string to display")。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;4.重载父窗口的 BOOL PreTranslateMessage(MSG* pMsg) ，在函数中调用 m_tt.RelayEvent(pMsg)。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;下面假设在窗口CWndYour中使用CToolTipCtrl<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;在类定义中添加变量说明：<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<font face="Courier New" size=2><font color=#0000ff><strong>class<span class=Apple-converted-space>&nbsp;</span></strong></font>CWndYour:xxx<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>{<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>CToolTipCtrl m_tt;<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>}<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font></font><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;在OnCreate中添加需要显示Tip的子窗口<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<font face="Courier New" size=2><font color=#000000>CWndYour::OnCreate(....)<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>{<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>EnableToolTips(TRUE);<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>m_tt.Create(<font color=#0000ff><strong>this</strong></font>);<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>m_tt.Activate(TRUE);<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>CWnd* pW=GetDlgItem(IDC_CHECK1);<font color=#008000>//得到窗口指针</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>m_tooltip.AddTool(pW,"Check1");<font color=#008000>//添加</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>........<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>}<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font></font><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;在BOOL PreTranslateMessage(MSG* pMsg)中添加代码<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL CWndYour::PreTranslateMessage(MSG* pMsg)<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;{<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; {<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; m_tt.RelayEvent(pMsg);<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; }<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; return CParentClass::PreTranslateMessage(pMsg);<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;}<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;这样当鼠标移动到相应的子窗口上时会显示出相应的ToolTip。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;动态改变ToolTip的显示内容的方法及步骤：<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;1.上面所讲的1、2、4步骤。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;2.在增加ToolTip时不指定显示的字串，而是使用LPSTR_TEXTCALLBACK。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;3.在窗口中增加消息映射 ON_NOTIFY_EX( TTN_NEEDTEXT, 0, SetTipText )。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;4.在窗口中增加一个函数用于动态提供显示内容，其原型为 BOOL SetTipText( UINT id, NMHDR * pTTTStruct, LRESULT * pResult )，下面的代码可以根据传入的参数判定应该显示的内容。<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<font face="Courier New" size=2><font color=#000000>BOOL CWndYour::SetTipText( UINT id, NMHDR * pTTTStruct, LRESULT * pResult )<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>{<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pTTTStruct;<span class=Apple-converted-space>&nbsp;</span><font color=#ffffff><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>UINT nID =pTTTStruct-&gt;idFrom;<span class=Apple-converted-space>&nbsp;</span><font color=#008000>//得到相应窗口ID，有可能是HWND</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>if<span class=Apple-converted-space>&nbsp;</span></strong></font>(pTTT-&gt;uFlags &amp; TTF_IDISHWND)<span class=Apple-converted-space>&nbsp;</span><font color=#008000>//表明nID是否为HWND</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>{<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>nID = ::GetDlgCtrlID((HWND)nID);<font color=#008000>//从HWND得到ID值，当然你也可以通过HWND值来判断</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>switch</strong></font>(nID)<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>case</strong></font>(IDC_YOUR_CONTROL1)<span class=Apple-converted-space>&nbsp;</span><font color=#ffffff><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>strcpy(pTTT-&gt;lpszText,your_string1);<font color=#008000>//设置</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>return<span class=Apple-converted-space>&nbsp;</span></strong></font>TRUE;<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>break</strong></font>;<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>case</strong></font>(IDC_YOUR_CONTROL2)<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#008000>//设置相应的显示字串</font><font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>return<span class=Apple-converted-space>&nbsp;</span></strong></font>TRUE;<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>break</strong></font>;<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font>}<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><strong>return</strong></font>(FALSE);<font color=#ffffff><span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font>}<span class=Apple-converted-space>&nbsp;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</font></font></font></font></p>
<font size=-1><font face="Courier New" size=2>
<p><font size=-1><em>文章来源：<strong>VCHelp</strong>。</em></font></p>
</font></font></span></span>
<img src ="http://www.cppblog.com/elva/aggbug/89370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-07-06 15:25 <a href="http://www.cppblog.com/elva/archive/2009/07/06/89370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>libtool的“command not found”问题</title><link>http://www.cppblog.com/elva/archive/2009/05/16/83135.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Sat, 16 May 2009 09:53:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/05/16/83135.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/83135.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/05/16/83135.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/83135.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/83135.html</trackback:ping><description><![CDATA[<p>libtool生成的脚本中一行</p>
<p>ECHO="echo"</p>
<p>导致脚本引用小写echo的时候错误，不知为何导致这种问题，<br></p>
<p><br></p>
<p>终于查到解决办法：<br></p>
<p><br></p>
<p>I think I have a workaround to fix this problem:</p>
<p>First I've copied the directory "/usr/share/<wbr>apps/kdevappwiz<wbr>ard/" to "$HOME/<wbr>.kde/share/<wbr>apps/". Next I've extract the archive "$HOME/<wbr>.kde/share/<wbr>apps/kdevappwiz<wbr>ard/template-<wbr>common/<wbr>incadmin.<wbr>tar.gz" and I've replaced the old file "ltmain.sh" with the new one from "/usr/share/<wbr>libtool/<wbr>config/<wbr>ltmain.<wbr>sh".
Then I've packed them again to a new file named "incadmin.tar.gz" and
replaced the old archive with the new one. Now the script ltmain.sh
creates a current libtool while compilation and my source code compiles
without any error.</p>
<p>I have attached my new archive "incadmin.tar.gz" with the new file "ltmain.sh" included. Hope this will help.、</p>
<p><br></p>
<p>版本:可能换低版本也可以解决，问题版本是：<br></p>
<p>qian@qian:~/work/sdf/debug/src$ libtool --version<br>ltmain.sh (GNU libtool) 2.2.6<br>Written by Gordon Matzigkeit &lt;gord@gnu.ai.mit.edu&gt;, 1996<br><br>Copyright (C) 2008 Free Software Foundation, Inc.<br>This is free software; see the source for copying conditions.&nbsp; There is NO<br>warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.<br>低<br></p><img src ="http://www.cppblog.com/elva/aggbug/83135.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-05-16 17:53 <a href="http://www.cppblog.com/elva/archive/2009/05/16/83135.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC使用CRT调试功能来检测内存泄漏</title><link>http://www.cppblog.com/elva/archive/2009/05/06/82037.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 06 May 2009 06:55:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/05/06/82037.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/82037.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/05/06/82037.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/82037.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/82037.html</trackback:ping><description><![CDATA[C/C++ 编程语言的最强大功能之一便是其动态分配和释放内存，但是中国有句古话：&#8220;最大的长处也可能成为最大的弱点&#8221;，那么 C/C++ 应用程序正好印证了这句话。在 C/C++ 应用程序开发过程中，动态分配的内存处理不当是最常见的问题。其中，最难捉摸也最难检测的错误之一就是内存泄漏，即未能正确释放以前分配的内存的错误。偶尔发生的少量内存泄漏可能不会引起我们的注意，但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种 各样的征兆：从性能不良（并且逐渐降低）到内存完全耗尽。更糟的是，泄漏的程序可能会用掉太多内存，导致另外一个程序垮掉，而使用户无从查找问题的真正根源。此外，即使无害的内存泄漏也可能殃及池鱼。<br><br>幸运的是，Visual Studio 调试器和 C 运行时 (CRT) 库为我们提供了检测和识别内存泄漏的有效方法。下面请和我一起分享收获——如何使用 CRT 调试功能来检测内存泄漏？<br><br>一、如何启用内存泄漏检测机制<br><br>　　VC++ IDE 的默认状态是没有启用内存泄漏检测机制的，也就是说即使某段代码有内存泄漏，调试会话的 Output 窗口的 Debug 页不会输出有关内存泄漏信息。你必须设定两个最基本的机关来启用内存泄漏检测机制。<br><br>　　一是使用调试堆函数：<br>#define _CRTDBG_MAP_ALLOC <br>#include&lt;stdlib.h&gt; <br><br>#include&lt;crtdbg.h&gt;<br><br>注意：#include 语句的顺序。如果更改此顺序，所使用的函数可能无法正确工作。<br><br>　　通过包含 crtdbg.h 头文件，可以将 malloc 和 free 函数映射到其&#8220;调试&#8221;版本 _malloc_dbg 和 _free_dbg，这些函数会跟踪内存分配和释放。此映射只在调试（Debug）版本（也就是要定义 _DEBUG）中有效。发行版本（Release）使用普通的 malloc 和 free 函数。#define 语句将 CRT 堆函数的基础版本映射到对应的&#8220;调试&#8221;版本。该语句不是必须的，但如果没有该语句，那么有关内存泄漏的信息会不全。<br><br>　　二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息：<br><br>_CrtDumpMemoryLeaks();<br><br><br>　　当在调试器下运行程序时，_CrtDumpMemoryLeaks 将在 Output 窗口的 Debug 页中显示内存泄漏信息。比如： Detected memory leaks!<br>Dumping objects -&gt;<br><br>C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.<br><br>Data: &lt;AB&gt; 41 42<br><br><br><br>c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {44} normal <br>block at 0x00441BD0, 33 bytes long.<br><br>Data: &lt; C &gt; 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD<br><br><br><br>c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {43} normal <br>block at 0x00441C20, 40 bytes long.<br><br>Data: &lt; C &gt; 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00<br><br><br><br>Object dump complete.<br><br>如果不使用 #define _CRTDBG_MAP_ALLOC 语句，内存泄漏的输出是这样的：<br><br><br>Detected memory leaks!<br><br>Dumping objects -&gt;<br><br>{45} normal block at 0x00441BA0, 2 bytes long.<br>Data: &lt;AB&gt; 41 42 <br><br>{44} normal block at 0x00441BD0, 33 bytes long.<br>Data: &lt; C &gt; 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD <br><br>{43} normal block at 0x00441C20, 40 bytes long.<br>Data: &lt; C &gt; C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00 <br><br>Object dump complete.<br><br><br><br>　　根据这段输出信息，你无法知道在哪个源程序文件里发生了内存泄漏。下面我们来研究一下输出信息的格式。第一行和第二行没有什么可说的，从第三行开始：<br><br><br>xx}：花括弧内的数字是内存分配序号，本文例子中是 {45}，{44}，{43}；<br>block：内存块的类型，常用的有三种：normal（普通）、client（客户端）或 CRT（运行时）；本文例子中是：normal block； <br>用十六进制格式表示的内存位置，如：at 0x00441BA0 等；<br>以字节为单位表示的内存块的大小，如：32 bytes long； <br>前 16 字节的内容（也是用十六进制格式表示），如：Data: 41 42 等；<br><br><br>　　仔细观察不难发现，如果定义了 _CRTDBG_MAP_ALLOC ，那么在内存分配序号前面还会显示在其中分配泄漏内存的文件名，以及文件名后括号中的数字表示发生泄漏的代码行号，比如： <br><br><br>C:\Temp\memleak\memleak.cpp(15)<br><br><br>　　双击 Output 窗口中此文件名所在的输出行，便可跳到源程序文件分配该内存的代码行（也可以选中该行，然后按 F4，效果一样） ，这样一来我们就很容易定位内存泄漏是在哪里发生的了，因此，_CRTDBG_MAP_ALLOC 的作用显而易见。<br><br>使用 _CrtSetDbgFlag<br>　　如果程序只有一个出口，那么调用 _CrtDumpMemoryLeaks 的位置是很容易选择的。但是，如果程序可能会在多个地方退出该怎么办呢？在每一个可能的出口处调用 _CrtDumpMemoryLeaks 肯定是不可取的，那么这时可以在程序开始处包含下面的调用：_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );这条语句无论程序在什么地方退出都会自动调用 _CrtDumpMemoryLeaks。注意：这里必须同时设置两个位域标志：_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。<br><br>设置 CRT 报告模式<br>　　默认情况下，_CrtDumpMemoryLeaks 将内存泄漏信息 dump 到 Output 窗口的 Debug 页， 如果你想将这个输出定向到别的地方，可以使用 _CrtSetReportMode 进行重置。如果你使用某个库，它可能将输出定向到另一位置。此时，只要使用以下语句将输出位置设回 Output 窗口即可：<br><br><br>_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );<br><br>　　有关使用 _CrtSetReportMode 的详细信息，请参考 MSDN 库关于 _CrtSetReportMode 的描述。<br><br>二、解释内存块类型<br><br>　　前面已经说过，内存泄漏报告中把每一块泄漏的内存分为 normal（普通块）、client（客户端块）和 CRT 块。事实上，需要留心和注意的也就是 normal 和 client，即普通块和客户端块。<br>　　1.normal block（普通块）：这是由你的程序分配的内存。<br>　　2.client block（客户块）：这是一种特殊类型的内存块，专门用于 MFC 程序中需要析构函数的对象。MFC new 操作符视具体情况既可以为所创建的对象建立普通块，也可以为之建立客户块。<br>　　3.CRT block（CRT 块）：是由 C RunTime Library 供自己使用而分配的内存块。由 CRT 库自己来管理这些内存的分配与释放，我们一般不会在内存泄漏报告中发现 CRT 内存泄漏，除非程序发生了严重的错误（例如 CRT 库崩溃）。 <br><br>　　除了上述的类型外，还有下面这两种类型的内存块，它们不会出现在内存泄漏报告中：<br>　　1.free block（空闲块）：已经被释放(free)的内存块。 <br>　　2.Ignore block（忽略块）：这是程序员显式声明过不要在内存泄漏报告中出现的内存块。<br><br>三、如何在内存分配序号处设置断点<br><br>　　在内存泄漏报告中，的文件名和行号可告诉分配泄漏的内存的代码位置，但仅仅依赖这些信息来了解完整的泄漏原因是不够的。因为一个程序在运行时，一段分配内存的代码可能会被调用很多次，只要有一次调用后没有释放内存就会导致内存泄漏。为了确定是哪些内存没有被释放，不仅要知道泄漏的内存是在哪里分配的，还要知道泄漏产生的条件。这时内存分配序号就显得特别有用——这个序号就是文件名和行号之后的花括弧里的那个数字。 <br><br><br>　　例如，在本文例子代码的输出信息中，&#8220;45&#8221;是内存分配序号，意思是泄漏的内存是你程序中分配的第四十五个内存块：<br><br><br>Detected memory leaks!<br><br>Dumping objects -&gt;<br><br>C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.<br><br>Data: &lt;AB&gt; 41 42 <br><br>......<br><br>Object dump complete.<br><br><br>　　CRT 库对程序运行期间分配的所有内存块进行计数，包括由 CRT 库自己分配的内存和其它库（如 MFC）分配的内存。因此，分配序号为 N 的对象即为程序中分配的第 N 个对象，但不一定是代码分配的第 N 个对象。（大多数情况下并非如此。）这样的话，你便可以利用分配序号在分配内存的位置设置一个断点。方法是在程序起始附近设置一个位置断点。当程序在该点中断时，可以从 QuickWatch（快速监视）对话框或 Watch（监视）窗口设置一个内存分配断点：<br><br>　　例如，在 Watch 窗口中，在 Name 栏键入下面的表达式：<br><br><br>_crtBreakAlloc<br><br><br>　　如果要使用 CRT 库的多线程 DLL 版本（/MD 选项），那么必须包含上下文操作符，像这样： <br><br><br>{,,msvcrtd.dll}_crtBreakAlloc<br><br><br>　　现在按下回车键，调试器将计算该值并把结果放入 Value 栏。如果没有在内存分配点设置任何断点，该值将为 &#8211;1。<br><br>　　用你想要在其位置中断的内存分配的分配序号替换 Value 栏中的值。例如输入 45。这样就会在分配序号为 45 的地方中断。 <br><br>　　在所感兴趣的内存分配处设置断点后，可以继续调试。这时，运行程序时一定要小心，要保证内存块分配的顺序不会改变。当程序在指定的内存分配处中断时，可以查看 Call Stack（调用堆栈）窗口和其它调试器信息以确定分配内存时的情况。如果必要，可以从该点继续执行程序，以查看对象发生了什么情况，或许可以确定未正确释放对象的原因。<br><br>　　尽管通常在调试器中设置内存分配断点更方便，但如果愿意，也可在代码中设置这些断点。为了在代码中设置一个内存分配断点，可以增加这样一行（对于第四十五个内存分配）：<br><br><br>_crtBreakAlloc = 45;<br><br><br>　　你还可以使用有相同效果的 _CrtSetBreakAlloc 函数：<br><br><br>_CrtSetBreakAlloc(45);<br><br><br><br>四、如何比较内存状态<br><br>　　定位内存泄漏的另一个方法就是在关键点获取应用程序内存状态的快照。CRT 库提供了一个结构类型 _CrtMemState。你可以用它来存储内存状态的快照：<br><br><br>_CrtMemState s1, s2, s3;<br><br><br>　　若要获取给定点的内存状态快照，可以向 _CrtMemCheckpoint 函数传递一个 _CrtMemState 结构。该函数用当前内存状态的快照填充此结构：<br><br><br>_CrtMemCheckpoint( &amp;s1 );<br><br><br>　　通过向 _CrtMemDumpStatistics 函数传递 _CrtMemState 结构，可以在任意地方 dump 该结构的内容：<br><br><br>_CrtMemDumpStatistics( &amp;s1 );<br><br><br>　　该函数输出如下格式的 dump 内存分配信息：<br><br><br>0 bytes in 0 Free Blocks.<br>75 bytes in 3 Normal Blocks.<br>5037 bytes in 41 CRT Blocks.<br>0 bytes in 0 Ignore Blocks.<br>0 bytes in 0 Client Blocks.<br>Largest number used: 5308 bytes.<br>Total allocations: 7559 bytes.<br><br><br>　　若要确定某段代码中是否发生了内存泄漏，可以通过获取该段代码之前和之后的内存状态快照，然后使用 _CrtMemDifference 比较这两个状态：<br><br><br>_CrtMemCheckpoint( &amp;s1 );// 获取第一个内存状态快照<br><br>// 在这里进行内存分配<br><br>_CrtMemCheckpoint( &amp;s2 );// 获取第二个内存状态快照<br><br>// 比较两个内存快照的差异<br>if ( _CrtMemDifference( &amp;s3, &amp;s1, &amp;s2) )<br>_CrtMemDumpStatistics( &amp;s3 );// dump 差异结果<br><br><br>　　顾名思义，_CrtMemDifference 比较两个内存状态（前两个参数），生成这两个状态之间差异的结果（第三个参数）。在程序的开始和结尾放置 _CrtMemCheckpoint 调用，并使用 _CrtMemDifference 比较结果，是检查内存泄漏的另一种方法。如果检测到泄漏，则可以使用 _CrtMemCheckpoint 调用通过二进制搜索技术来分割程序和定位泄漏。<br><br><br><br>五、结论<br><br>　　尽管 VC ++ 具有一套专门调试 MFC 应用程序的机制，但本文上述<span class=t_tag onclick=tagshow(event) href="tag.php?name=%E8%AE%A8%E8%AE%BA">讨论</span>的内存分配很简单，没有涉及到 MFC 对象，所以这些内容同样也适用于 MFC 程序。在 MSDN 库中可以找到很多有关 VC++ 调试方面的资料，如果你能善用 MSDN 库，相信用不了多少时间你就有可能成为调试高手。
<img src ="http://www.cppblog.com/elva/aggbug/82037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-05-06 14:55 <a href="http://www.cppblog.com/elva/archive/2009/05/06/82037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC MFC SDI/MDI框架各部分指针获取方式</title><link>http://www.cppblog.com/elva/archive/2009/04/07/79154.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 07 Apr 2009 02:51:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/04/07/79154.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/79154.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/04/07/79154.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/79154.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/79154.html</trackback:ping><description><![CDATA[<span  style="color: rgb(51, 51, 51); font-family: Arial; font-size: 13px; line-height: 20px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "><div class="c_b" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><br></div><div class="c_neirong" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">&#160;&#160;&#160;&#160;<div goog_ds_charindex="43" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><table cellspacing="0" cellpadding="3" width="580" border="1" goog_ds_charindex="44" style="table-layout: auto; line-height: normal; "><tbody goog_ds_charindex="45" style="line-height: normal; "><tr goog_ds_charindex="46" style="line-height: normal; "><td width="16%" goog_ds_charindex="47" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p align="center" goog_ds_charindex="48" style="font-size: 10pt; line-height: normal; "></p></td><td width="16%" goog_ds_charindex="50" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p align="center" goog_ds_charindex="51" style="font-size: 10pt; line-height: normal; "><strong goog_ds_charindex="52" style="line-height: normal; ">获得CWinApp</strong></p></td><td width="16%" goog_ds_charindex="66" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p align="center" goog_ds_charindex="67" style="font-size: 10pt; line-height: normal; "><strong goog_ds_charindex="68" style="line-height: normal; ">获得CMainFrame</strong></p></td><td width="16%" goog_ds_charindex="85" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p align="center" goog_ds_charindex="86" style="font-size: 10pt; line-height: normal; "><strong goog_ds_charindex="87" style="line-height: normal; ">获得CChildFrame</strong></p></td><td width="16%" goog_ds_charindex="105" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p align="center" goog_ds_charindex="106" style="font-size: 10pt; line-height: normal; "><strong goog_ds_charindex="107" style="line-height: normal; ">获得CDocument</strong></p></td><td width="16%" goog_ds_charindex="123" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p align="center" goog_ds_charindex="124" style="font-size: 10pt; line-height: normal; "><strong goog_ds_charindex="125" style="line-height: normal; ">获得CView</strong></p></td></tr><tr goog_ds_charindex="138" style="line-height: normal; "><td width="16%" goog_ds_charindex="139" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><strong goog_ds_charindex="140" style="line-height: normal; ">在CWinApp中</strong></td><td width="16%" goog_ds_charindex="153" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="154" style="font-size: 10pt; line-height: normal; "></p></td><td width="16%" goog_ds_charindex="156" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="157" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()</p><p goog_ds_charindex="175" style="font-size: 10pt; line-height: normal; ">m_pMainWnd</p></td><td width="16%" goog_ds_charindex="189" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="190" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()->MDIGetActive()</p><p goog_ds_charindex="224" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()->GetActiveFrame()</p></td><td width="16%" goog_ds_charindex="260" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="261" style="font-size: 10pt; line-height: normal; ">SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()</p><p goog_ds_charindex="314" style="font-size: 10pt; line-height: normal; ">MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()</p></td><td width="16%" goog_ds_charindex="384" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">SDI:AfxGetMainWnd()->GetActiveView()&#160;&#160;<br goog_ds_charindex="423" style="line-height: normal; ">MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()</td></tr><tr goog_ds_charindex="479" style="line-height: normal; "><td width="16%" goog_ds_charindex="480" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><strong goog_ds_charindex="481" style="line-height: normal; ">在CMainFrame中</strong></td><td width="16%" goog_ds_charindex="497" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="498" style="font-size: 10pt; line-height: normal; ">AfxGetApp()</p><p goog_ds_charindex="512" style="font-size: 10pt; line-height: normal; ">theApp</p></td><td width="16%" goog_ds_charindex="522" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "></td><td width="16%" goog_ds_charindex="523" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="524" style="font-size: 10pt; line-height: normal; ">MDIGetActive()</p><p goog_ds_charindex="541" style="font-size: 10pt; line-height: normal; ">GetActiveFrame()</p></td><td width="16%" goog_ds_charindex="560" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">SDI:GetActiveView()->GetDocument()&#160;&#160;<br goog_ds_charindex="597" style="line-height: normal; ">MDI:MDIGetActive()->GetActiveView()->GetDocument()&#160;&#160;</td><td width="16%" goog_ds_charindex="651" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">SDI:GetActiveView()&#160;&#160;<br goog_ds_charindex="673" style="line-height: normal; ">MDI:MDIGetActive()->GetActiveView()</td></tr><tr goog_ds_charindex="712" style="line-height: normal; "><td width="16%" goog_ds_charindex="713" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><strong goog_ds_charindex="714" style="line-height: normal; ">在CChildFrame中</strong></td><td width="16%" goog_ds_charindex="731" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="732" style="font-size: 10pt; line-height: normal; ">AfxGetApp()</p><p goog_ds_charindex="746" style="font-size: 10pt; line-height: normal; ">theApp</p></td><td width="16%" goog_ds_charindex="756" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">GetParentFrame()</td><td width="16%" goog_ds_charindex="776" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="777" style="font-size: 10pt; line-height: normal; "></p></td><td width="16%" goog_ds_charindex="779" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">GetActiveView()->GetDocument()&#160;&#160;</td><td width="16%" goog_ds_charindex="813" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">GetActiveView()</td></tr><tr goog_ds_charindex="831" style="line-height: normal; "><td width="16%" goog_ds_charindex="832" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><strong goog_ds_charindex="833" style="line-height: normal; ">在CDocument中</strong></td><td width="16%" goog_ds_charindex="848" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="849" style="font-size: 10pt; line-height: normal; ">AfxGetApp()</p><p goog_ds_charindex="863" style="font-size: 10pt; line-height: normal; ">theApp</p></td><td width="16%" goog_ds_charindex="873" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">AfxGetMainWnd()&#160;&#160;</td><td width="16%" goog_ds_charindex="893" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="894" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()->MDIGetActive()</p><p goog_ds_charindex="928" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()->GetActiveFrame()</p></td><td width="16%" goog_ds_charindex="964" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "></td><td width="16%" goog_ds_charindex="965" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">POSITION&#160;&#160; pos&#160;&#160; =&#160;&#160; GetFirstViewPosition();GetNextView(pos)&#160;&#160;</td></tr><tr goog_ds_charindex="1030" style="line-height: normal; "><td width="16%" goog_ds_charindex="1031" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><strong goog_ds_charindex="1032" style="line-height: normal; ">在CView中</strong></td><td width="16%" goog_ds_charindex="1043" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="1044" style="font-size: 10pt; line-height: normal; ">AfxGetApp()</p><p goog_ds_charindex="1058" style="font-size: 10pt; line-height: normal; ">theApp</p></td><td width="16%" goog_ds_charindex="1068" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">AfxGetMainWnd()&#160;&#160;</td><td width="16%" goog_ds_charindex="1088" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">GetParentFrame()&#160;&#160;</td><td width="16%" goog_ds_charindex="1109" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">GetDocument()</td><td width="16%" goog_ds_charindex="1124" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "></td></tr><tr goog_ds_charindex="1126" style="line-height: normal; "><td width="16%" goog_ds_charindex="1127" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><strong goog_ds_charindex="1128" style="line-height: normal; ">在其他类中</strong></td><td width="16%" goog_ds_charindex="1137" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="1138" style="font-size: 10pt; line-height: normal; ">AfxGetApp()</p></td><td width="16%" goog_ds_charindex="1153" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">AfxGetMainWnd()&#160;&#160;</td><td width="16%" goog_ds_charindex="1173" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="1174" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()->MDIGetActive()</p><p goog_ds_charindex="1208" style="font-size: 10pt; line-height: normal; ">AfxGetMainWnd()->GetActiveFrame()</p></td><td width="16%" goog_ds_charindex="1245" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><p goog_ds_charindex="1246" style="font-size: 10pt; line-height: normal; ">SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()</p><p goog_ds_charindex="1299" style="font-size: 10pt; line-height: normal; ">MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()</p></td><td width="16%" goog_ds_charindex="1369" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">SDI:AfxGetMainWnd()->GetActiveView()&#160;&#160;<br goog_ds_charindex="1408" style="line-height: normal; ">MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()</td></tr></tbody></table></div><div goog_ds_charindex="1467" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "></div><div goog_ds_charindex="1468" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">理一理MFC的这几个类的关系，可以很容易明白上面的这些乱七八糟的逻辑。</div><div goog_ds_charindex="1505" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">App是应用域，所有的域中的东西都可以通过全局函数访问到它。</div><div goog_ds_charindex="1537" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">MainFrame是主框架，也基本可以用全局函数访问到。</div><div goog_ds_charindex="1567" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">MainFrame下是若干个ChildFrame，ChildFrame中若干个View和Document（可能不成对），ChildFrame管理着View，View和Document进行互操作。</div><div goog_ds_charindex="1666" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">因此整体框架就出来了，一般除了直接应用的关系都可以通过MainFrame-->Active ChildFrame-->Active View-->Document这条线进行访问，这应该叫什么来自？万能方法吧^_^。</div><div goog_ds_charindex="1666" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; "><br></div><div goog_ds_charindex="1666" style="font-family: Arial; word-wrap: break-word; word-break: break-all; visibility: visible !important; filter: none; font-size: 12px; line-height: normal; ">原文链接：<a href="http://hi.baidu.com/vcmfc/blog/item/35f8ef3877d87dcad4622503.html">http://hi.baidu.com/vcmfc/blog/item/35f8ef3877d87dcad4622503.html</a></div></div></span>
<img src ="http://www.cppblog.com/elva/aggbug/79154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-04-07 10:51 <a href="http://www.cppblog.com/elva/archive/2009/04/07/79154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CListView 获取滚动条位置</title><link>http://www.cppblog.com/elva/archive/2009/03/05/75584.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 05 Mar 2009 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/03/05/75584.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/75584.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/03/05/75584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/75584.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/75584.html</trackback:ping><description><![CDATA[<br>CListView中的滚动条不是一个控件，WS_VSCROLL风格创建出来的，应该不能获取其句柄，目前我是没办法。，要获取其滚动的位置，可以采用下面代码：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SCROLLINFO&nbsp;si;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.cbSize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(si);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.fMask&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SIF_ALL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;::GetScrollInfo(m_hWnd,SB_VERT,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">si);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(si.nPos&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;si.nPage&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;si.nMax)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox(_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">end</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(si.nPos&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;si.nMin)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox(_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">begin</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));</span></div>
<img src ="http://www.cppblog.com/elva/aggbug/75584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-03-05 11:04 <a href="http://www.cppblog.com/elva/archive/2009/03/05/75584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浮点数的比较</title><link>http://www.cppblog.com/elva/archive/2009/02/19/74263.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 19 Feb 2009 03:48:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2009/02/19/74263.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/74263.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2009/02/19/74263.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/74263.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/74263.html</trackback:ping><description><![CDATA[在数学运算当中经常会涉及到判断两个数是否相等的情况 <br>对于整数很好处理 A==B这样的一个语句就可以<font color=#6600ff>解决</font>全部的问题 <br>但是对于浮点数是不同的 <br><br>首先，浮点数在计算机当中的二进制表达方式就决定了大多数浮点数都是无法精确的表达的 <br>现在的计算机大部分都是<nobr style="COLOR: #6600ff; BORDER-BOTTOM: 0px dotted; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" target="_blank">数字</nobr>计算机，不是模拟机，数字机的离散化的数据表示方法自然无法精确表达大部分的数据量的。 <br><br>其次计算机浮点数的精度在单精度float类型下，只有7位，在进行浮点运算的时候，这个精度往往会导致运算的结果和实际期望的结果之间有误差 <br><br>因为前两个原因，我们很难用 A==B来判定两个浮点数是否相同 <br><br>很自然，我们可以想到 fabs(A-B) &lt; epsilon 这样的一种判别方法 <br>但是这种判别方法稳妥吗？ <br>它也不稳妥。 <br><br>首先， epsilon是一个绝对的数据，也就是误差分析当中说说的绝对误差 <br>使用一个固定的数值，对于float类型可以表达的整个数域来说是不可以的 <br>比如epsilon取值为0.0001，而a和b的数值大小也是0.0001附近的，那么显然不合适 <br>另外对于a和b大小是10000这样的数据的时候，它也不合适，因为10000和10001也可以认为是相等的呢 <br>适合它的情况只是a或者b在1或者0附近的时候 <br><br>既然绝对误差不可以，那么自然的我们就会想到了相对误差 <br>bool IsEqual(float a, float b, float relError ) {&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ( fabs ( (a-b)/a ) &lt; relError ) ? true&nbsp;&nbsp; : false; <br>} <br>这样写还不完善，因为是拿固定的第一个参数做比较的，那么在调用 <br>IsEqual(a, b, relError ) 和 IsEqual(b, a, relError ) 的时候，可能得到不同的结果 <br>同时如果第一个参数是0的话，就有可能是除0溢出 <br>这个可以改造 <br>把除数选取为a和b当中绝对数值较大的即可 <br>bool IsEqual(float a, float b, relError ) <br>{&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp; if (fabs(a)&lt;fabs(b)) return ( fabs((a-b)/a)&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;&nbsp;&nbsp; relError ) ? true&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp;&nbsp;&nbsp; false;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; return ( fabs((a-b)/b)&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;&nbsp;&nbsp; relError ) ? true&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp;&nbsp;&nbsp; false; <br>}; <br><br>使用相对误差就很完善吗？ <br>也不是， 在某些特殊情况下， 相对误差也不能代表全部 <br>比如在判断空间三点是否共线的时候，使用判断点到另外两个点形成的线段的距离的方法的时候 <br>只用相对误差是不够的，应为线段距离可能很段，也可能很长，点到线段的距离，以及线段的长度做综合比较的时候，需要相对误差和绝对误差结合的方式才可以 <br>相对完整的比较算法应该如下： <br>bool IsEqual(float a, float b, float absError, float relError ) <br>{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (a==b) return true; <br>if (fabs(a-b)&lt;absError ) return true; <br>if (fabs(a&gt;b) return (fabs((a-b)/a&gt;relError ) ? true : false; <br>return (fabs((a-b)/b&gt;relError ) ? true : false; <br>} <br>这样才相对完整&nbsp;&nbsp;</p>
<p>&nbsp;</p>
<p>参照MSDN定义：</p>
<pre class=code>/* Compile options needed: none. Value of c is printed with a decimal
point precision of 10 and 6 (printf rounded value by default) to
show the difference
*/
#include <stdio.h />
// Define your own tolerance</pre>
<pre class=code>const double EPSILON = 1.00e-07;</pre>
<pre class=code>const&nbsp;float&nbsp;&nbsp;&nbsp;FLT_EPSILON&nbsp; = 1.192092896e-07F;</pre>
<pre class=code>
<pre class=code>
<p>const double&nbsp;&nbsp;DBL_EPSILON  = <font size=2>2.2204460492503131e-016;</font></p>
<p><font size=2></font></p>
<font size=2>
<p> </p>
#define FLOAT_EQ(x,v) (((v - EPSILON) &lt; x) &amp;&amp; (x &lt;( v + EPSILON)))
int main()
{
float a, b, c;
a = 1.345f;
b = 1.123f;
c = a + b;
// if (FLOAT_EQ(c, 2.468))   // Remove comment for correct result
if (c == 2.468)              // Comment this line for correct result
printf("They are equal.\n");
else
printf("They are not equal! The value of c is %13.10f,or %f",c,c);
}</font></pre>
</pre>
<img src ="http://www.cppblog.com/elva/aggbug/74263.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2009-02-19 11:48 <a href="http://www.cppblog.com/elva/archive/2009/02/19/74263.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>