﻿<?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++博客-酱坛子</title><link>http://www.cppblog.com/sunraiing9/</link><description>专注C++技术  在这里写下自己的学习心得 感悟 
和大家讨论 共同进步（欢迎批评！！！）</description><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 16:40:16 GMT</lastBuildDate><pubDate>Thu, 23 Apr 2026 16:40:16 GMT</pubDate><ttl>60</ttl><item><title>最近做地图遇到Z-buffer精度问题</title><link>http://www.cppblog.com/sunraiing9/archive/2009/03/27/78018.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Fri, 27 Mar 2009 03:31:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2009/03/27/78018.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/78018.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2009/03/27/78018.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/78018.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/78018.html</trackback:ping><description><![CDATA[<span class=Apple-style-span style="WORD-SPACING: 0px; FONT: 14px Tahoma; 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: 0">
<div class=postTitle style="PADDING-LEFT: 3px; FONT-WEIGHT: bolder; FONT-SIZE: 13px; PADDING-BOTTOM: 3px; PADDING-TOP: 3px; BORDER-BOTTOM: rgb(159,176,134) 1px dashed"><a id=viewpost1_TitleUrl style="COLOR: rgb(63,61,61); TEXT-DECORATION: none" href="http://www.cnitblog.com/lethep/articles/25570.html">关于深度冲突(Z-Finghting or Depth Fighting)的解决</a></div>
<div class=postText style="PADDING-RIGHT: 10px; MARGIN-TOP: 10px; PADDING-LEFT: 3px; FONT-SIZE: 13px; MARGIN-BOTTOM: 10px; PADDING-BOTTOM: 5px; PADDING-TOP: 1px; BACKGROUND-COLOR: rgb(224,223,227)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OpenGL,或者D3D 的深度缓存都存在精度问题,在最新的Nvidia GF8 系列显卡中已经开始应用float point depth buffer. 而在此之间,深度缓存其实只有位平面的概念. 这随API的不同,都需要指定后缓存深度缓存精度, Depth ,我一般使用24位,也就是D3D中常见的 D24S8. 但除非你是用浮点,否则都会有精度损失的问题,这种情况总是发生在2个几乎共面的片面,他们投影在后裁减平面时都会被赋予一个深度(当然,如果深度缓存可写的话),而上面已经说过,目前来说,深度只是位平面, 你可以把他假设为这样的形势<br><br>depth&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; w<br>0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [near_clip,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;near_clip&nbsp;+&nbsp;0.1]<br>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [near_clip&nbsp;+&nbsp;0.1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;near_clip&nbsp;+0.2]<br>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [near_clip&nbsp;+&nbsp;0.3&nbsp;,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;near_clip&nbsp;+0.4]<br>........<br>max&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [far_clip - 0.1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;far_clip]<br>上面假设硬件的最小深度单元 r = 0.1<br><br>那么将会出现这样的问题.<br>当2个片元距离近裁减平面 w&nbsp; 落在同一个区间的时候,他们的深度是相等的. 最终你所看到的结果,就是下面的这种样子:<br><img src="http://www.cnitblog.com/images/cnitblog_com/lethep/4967/o_Depth_Fighting01.jpg" border=0><br>注意到蓝色线框里面.<br><br><br>要解决这个问题, 你只要google 或者去 beyond3d,等论坛,搜索 depth fighting ,得到的答案往往就是设置深度偏移. OpenGL : Polygon offset. D3D: Depth Bais.<br>拿OpenGL 来说,就是对有存在深度冲突的2个 Mesh Object&nbsp; A,B如下方式渲染.<br>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><img src="http://www.cnitblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: rgb(0,0,0)">A.Render();<br><img src="http://www.cnitblog.com/Images/OutliningIndicators/None.gif" align=top>glEnable(GL_POLYGON_OFFSET_FILL);<br><img src="http://www.cnitblog.com/Images/OutliningIndicators/None.gif" align=top>glPolygonOffset(</span><span style="COLOR: rgb(0,0,0)">0.0f</span><span style="COLOR: rgb(0,0,0)">,</span><span style="COLOR: rgb(0,0,0)">-</span><span style="COLOR: rgb(0,0,0)">1.0f</span><span style="COLOR: rgb(0,0,0)">);<br><img src="http://www.cnitblog.com/Images/OutliningIndicators/None.gif" align=top>B.Render();<br><img src="http://www.cnitblog.com/Images/OutliningIndicators/None.gif" align=top>glDisable(GL_POLYGON_OFFSET_FILL);</span></div>
<br>这是一个不错的方法,但是实际操作起来很麻烦,而且没有效率. 注意到,你必须一先一后的渲染这2个对象, 拿上图来说,我需要在MAX 中把手套和手臂脱离,形成一个独立的节点,然后我起码需要新建立2个顶点缓存,并在渲染的过程中设置2次.这对于带宽是个不小的代价.所以我不是很赞成这样去处理,当然,有的时候无法避免了,也会如此..<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果避免发生Z-Fighting 才是关键. 注意到上面的depth - w 的位平面对应关系. 由于硬件都只能支持一定的深度格式,也就是说,Depth bits 是一定的,假为 D.而顶点的投影深度则毫无限制,他可以是 near_clip ---&gt; far_clip 的任意一个浮点数.因此<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dw/D<strong><span class=Apple-converted-space>&nbsp;</span>= (far_clip - near_clip)/near_clip;<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;<span>从上面可以看出, 要想dw 更精确,那么 near_clip 必然要更大(适用范围是far_clip &gt;&gt; near_clip).<br>上面那张存在depth-fighting 的截图当时的情况是 near_clip :0.0001 far_clip : 64000.0<br>下面的是在near_clip 0.1 far_clip 不变.<br><img src="http://www.cnitblog.com/images/cnitblog_com/lethep/4967/o_Depth_Fighting02.jpg" border=0><br><br>继续提高定点投影深度,也不会出现难看的深度冲突了.<br><img src="http://www.cnitblog.com/images/cnitblog_com/lethep/4967/o_Depth_Fighting03.jpg" border=0></span></div>
</span>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/78018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2009-03-27 11:31 <a href="http://www.cppblog.com/sunraiing9/archive/2009/03/27/78018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实时3D绘图的阴影效果</title><link>http://www.cppblog.com/sunraiing9/archive/2009/03/27/78015.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Fri, 27 Mar 2009 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2009/03/27/78015.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/78015.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2009/03/27/78015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/78015.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/78015.html</trackback:ping><description><![CDATA[<span class=Apple-style-span style="WORD-SPACING: 0px; FONT: 16px 'Times New Roman'; 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: 0">
<div style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px">对作者心血表示感谢，先附上原文：<a style="COLOR: rgb(0,44,153); TEXT-DECORATION: none" href="http://www.86vr.com/teach/cursor/200410/3841.html">http://www.86vr.com/teach/cursor/200410/3841.html</a>
<div style="BORDER-RIGHT: rgb(187,187,187) 1px solid; PADDING-RIGHT: 32px; BORDER-TOP: rgb(187,187,187) 1px solid; PADDING-LEFT: 32px; PADDING-BOTTOM: 32px; BORDER-LEFT: rgb(187,187,187) 1px solid; PADDING-TOP: 32px; BORDER-BOTTOM: rgb(187,187,187) 1px solid; BACKGROUND-COLOR: rgb(255,255,255); webkit-background-clip: initial; webkit-background-origin: initial"><span class=Apple-style-span style="FONT-SIZE: 15px; COLOR: rgb(51,51,51); LINE-HEIGHT: 25px; FONT-FAMILY: 宋体; webkit-border-horizontal-spacing: 5px; webkit-border-vertical-spacing: 5px"><span class=Apple-style-span style="FONT-WEIGHT: bold; FONT-SIZE: 20px; COLOR: rgb(204,51,0); LINE-HEIGHT: normal; FONT-FAMILY: '黑体 Arial'"><span class=Apple-tab-span style="WHITE-SPACE: pre"></span>实时3D绘图的阴影效果</span><br></span></div>
<div style="BORDER-RIGHT: rgb(187,187,187) 1px solid; PADDING-RIGHT: 32px; BORDER-TOP: rgb(187,187,187) 1px solid; PADDING-LEFT: 32px; PADDING-BOTTOM: 32px; BORDER-LEFT: rgb(187,187,187) 1px solid; PADDING-TOP: 32px; BORDER-BOTTOM: rgb(187,187,187) 1px solid; BACKGROUND-COLOR: rgb(255,255,255); webkit-background-clip: initial; webkit-background-origin: initial"><span class=Apple-style-span style="FONT-SIZE: 15px; COLOR: rgb(51,51,51); LINE-HEIGHT: 25px; FONT-FAMILY: 宋体; webkit-border-horizontal-spacing: 5px; webkit-border-vertical-spacing: 5px">目 录
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　1 平面阴影<br>　　2 体积阴影
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<br><a style="COLOR: rgb(0,44,153); TEXT-DECORATION: none" href="http://www.chinagamedev.net/cgd/develop/3D/200306/image/RealShadow/planar_shadow.zip" target=_blank>附带的源程序（91KB）</a>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　在目前的实时3D绘图中，要做出真实的阴影效果，是很不容易的。因为阴影是因物体遮住光源所产生的，因此，要做出正确的阴影效果，就需要对整个场景做处理，这样才能判断出哪些物体被哪些物体遮住了。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　不过，目前的3D硬件，并不容易进行这类的测试，因为资料量和工作量都太大了。不过，这并不表示使用现在的3D硬件就无法做出阴影。现在已经有很多方法是适合用在目前的3D硬件上面，可以产生效果不错的阴影。本文会就一些常用的方法，做简单的介绍。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<br>1、平面阴影
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　目前常用的方法，几乎都是把阴影看成是&#8220;物体投射到其它表面&#8221;来处理。在光源是平行光的时候（例如，太阳光），可以看成是物体把阴影&#8220;投射&#8221;到另一个表面上，如下图所示：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/200410910540RealShadow-1.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　如果场景中只有一个重要的光源（即最强的光源），那可以假设只有这个光源会产生明显的阴影。以平行光源来说，要把阴影&#8220;投射&#8221;到一个平面上，就是一件相当容易的事。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　设空间有一点V，平行光源的方向是L，要投射阴影的平面是P，那么，存在一常数k使
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105431a1.gif" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　成立，如下图（V、L、和 P均为四维向量，表示一个三维的齐次坐标：homogeneous coordinate）：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105453RealShadow-2.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　解上式得
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105523b.gif" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　空间中的点V投影到平面P的位置是V+kP。对一个3D模型（model）的每个顶点都代入这个式子，就可以得到投影的结果了。不过，因为目前的3D硬件都是以4&#215;4的矩阵来做变换，所以如果能把投影的动作写成一个矩阵，就会方便很多。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　设V = &lt;Vx, Vy, Vz, 1&gt;，L = &lt;Lx, Ly, Lz, 0&gt;，P = &lt;a, b, c, d&gt;；展开前面的式子，会发现k有一个分母：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105613c.gif" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　因此这个式子会有点复杂。不过，因为在OpenGL中的向量都是齐次坐标（homogeneous coordinate），所以可以先把分母提出来，放到w中。对Vx展开得到：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105629d.gif" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
整理一下得到
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105653e.gif" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　这样就变成向量内积的形式，可以放到矩阵中。对Vy和Vz做同样的动作，再加上放到w的分母部分，就可以得到下面的矩阵：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/200410910576f.gif" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　因此，理论上，要画阴影时，把MODELVIEW矩阵设成上面的矩阵，画出物体，就会是阴影的样子。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　上面讨论的是以平行光源为主。如果光源是点光源，也可以用类似的方法来做。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　这个方法可以对任何平面做出阴影的效果。如果有多个平面，可以分别对每个平面都做一次。不过，这个方法显然是没办法把阴影投影到曲面上。所以，这个方法通常称为平面阴影（planar shadow）。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　理论的部分已经讨论完了。不过，实作的时候，还有一些细节部分是需要特别注意的。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　首先，如果真的直接用上面的方法来做，那做出来的结果可能会像这样：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/20041091057521.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　这是因为画了图中的地板之后，再画黑色的阴影时，会和地板产生所谓的Z fighting现象，也就是阴影的一部分的Z值较地板的Z值小，所以会画出来，但是有些部分的Z值则可能比地板的Z值大，所以就没画出来了。这种现象会使得阴影变得破碎不完整。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　现在的3D硬件通常提供一个叫多边形偏移（polygon offset）的功能，用来解决Z fighting的问题。多边形偏移的原理，是在画一个物体时，要求把它的Z值进行一个小的调整。例如，在上面的例子中，我们可以把阴影的Z值减一个小的数字，这样就可以避免Z fighting的现象。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　处理掉Z fighting后，再来是第二个问题：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/20041091058102.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　上图中，阴影跑到地板的外面去了。这里需要一个方法，把阴影切到地板的范围内。这个例子中，地板的边界是直线，所以可以用user defined clip planes来做。不过，如果地板是奇怪的形状，就需要别的方法。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　而且，光是把阴影切到地板的范围内是不够的。通常阴影是用blending的方式画上去的。如果一个物体的形状比较复杂，那有些地方可能会blend两次或更多次。这样会让阴影看起来不是同一个颜色，即有些地方颜色较深而有些地方较浅。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　现在的3D硬件多半支持模板缓冲区（stencil buffer）。模板缓冲区是一个用来&#8220;做记号&#8221;的缓冲区。通常模板缓冲区可以存放1 bits到8 bits不等的数字，不同的硬件支持的大小会不一样。目前的3D硬件通常把模板缓冲区和Z buffer放在一起。例如，它可能支持15 bits的Z buffer加上1 bit的模板缓冲区；或是支持24 bits的Z buffer加上8 bit的模板缓冲区。因此，通常模板缓冲区的测试是和Z测试一起做的，也就是在使用Z buffer时，模板缓冲区可说是&#8220;免费&#8221;的。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　在我们的例子中，可以先把模板缓冲区（stencil buffer）全清为0。在画地板之前，把模板缓冲区设定为&#8220;当Z测试通过时，把模板的值设为1&#8221;。这样一来，画完地板之后，地板所占有的那些像素的模板值就都会是1，其它的地方还是0。现在，把模板缓冲区设定成&#8220;当Z测试通过时，若模板的值为1才画，且将模板的值设为0&#8221;。然后开始画阴影。这样画出来的阴影，一定会在地板的范围内，而且每个像素只会被画一次，不会出现blend两次的情形。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　如果有多个平面要投影，可以为每个平面指定不同的模板（stencil）值。不过，如果模板缓冲区（stencil buffer）只有1 bit，那就没办法了。这时，可能就需要在画下一个平面之前，先把模板缓冲区清掉，这样会花很多时间。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　下图是一个完整的例子：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/20041091058353.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　参考程序你可以去试验。这个程序需要至少2 bits的模板缓冲区（stencil buffer）支持。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　平面阴影（Planar shadow）就差不多是这个样子了。平面阴影的好处是简单、容易做，而且在投影面不多的时候，速度很快。但是，当投影面变多时，或是物体很复杂时，速度很快就会变得很慢，因为对每个平面都需要把投影的物体再画一次。而且，它只能投影在平面上，对于不规则的表面则完全没办法。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　还有一些别的方法可以产生阴影的效果。后面还会再讨论一些产生阴影的方式，都可以投影在任何不规则的表面上。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
2、体积阴影
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　前面所介绍的方法，即平面阴影（Planar shadow），只适用于平面上。但是，除了少数的情形之外，绝大多数的情形下，根本无法预测阴影会被投射在什么样的表面上。所以，我们需要自由度更高的方法。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　在这里介绍一个较为灵活的方法，它可以将阴影投射在不规则的表面上。这个方法称为体积阴影（Volumetric Shadow）。这个方法的动点在于，它并不是利用&#8220;把物体投影到表面&#8221;的方式来产生阴影，而是去找出场景中，有哪些像素是在阴影中。也就是说，想象一个物体挡住光时，在物体的后面会形成一个大的&#8220;阴影锥&#8221;。很明显的，若一个像素在&#8220;阴影锥&#8221;之中，那它就是在阴影之中。如下图所示：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/2004109105974.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　上图中的红色球体，在受光照后，在后方产生一个&#8220;阴影锥&#8221;，即Shadow Volume，而这个&#8220;阴影锥&#8221;和灰色平面的交集，就是阴影会出现的地方。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　所以，基本上体积阴影（Volumetric Shadow）的原理是很简单的。不过，要真正实作又是另一回事。为了简单起见，这里先以一个简单的三角形开始。目前的3D绘图几乎都是以三角形为基础，所以从三角形开始，应该是很适当的。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　现在，假设有一个已经绘制完成的3D场景。因为使用Z buffer的关系，对每一个像素而言，都有一个相对的Z值，即表示该像素和观察者的距离的值。如果现在有一个三角面，把阴影投射到这个3D场景中，并画出这个三角面的&#8220;阴影锥&#8221;。因为物体是一个三角形，所以它的&#8220;阴影锥&#8221;也是一个三角锥。这时，要如何知道3D场景中，有哪些像素是和这个三角锥有交集？
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　其实方法很简单。想象许多射线，由观察者射向每个像素。如果射线和&#8220;阴影锥&#8221;完全没有交集，它所对应的像素当然就不会和&#8220;阴影锥&#8221;有交集。不过，即使是射线和&#8220;阴影锥&#8221;有交集，并不一定表示该像素就一定和&#8220;阴影锥&#8221;有交集，因为射线可能会射入&#8220;阴影锥&#8221;后又射出。所以，只有在射线射入&#8220;阴影锥&#8221;之后，在离开&#8220;阴影锥&#8221;之前就遇到其对应的像素时，才表示这个像素和&#8220;阴影锥&#8221;有交集。下图显示出各种不同的情形：
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/20041091059425.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　上图中的（1）和（2）都是面对观察者的面，所以它们所涵盖的像素，就是&#8220;射线会射入阴影锥&#8221;的像素。而（3）则是背对观察者的面，所以它所涵盖的像素是&#8220;射线会离开阴影锥&#8221;的像素。所以，会和阴影锥有交集的像素，就是（1）+（2）-（3）的那些像素，也就是阴影所在的位置。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　不过，要怎么在一般的3D绘图硬件中，得到（1）+（2）-（3）的结果呢？和平面阴影（Planar shadow）一样，这需要模板缓冲区（stencil buffer）。在OpenGL和Direct3D中的模板缓冲区都可以让它进行&#8220;加一&#8221;和&#8220;减一&#8221;的动作。所以，只要把模板缓冲区设定成：在绘制（1）和（2）的面时，让模板缓冲区加一；而在绘制（3）的面时，让 模板缓冲区减一。这样一来，在画完（1）～（3）时，那些模板（stencil）值不为0的像素就是阴影了。最后，把所有模板不为0的像素利用alpha blending的方式，使其亮度降低，就可以达到绘制阴影的效果。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　上面的例子是用一个三角面。对于比较复杂的物体，其原理还是一样的。当物体是由许多三角面组成时，可以把所有面对光源的三角面都进行上面的动作，就可以产生阴影。不过，这样有个缺点：因为很多三角面的边是接在一起的，所以这样做会十分浪费时间。要提高效率其实也很容易。在绘制&#8220;阴影锥&#8221;的时候，若有一个边是被两个三角面所共享，那就表示这是一个&#8220;内部&#8221;的边，在绘制&#8220;阴影锥&#8221;的时候，就可以不用去画这个边。这样就可以省下不少的时间。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　这个方法适用于非常复杂的物体。不过，它还是可能会遇上一些问题。一个情形是，如果观察者在&#8220;阴影锥&#8221;的内部，会发生一些麻烦的情形。不过，对大部分的情形来说，只要将模板缓冲区（stencil buffer）设定成&#8220;减到0就停止&#8221;，即0 - 1 = 0，就可以解决。当然这无法解决所有的问题，不过通常已经够好了。另外，如果物体不是 convex（即&#8220;凸&#8221;的），那可能会出现&#8220;射线重复进入阴影锥&#8221;的情形。这种情形并不会有问题，不过模板缓冲区就需要比较多bit才不会出错。一般来说，4 bits就已经可以处理绝大多数的物体的。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　下面的画面是体积阴影（Volumetric Shadow）的结果，是由DirectX 8 SDK中的一个示范程序所产生的。这个程序的结构并不复杂，所以有兴趣的话，可以自行参考它的原始码。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
<center><img src="http://www.86vr.com/files/2004-10/200410911086.jpg" border=0></center>
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　这个方法比平面阴影（Planar shadow）更能适用于不同的场景。不过，它当然也有缺点。最主要的缺点是在于它的复杂度。要做出有效率的&#8220;阴影锥&#8221;，需要对物体做相当麻烦的处理，基本上就是要找出物体在某个方向的&#8220;外缘&#8221;（即silhouette）。虽然这并不太难做，但是还是需要花费相当的CPU时间去处理。另外，为所有的物体绘制出其&#8220;阴影锥&#8221;，需要相当大量的填充率（fill rate）和内存频宽。若是延后渲染（deferred renderer），例如图素渲染（tile renderer）则影响不会这么大，特别是图素渲染可以支持一些特别的功能，来加速体积阴影（Volumetric Shadow）的动作。
<p style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 6px; MARGIN: 0px; PADDING-TOP: 6px"></p>
　　基本上，体积阴影（Volumetric Shadow）的效果，一般来说都不错。最主要的缺点则是在效率方面，特别是当物体的复杂度和数量增加时，CPU需要的工作量会大增，是较为不理想的。后面会再介绍一些速度更快的方法。</span></div>
</div>
</span>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/78015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2009-03-27 11:11 <a href="http://www.cppblog.com/sunraiing9/archive/2009/03/27/78015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存文件映射应用举例『转』</title><link>http://www.cppblog.com/sunraiing9/archive/2008/04/03/46171.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Thu, 03 Apr 2008 07:04:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2008/04/03/46171.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/46171.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2008/04/03/46171.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/46171.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/46171.html</trackback:ping><description><![CDATA[<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td>
            <div class=cnt id=blog_text><span>
            <p>下面这些函数被应用于文件内存映射中：<br><br><font color=#0000ff>1) CreateFileMapping <br>2) FlushViewOfFile <br>3) MapViewOfFile <br>4) MapViewOfFileEx <br>5) MapViewOfFileVlm <br>6) OpenFileMapping <br>7) UnmapViewOfFile&nbsp;&nbsp; <br>8) UnmapViewOfFileVlm</font> </p>
            <p><font color=#ff0000>函数详细说明：『见本页末』</font></p>
            <p><span>
            <p>例子：<br><font color=#0000ff>/*****************************************************/<br>/*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>/*这个例子创建了文件映射视图，并通过这个映射&nbsp;&nbsp;&nbsp;&nbsp; */<br>/*视图来操作文件内容。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>/*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>/****************************************************/<br>#include &lt;stdio.h&gt;<br>#include &lt;stdlib.h&gt;<br>#include &lt;windows.h&gt;</font></p>
            <p><font color=#0000ff>int main()<br>{<br>HFILE hFile;<br>OFSTRUCT opBuf;<br>HANDLE hMapfile;<br>HANDLE hMapview;<br>BYTE *recv;<br>hFile=OpenFile(".\\map.test",&amp;opBuf,OF_READWRITE);<br>if (hFile==HFILE_ERROR)<br>{<br>&nbsp;&nbsp; printf("open file failed!\n");<br>&nbsp;&nbsp; return 1;<br>}<br>hMapfile=CreateFileMapping((HANDLE)hFile,NULL,PAGE_READWRITE,0,0,"MapTest");<br>if(hMapfile==NULL)<br>{<br>&nbsp;&nbsp; printf("mapping file failed!\n");<br>&nbsp;&nbsp; return 1;<br>}<br>CloseHandle((HANDLE)hFile);<br>hFile=0;<br>hMapview=MapViewOfFile(hMapfile,FILE_MAP_WRITE,0,0,0);<br>if(hMapview==NULL)<br>{<br>&nbsp;&nbsp; printf("mapping view failed!\n");<br>&nbsp;&nbsp; return 1;<br>}<br>recv=(BYTE *)hMapview;<br>printf("Mapping view's content is :%.10s \n",recv);<br>recv[0]='s';<br>printf("Mapping view's content is :%.10s \n",recv);<br>UnmapViewOfFile(hMapview);<br>return 0;<br>}</font></p>
            </span>
            <p>&#160;</p>
            <p>一、<font color=#ff0000>CreateFileMapping</font> 为指定文件创建一个有名或无名的文件映象；<br>HANDLE CreateFileMapping(<br>HANDLE hFile,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 映射文件的句柄<br>LPSECURITY_ATTRIBUTES lpFileMappingAttributes,<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; // 安全描述符指针<br>DWORD flProtect,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 对映射对象的保护<br>DWORD dwMaximumSizeHigh,&nbsp;&nbsp; // 对象最大长度的高32位<br>DWORD dwMaximumSizeLow,&nbsp;&nbsp;&nbsp; // 对象最大长度的低32位<br>LPCTSTR lpName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 文件内存映射对象的名字<br>);</p>
            <p>注意：<br>hFile：映射文件的句柄，文件的打开模式必须与flProtect参数指定的相一致；如果这个参数值为0xFFFFFFFF，那 么必须在dwMaximumSizeHigh和dwMaximumSizeLow参数中指定映射对象的大小。并且将在操作系统虚拟内存页面替换文件中创建 文件映射对象，而不是使用磁盘文件，同时必须给出这个映射对象的大小。文件映射对象通过副本，遗传或名字来共享。<br>lpFileMappingAttributes：安全描述符指针，决定返回句柄是否能被子进程继承，如果是NULL，那么子进程不能继承。WinNt中，如果是NULL，那么文件映射对象得到一个默认的安全描述符。<br>flProtect：为得到的文件试图指定保护模式，可以被设置为下列值：<br>PAGE_READONLY ：只读属性，并且hFile对应的文件必须以GENERIC_READ形式打开。<br>PAGE_READWRITE：可读可写属性，并且hFile对应的文件必须以GENERIC_READ 和 GENERIC_WRITE形式打开。<br>PAGE_WRITECOPY：对可写区域复制后操作，并且hFile对应的文件必须以GENERIC_READ 和 GENERIC_WRITE形式打开。<br>dwMaximumSizeHigh，dwMaximumSizeLow：如果这两个参数为0，则文件映射对象的最大长度等于hFile指定的文件长度。<br>lpName： 文件映射对象的名字，如果这个名字已存在，则按照flProtect指定的来处理映射对象。如果此参数为空，则创建一个无名字的文件映射对象。如果此参数 的名字与系统事件的名字相同，则函数执行失败，GetLastError返回 ERROR_INVALID_HANDLE；</p>
            <p>返回值：函数调用成功返回文件映射对象的句柄，如果文件映射对象已经存在则返回原有映射对象的句柄，GetLastError返回ERROR_ALREADY_EXISTS。函数执行失败返回Null。</p>
            <p>二、<font color=#ff0000>FlushViewOfFile</font> 把文件映射视图中的修改的内容或全部写回到磁盘文件中<br>BOOL FlushViewOfFile(<br>LPCVOID lpBaseAddress,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 修改内容的起始地址<br>DWORD dwNumberOfBytesToFlush // 修改的字节数目<br>);<br>函数执行成功返回非零。</p>
            <p>三、<font color=#ff0000>MapViewOfFile</font> 在调用进程的地址空间映射一个文件视图<br>LPVOID MapViewOfFile(<br>HANDLE hFileMappingObject, // 已创建的文件映射对象句柄<br>DWORD dwDesiredAccess,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 访问模式<br>DWORD dwFileOffsetHigh,&nbsp;&nbsp;&nbsp;&nbsp; // 文件偏移的高32位<br>DWORD dwFileOffsetLow,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 文件偏移的低32位<br>DWORD dwNumberOfBytesToMap // 映射视图的大小<br>);<br>注意：<br>hFileMappingObject： 由CreateFileMapping 或 OpenFileMapping 返回的文件映射对象句柄。<br>dwDesiredAccess：映射视图的访问模式，与创建文件映射对象的保护模式flProtect有关，可以被设置为下列值：<br>FILE_MAP_WRITE：一个可读写属性的文件视图被创建，保护模式为PAGE_READWRITE <br>FILE_MAP_READ ：一个只读属性的文件视图被创建，保护模式为PAGE_READWRITE 或 PAGE_READONLY <br>FILE_MAP_ALL_ACCESS：与FILE_MAP_WRITE模式相同<br>FILE_MAP_COPY：保护模式为PAGE_WRITECOPY时，得到一个视图文件，当你对视图文件写操作时，页面自动交换，并且你所做的修改不会损坏原始数据资料。<br>dwNumberOfBytesToMap：映射文件部分的大小，如果为0，则映射整个文件。 <br>返回值：<br>如果成功返回返回映射视图的起始地址，如果失败返回NULL。</p>
            <p>四、<font color=#ff0000>MapViewOfFileEx</font> 在调用进程的地址空间映射一个文件视图，并且允许调用进程为映射视图指定特殊的内存地址 <br>LPVOID MapViewOfFileEx(<br>HANDLE hFileMappingObject, // 文件映射对象的句柄<br>DWORD dwDesiredAccess,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 访问模式<br>DWORD dwFileOffsetHigh,&nbsp;&nbsp;&nbsp;&nbsp; // 文件偏移的高32位<br>DWORD dwFileOffsetLow,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 文件偏移的低32位<br>DWORD dwNumberOfBytesToMap, // 映射视图的大小<br>LPVOID lpBaseAddress&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 指定映射视图的其实内存地址<br>);<br>注意：<br>与MapViewOfFile用法相同，但是如果指定的内存地址空间大小不够，则函数执行失败。<br>五、<font color=#ff0000>OpenFileMapping</font> 打开一个已命名的文件映射对象<br>HANDLE OpenFileMapping(<br>DWORD dwDesiredAccess, // 访问模式<br>BOOL bInheritHandle,&nbsp;&nbsp;&nbsp; // 继承标志<br>LPCTSTR lpName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 文件映射对象名指针<br>);<br>注意：<br>dwDesiredAccess：访问模式与MapViewOfFile中的访问模式相同。<br>bInheritHandle：继承标志，是否可以被一个新的进程继承使用，如果为TRUE，就可以被一个新进程继承句柄。<br>返回值：<br>成功返回一个已命名的文件映射对象，失败返回NULL。</p>
            <p>六、<font color=#ff0000>UnmapViewOfFile</font> 删除文件的映射视图<br>BOOL UnmapViewOfFile(<br>LPCVOID lpBaseAddress&nbsp;&nbsp; // 映射视图起始地址<br>);<br>注意：<br>lpBaseAddress：映射视图起始地址，由 MapViewOfFile 函数 MapViewOfFileEx产生。 <br>返回值：<br>如果调用成功返回非零，并且所有指定地址内的脏页面会被写入硬盘。调用失败返回零。</p>
            </span></div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/46171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2008-04-03 15:04 <a href="http://www.cppblog.com/sunraiing9/archive/2008/04/03/46171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>#pragma once与#ifndef的区别</title><link>http://www.cppblog.com/sunraiing9/archive/2008/01/22/41652.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 22 Jan 2008 10:14:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2008/01/22/41652.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/41652.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2008/01/22/41652.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/41652.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/41652.html</trackback:ping><description><![CDATA[<p>为了避免同一个文件被include多次<br><br>1&nbsp;&nbsp; #ifndef方式<br>2&nbsp;&nbsp; #pragma once方式<br><br>在能够支持这两种方式的编译器上，二者并没有太大的区别，但是两者仍然还是有一些细微的区别。<br>&nbsp;&nbsp;&nbsp; 方式一： </p>
<p>&nbsp;&nbsp;&nbsp; #ifndef __SOMEFILE_H__<br>&nbsp;&nbsp;&nbsp; #define __SOMEFILE_H__<br>&nbsp;&nbsp;&nbsp; ... ... // 一些声明语句<br>&nbsp;&nbsp;&nbsp; #endif </p>
<p>&nbsp;&nbsp;&nbsp; 方式二： </p>
<p>&nbsp;&nbsp;&nbsp; #pragma once<br>&nbsp;&nbsp;&nbsp; ... ... // 一些声明语句 </p>
<p><br>&nbsp;&nbsp;&nbsp; #ifndef的方式依赖于宏名字不能冲突，这不光可以保证同一个文件不会被包含多次，也能保证内容完全相同的两个文件不会被不小心同时包含。当然，缺点就是如果不同头文件的宏名不小心&#8220;撞车&#8221;，可能就会导致头文件明明存在，编译器却硬说找不到声明的状况<br><br>&nbsp;&nbsp;&nbsp; #pragma once则由编译器提供保证：同一个文件不会被包含多次。注意这里所说的&#8220;同一个文件&#8221;是指物理上的一个文件，而不是指内容相同的两个文件。带来的好处是，你不必再费劲想个宏名了，当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝，本方法不能保证他们不被重复包含。当然，相比宏名碰撞引发的&#8220;找不到声明&#8221;的问题，重复包含更容易被发现并修正。<br><br>&nbsp;&nbsp; 方式一由语言支持所以移植性好，方式二 可以避免名字冲突。 <br>一般可以这样处理：<br>#infndef XX<br>#define XX<br>&nbsp;&nbsp;&nbsp;&nbsp;#if _MSC_VER &gt; 1000&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#pragma once&nbsp;<br>&nbsp;&nbsp;&nbsp; #endif<br>&nbsp;&nbsp;&nbsp;.<br>&nbsp;&nbsp;&nbsp;.<br>#endif<br>注意：&nbsp;&nbsp; _MSC_VER 是出于版本兼容性考虑，定义<br>&nbsp;&nbsp; Defines the compiler version. Defined as 1200 for Microsoft Visual C++ 6.0. Always defined.<br></p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/41652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2008-01-22 18:14 <a href="http://www.cppblog.com/sunraiing9/archive/2008/01/22/41652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在入口函数内加如该段代码 能对内存泄露进行输出</title><link>http://www.cppblog.com/sunraiing9/archive/2007/12/21/39227.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Fri, 21 Dec 2007 08:52:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/12/21/39227.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/39227.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/12/21/39227.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/39227.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/39227.html</trackback:ping><description><![CDATA[ 在入口函数内加如该段代码 能对内存泄露进行输出


	int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); 
	tmpFlag |= _CRTDBG_LEAK_CHECK_DF; 
	_CrtSetDbgFlag( tmpFlag );
<img src ="http://www.cppblog.com/sunraiing9/aggbug/39227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-12-21 16:52 <a href="http://www.cppblog.com/sunraiing9/archive/2007/12/21/39227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>哈希表（摘）</title><link>http://www.cppblog.com/sunraiing9/archive/2007/12/13/38448.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Thu, 13 Dec 2007 09:53:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/12/13/38448.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/38448.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/12/13/38448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/38448.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/38448.html</trackback:ping><description><![CDATA[<strong><font size=4>哈希表与哈希函数</font></strong> <br>　　哈希查找因使用哈希 (Hash) 函数而得名，<strong>哈希函数</strong>又叫<strong>散列函数</strong>，它是一种能把关键字映射成记录存贮地址的函数。 <br><strong>1.哈希表</strong><br>①它是一种能把关键字映射成记录存贮地址的函数。<br>②假定数组 HT[0 ～ m-1] 为存贮记录的地址空间， m 为表长，哈希函数 H 以记录的关键字 K 为自变量，计算出对应的函数值 H(K) ，并以它作为关键字 K 所标识的记录在表 HT 中的 ( 相对 ) 地址或索引号，这样产生的记录表 HT 叫做对应于哈希函数 H 的<strong>哈希表</strong>。<br>③简言之，在哈希表中，关键字为 K 的记录，存贮在 HT[H(K)] 位置。<br>④哈希函数值 H(K) 称为 K 的哈希地址或散列地址。<br>&nbsp;&nbsp;&nbsp;&nbsp;
<object codeBase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0 height=281 width=436 classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000>
<embed src="tupian/t9.16.swf" quality="high"
    pluginspage="http://www.macromedia.com/go/getflashplayer"
    type="application/x-shockwave-flash" width="436" height="281"></embed>
    </object><br><strong>3、哈希表的冲突现象</strong><br><font color=#0000ff>（1）冲突</font><br>&nbsp;&nbsp;&nbsp; 　不同的关键字值，具有相同的哈希地址，因而被映射到同一表位置上。该现象称为冲突(Collision)或碰撞。<br>&nbsp; 　【例】上图中的k<sub>2</sub>&#8800;k<sub>5</sub>，但h(k<sub>2</sub>)=h(k<sub>5</sub>)，故k<sub>2</sub>和K<sub>5</sub>所在的结点的存储地址相同。<br><br><font color=#0000ff>（2）安全避免冲突的条件</font><br>&nbsp;&nbsp;&nbsp; 如何避免冲突发生，则取决于哈希函数的构造。 <br>&nbsp;&nbsp;&nbsp; 使散列地址均匀地分布在哈希表的整个地址区间内，这样可以避免或减少发生冲突。<br>&nbsp;&nbsp;&nbsp; 哈希函数的构造，与关键字的长度、哈希表的大小、关键字的实际取值状况等许多因素有关，而且有的因素事前不能确定。所以，避免冲突这并非是件容易做到的事。<br><br><font color=#0000ff>（3）冲突不可能完全避免</font><br>&nbsp;&nbsp;&nbsp; 　由于关键字的值域往往比哈希表的个数大的多，所以哈希函数是一种压缩映射，碰撞是难免的。<br>&nbsp;&nbsp;&nbsp;【例】存贮 100 个学生记录，尽管安排 120 个地址空间，但由于学生名 ( 假设不超过 10 个英文字母 ) 的理论个数超过 2610 ，要找到一个哈希函数把 100 个任意的学生名映射成 [0 ， 119] 内的不同整数，实际上是不可能的。<br><strong>&nbsp;&nbsp;&nbsp;<font color=#ff0000>注意：</font>问题在于一旦发生了冲突应如何处理。<br></strong><br><br><strong><font size=4>构造哈希表</font></strong> <br>　　构造哈希函数的方法很多，这里只介绍一些常用的，计算简便的方法。<br><strong>1.平方取中法</strong><br>　　算出关键字值的平方，再取其中若干位作为哈希函数值 ( 散列地址 ) 。<br>【例】假定表中各关键字是由字母组成的，用二位数字的整数 01 ～ 26 表示对应的 26 个英文字母在计算机中的内部编码，则使用平方取中法计算 KEYA ， KEYB ， AKEY ， BKEY 的散列地址可得：<br>关键字 K &nbsp;&nbsp;&nbsp;&nbsp;K 的内部编码 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;K <sup>2</sup> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;H(K) <br>&nbsp;KEYA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11052501 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;122157778355001 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;778<br>&nbsp;KEYB &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;11052502 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;122157800460004 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;800<br>&nbsp;AKEY &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;01110525 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;001233265775625 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;265 <br>&nbsp;BKEY &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;02110525 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;004454315775625 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;315 <br>平方之后，取左起第 7 ～ 9 位作为散列地址。<br><br><strong>2.除留余数法</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;这种方法是用模运算 (%) 得到的。设给出的关键字值为 K ，存储区单元数为 m ，则用一个小于 m 的质数 P 去除 K ，得到的余数为 R ，即： R ＝ K % P 。如果 R 落在存储区地址范围内，则 R 就取为哈希函数值 ( 散列地址 ) ；否则，再用一个线性数求出哈希函数值。<br>【例】有一组关键字从 000001 到 859999 ，指定的存储区地址为 1000000 ～ 1005999 ，即 m ＝ 6000 ，可选 P ＝ 599 ，若要转换关键字 K ＝ 172148 ，则有：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R ＝ 172148 % 599 ＝ 4176 <br>因 R 不在指定的地址范围内，所以，取哈希函数为：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;H(K) ＝ 1000000 ＋ R<br>故有：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;H(K) ＝ H(172148) ＝ 1004176 <br>这样就把关键字 K 直接转换成存储地址了。<br><br><strong>3.数字分析法</strong><br>　　对各个关键字内部代码的各个码位进行分析。假设有 n 个 d 位的关键字，使用 s 个不同的符号 ( 如，对于十进制数，每一位可能出现的符号有 10 个，即 0 、 1 、 2 、&#8230;、 9) ，这 s 个不同的符号在各位上出现的频率不一定相同，它们可能在某些位上分布比较均匀，即每一个符号出现的次数都接近 n/s 次；而在另一些位上分布不均匀。这时，选取其中分布比较均匀的某些位作为哈希函数值 ( 散列地址 ) ，所选取的位数应视存储区地址范围而定，这就是数字分析法。<br><font color=#ff0000>注意：</font><br>　　这种方法适合于关键字值中各位字符分布为已知的情况。<br>例如，给定一组关键字：<br>K 1 ： 542482241 <br>K 2 ： 542813678<br>K 3 ： 532228171<br>K 4 ： 542389671 <br>K 5 ： 542541577 <br>K 6 ： 542985376<br>K 7 ： 542193552 <br><img height=43 src="http://sjjg.js.zwu.edu.cn/SFXX/sanlie/tupian/cc.gif" width=376><br>　　这里 n ＝ 7 ； d ＝ 9 ； s ＝ 10 。为了衡量各位上 s 个字符分布的均匀度，可采用度量标准： 式中 a ik 表示第 i 个字符在第 k 位上出现的 (k ＝ 1 ， 2 ，&#8230;， d) 次数。&#955; k 值越小，可认为分布越均匀。这里，自左向右，各位上字符的分布均匀度为：<br>&#955; １ ＝ (7 － 7/10) 2 ＋ 9 &#215; (0 － 7/10) 2 ＝ 44.1<br>&#955; ２ ＝ 44.1 <br>&#955; ３ ＝ 44.1 <br>&#955; ４ ＝ 7 &#215; (1-7/10) 2 ＋ 3 &#215; (0 － 7/10) 2 ＝ 2.1<br>&#955; ５ ＝ 4 &#215; (1-7/10) 2 ＋ (3 － 7/10) 2 ＋ 5 &#215; (0-7/10) 2 ＝ 8.1 <br>&#955; ６ ＝ 5 &#215; (1-7/10) 2 ＋ (2 － 7/10) 2 ＋ 4 &#215; (0-7/10) 2 ＝ 4.1 <br>&#955; ７ ＝ 3 &#215; (1-7/10) 2 ＋ 2 &#215; (2 － 7/10) 2 ＋ 5 &#215; (0-7/10) 2 ＝ 6.1<br>&#955; ８ ＝ 2 &#215; (1-7/10) 2 ＋ (5 － 7/10) 2 ＋ 7 &#215; (0-7/10) 2 ＝ 22.1 <br>&#955; ９ ＝ 4 &#215; (1-7/10) 2 ＋ (3 － 7/10) 2 ＋ 5 &#215; (0-7/10) 2 ＝ 8.1 <br>　　假定存储区地址为 000 ～ 999 ，则应取关键字的第 4 、 6 、 7 位作为哈希函数值 ( 散列地址 ) ，它们分别为 422 、 836 、 281 、 396 、 515 、 953 和 135 。由于数字分析法需预先知道各位上字符的分布情况，这就大大限制了它的实用性。 <br><br>　 　构造哈希函数除了上面介绍的几种常用方法外，还有截段法，即截取关键字中的某一段数码作为哈希函数；分段迭加法，即把关键字的机内代码分成几段，再进行迭加 ( 可以是算术加，也可以是按位加 ) 得到哈希函数值。对于各种构造哈希函数的方法，很难一概而论地评价其优劣，任何一种哈希函数都应当用实际数据去测试它的均匀性，才能做出正确的判断和结论。 <br><br><br><strong><font size=4>解决冲突的主要方法</font></strong> <br>　　虽然我们不希望发生冲突，但实际上发生冲突的可能性仍是存在的。当关键字值域远大于哈希表的长度，而且事先并不知道关键字的具体取值时。冲突就难免会发生。另外，当关键字的实际取值大于哈希表的长度时，而且表中已装满了记录，如果插入一个新记录，不仅发生冲突，而且还会发生溢出。因此，处理冲突和溢出是哈希技术中的两个重要问题。<br><strong>1、开放定址法</strong><br>&nbsp;&nbsp;&nbsp; 　用开放定址法解决冲突的做法是：当冲突发生时，使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找，直到找到给定的关键字，或者碰到一个开放的地址(即该地址单元为空)为止（若要插入，在探查到开放的地址，则可将待插入的新结点存人该地址单元）。查找时探查到开放的地址则表明表中无待查的关键字，即查找失败。<br>&nbsp; <font color=#ff0000>注意：</font><br>&nbsp;①用开放定址法建立散列表时，建表前须将表中所有单元(更严格地说，是指单元中存储的关键字)置空。<br>&nbsp;②空单元的表示与具体的应用相关。<br>&nbsp;&nbsp;&nbsp; 　按照形成探查序列的方法不同，可将开放定址法区分为线性探查法、线性补偿探测法、随机探测等。<br><font color=#0000ff>（1）线性探查法(Linear Probing)</font><br><strong>该方法的基本思想是：</strong><br>　&nbsp;&nbsp;&nbsp; 将散列表T[0..m-1]看成是一个循环向量，若初始探查的地址为d(即h(key)=d)，则最长的探查序列为：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d，d+l，d+2，&#8230;，m-1，0，1，&#8230;，d-1<br>&nbsp;&nbsp;&nbsp; 　即:探查时从地址d开始，首先探查T[d]，然后依次探查T[d+1]，&#8230;，直到T[m-1]，此后又循环到T[0]，T[1]，&#8230;，直到探查到T[d-1]为止。<br><strong>探查过程终止于三种情况：</strong><br>&nbsp;&nbsp;&nbsp; 　(1)若当前探查的单元为空，则表示查找失败（若是插入则将key写入其中）；<br>　&nbsp;&nbsp;&nbsp; (2)若当前探查的单元中含有key，则查找成功，但对于插入意味着失败；<br>&nbsp;&nbsp;&nbsp; 　(3)若探查到T[d-1]时仍未发现空单元也未找到key，则无论是查找还是插入均意味着失败(此时表满)。<br><strong>利用开放地址法的一般形式，线性探查法的探查序列为：</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; h<sub>i</sub>=(h(key)+i)％m 0&#8804;i&#8804;m-1 //即d<sub>i</sub>=i<br><strong>用线性探测法处理冲突，思路清晰，算法简单，但存在下列缺点：</strong><br>　　① 处理溢出需另编程序。一般可另外设立一个溢出表，专门用来存放上述哈希表中放不下的记录。此溢出表最简单的结构是顺序表，查找方法可用顺序查找。<br>　　② 按上述算法建立起来的哈希表，删除工作非常困难。假如要从哈希表 HT 中删除一个记录，按理应将这个记录所在位置置为空，但我们不能这样做，而只能标上已被删除的标记，否则，将会影响以后的查找。<br>　　③ 线性探测法很容易产生堆聚现象。所谓堆聚现象，就是存入哈希表的记录在表中连成一片。按照线性探测法处理冲突，如果生成哈希地址的连续序列愈长 ( 即不同关键字值的哈希地址相邻在一起愈长 ) ，则当新的记录加入该表时，与这个序列发生冲突的可能性愈大。因此，哈希地址的较长连续序列比较短连续序列生长得快，这就意味着，一旦出现堆聚 ( 伴随着冲突 ) ，就将引起进一步的堆聚。<br>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/38448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-12-13 17:53 <a href="http://www.cppblog.com/sunraiing9/archive/2007/12/13/38448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CL.exe的全部命令开关(摘)</title><link>http://www.cppblog.com/sunraiing9/archive/2007/11/26/37323.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Mon, 26 Nov 2007 07:20:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/11/26/37323.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/37323.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/11/26/37323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/37323.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/37323.html</trackback:ping><description><![CDATA[CL.exe的全部命令开关
<p>&#160;</p>
<p>/C:在预处理输出中保留注释语句<br>/c:只编译，不连接，相当于在"Build"菜单下选择了"Compile"<br>/D:定义常量和宏，与源程序里的#define 有相同效果<br>/E:预处理C、C＋＋源文件，将源文件中所有的预编译指令及宏展开，将注释去掉，然后将预处理器的输出拷贝至标准输出设备输出，并且在每个文件的开头和末尾加入#line<br>/EH:指定编译器用何种异常处理模型<br>/EP:同/E,只是去掉了#line<br>/F:设置程序的堆栈大小<br>/FA:设置生成何种列表文件（汇编、汇编与机器码、汇编与源码、汇编与机器码以及源码）<br>/Fa:指定用/FA设置的列表文件的存放路径及（或）文件名<br>/FD:生成文件的相互依赖信息<br>/Fd:设置程序数据库文件（PDB）的存放路径及（或）文件名<br>/Fe:设置最终可执行文件的存放路径及（或）文件名<br>/FI:预处理指定的头文件，与源文件中的＃include有相同效果<br>/Fm:创建map文件<br>/Fo:设置编译后Obj文件的存放路径及（或）文件名<br>/Fp:设置预编译文件（pch）的存放路径及（或）文件名<br>/FR:生成浏览信息（sbr）文件<br>/Fr:同/FR,不同之处在于/Fr不包括局部变量信息<br>/G3:为80386处理器优化代码生成<br>/G4:为80486处理器优化代码生成<br>/G5:为Pentium处理器优化代码生成<br>/G6:为Pentium Pro处理器优化代码生成<br>/GA:为Windows应用程序作优化<br>/GB:为Pentium处理器优化代码生成，使用80386、80486、Pentium、Pentium Pro的混合指令集，是代码生成的默认选项（程序属性选项中Processor对应Blend）<br>/GD:为Windows动态库（dll）作优化，此开关在VC6中没有实现<br>/Gd:指定使用__cdecl的函数调用规则<br>/Ge:激活堆栈检测<br>/GF:消除程序中的重复的字符串，并将她放到只读的缓冲区中<br>/Gf:消除程序中的重复字符串<br>/Gh:在每个函数的开头调用钩子（hook）函数--penter<br>/Gi:允许渐进编译<br>/Gm:允许最小化rebuild<br>/GR:允许运行时类型信息(Run-Time Type Infomation)<br>/Gr:指定使用__fastcall的函数调用规则<br>/Gs:控制堆栈检测所用内存大小<br>/GT:支持用__declspec(thread)分配的数据的fier-safety<br>/GX:允许同步异常处理，与/EHsc开关等价<br>/Gy:允许编译器将每一个函数封装成COMDATs的形式，供连接器调用<br>/GZ:允许在Debug build 的时候捕捉Release build的错误<br>/Gz:指定使用__stdcall的函数调用规则<br>/H:限制外部名字的长度<br>/HELP:列出编译器的所有的命令开关<br>/I:指定头文件的搜索路径<br>/J:将char的缺省类型从signed char改成unsigned char<br>/LD:创建一个动态连接库<br>/LDd:创建一个Debug版本的动态链接库<br>/link:将指定的选项传给连接器<br>/MD:选择多线程、DLL版本的C Run－Time库<br>/MDd:选择多线程、DLL、Debug版本的C Run－Time库<br>/ML:选择单线程版本的C Run—Time库<br>/MLd:选择单线程、Debug版本的C Run—Time库<br>/MT:选择多线程版本的C Run-Time库<br>/MTd:选择多线程、Debug版本的C Run—Time库<br>/nologo:不显示程序的版权信息<br>/O1:优化使产生的可执行代码最小<br>/O2:优化使产生的可执行代码速度最快<br>/Oa:指示编译器程序里没有使用别名，可以提高程序的执行速度<br>/Ob:控制内联（inline）函数的展开<br>/Od:禁止代码优化<br>/Og:使用全局优化<br>/Oi:用内部函数去代替程序里的函数调用，可以使程序运行的更快，但程序的长度变长<br>/Op:提高浮点数比较运算的一致性<br>/Os:产生尽可能小的可执行代码<br>/Ot:产生尽可能块的可执行代码<br>/Ow:指示编译器在函数体内部没有使用别名<br>/Ox:组合了几个优化开关，达到尽可能多的优化<br>/Oy:阻止调用堆栈里创建帧指针<br>/Q1f:对核心级的设备驱动程序生成单独的调试信息<br>/QI0f:对Pentium 0x0f错误指令作修正<br>/Qifdiv:对Pentium FDIV错误指令作修正<br>/P:将预处理输出写到指定文件里，文件的后缀名为I<br>/TC:将命令行上的所有文件都当作C源程序编译，不管后缀名是否为.c<br>/Tc:将指定的文件当作C源程序编译，不管后缀名是否为.c<br>/TP:将命令行上的所有文件都当作C＋＋源程序编译，不管后缀名是否为.cpp<br>/Tp:将指定文件当作C＋＋源程序编译，不管后缀名是否为.cpp<br>/U:去掉一个指定的前面定义的符号或常量<br>/u:去掉所有前面定义的符号或常量<br>/V:在编译的obj文件里嵌入版本号<br>/vd:禁止/允许构造函数置换<br>/vmb:选择指针的表示方法，使用这个开关，在声明指向某个类的成员的指针之前，必须先定义这个类<br>/vmg:选择指针的表示方法，使用这个开关，在声明指向某个类的成员的指针之前，不必先定义这个类，但要首先指定这个类是使用何种继承方法<br>/vmm:设置指针的表示方法为Single Inheritance and Multiple Inheritance<br>/vms:设置指针的表示方法为Single Inheritance<br>/vmv:设置指针的表示方法为Any class<br>/W:设置警告等级<br>/w:禁止所有警告<br>/X:阻止编译器搜索标准的include 目录<br>/Yc:创建预编译头文件（pch）<br>/Yd:在所有的obj文件里写上完全的调试信息<br>/Yu:在build过程中使用指定的预编译头文件<br>/YX:指示编译器若预编译头文件存在，则使用它，若不存在，则创建一个<br>/Z7:生成MSC7.0兼容的调试信息<br>/Za:禁止语言扩展(Microsoft Extensions to C)<br>/Zd:调试信息只包含外部和全局的符号信息以及行号信息<br>/Ze:允许语言扩展(Microsoft Extensions to C)<br>/Zg:为源文件里面定义的每个函数生成函数原型<br>/ZI:生成程序库文件（Pdb）并支持Edit and Continue调试特性<br>/Zi:生成程序库文件（pdb），包含类型信息和符号调试信息<br>/ZL:从obj文件里去掉缺省的库文件名<br>/Zm:设置编译器的内存分配xianzhi<br>/Zn:禁止浏览信息文件里面的封装<br>/Zp:设置结构成员在内存里面的封装格式<br>/Zs:快速检查语法错误<br>－－－－－－－－－－－－－－－－－－－－－－－－－－<br>vc所支持的文件类型</p>
<p>DSW:全称是Developer Studio Workspace，最高级别的配置文件，记录了整个工作空间的配置信息，她是一个纯文本的文件，在vc创建新项目的时候自动生成<br>DSP:全称是Developer Studio Project，也是一个配置文件，不过她记录的是一个项目的所有配置信息，纯文本文件<br>OPT：与DSW、DSP配合使用的配置文件，她记录了与机器硬件有关的信息，同一个项目在不同的机器上的opt文件内容是不同的<br>CLW：记录了跟ClassWizard相关的信息，如果丢失了clw文件，那么在Class View面板里就没有类信息<br>PLG：实际上是一个超文本文件，可以用Internet Explorer打开，记录了Build的过程，是一个日志型文件<br>RC：资源描述文件，记录了所有的资源信息，在资源编辑器里作的修改，实际上都是对RC文件的修改<br>RC2：附加的资源描述文件，不能直接资源编辑器修改，只能手工添加，可以用来添加额外的资源<br>RES：经过资源编辑器编译之后的资源文件，以二进制方式存放<br>SBR：编译器生成的浏览信息文件，在代码导航的时候非常有用，她需要在编译时指定/FR或者/Fr开关<br>BSC：BSCMAKE.EXE将所有的SBR文件作为输入，经过处理之后输出一个BSC文件，在代码导航的时候实际用到的是BSC文件<br>ILK：当选定渐增型编译连接时，连接器自动生成ILK文件，记录连接信息<br>PDB：全称是Program DataBase，即程序数据库文件，用来记录调试信息，是一个相当重要的文件，没有他，程序无法正常调试<br>LIB：如果项目输出是Dll的话，一般会输出一个跟项目同名的Lib文件，记录输出的函数信息<br>EXP：同Lib，是跟Dll一起生成的输出文件<br>PCH：全称是PreCompiled Header，就是预先编译好的头文件，在编译时指定/Yu开关时编译器自动生成</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/37323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-11-26 15:20 <a href="http://www.cppblog.com/sunraiing9/archive/2007/11/26/37323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>被误解的C++——优化variant实现(摘抄)</title><link>http://www.cppblog.com/sunraiing9/archive/2007/10/09/33854.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 09 Oct 2007 14:35:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/10/09/33854.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/33854.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/10/09/33854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/33854.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/33854.html</trackback:ping><description><![CDATA[<div id=aTitle>
<h1>被误解的C++——优化variant实现</h1>
</div>
<div id=aInfo></div>
<div id=aContent>
<div id=googleJuXing_Ad>&nbsp;</div>
<div id=articleText>所属分类：C/C++ C++ 语言<br>-----------------------------------------<br><br>优化variant实现 <br>上一次，我大概制作了一个variant类型，并设法赋予这个类型同C++内置类型几乎一样的行为。但是，具体实现起来，倒是有点望而生畏。想想看，如果我的variant需要包容5种类型，那么单单一个操作符，就需要5&#215;5+1=26个操作符重载（那单独一个是variant类型操作数的重载）。所有二元操作符都是如此。 <br>通过蛮力来实现variant，尽管可能，但着实愚蠢。我们必须寻找更简单有效的实现途径，避免为了一个&#8220;屁眼大的&#8221;variant（请原谅我说粗话）写上几万行代码，而且这些代码就像一窝小猪仔那样相像。好在C++为我们提供了充足的现代武器，使我们拥有足够的火力摆平这些问题。 <br>让我们先从操作数都是variant的二元操作符入手： <br>variant&nbsp;&nbsp;operator+(&nbsp;const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{&#8230;} <br>&#8230; <br>简单起见，先考察operator+的实现，然后扩展到其他操作符。 <br>由于操作数是variant类型，那么它们可能代表不同的类型。我们必须知道操作数的实际类型，才能对其实施相应的+操作。最传统的办法就是使用switch： <br>variant&nbsp;operator+(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>switch(v1.get_type_code()) <br>{ <br>case&nbsp;vt_double: <br>switch(v2.get_type_code()) <br>{ <br>case&nbsp;vt_double: <br>&#8230;; <br>break; <br>&#8230; <br>} <br>case&nbsp;vt_int: <br>switch(v2.get_type_code()) <br>{ <br>case&nbsp;vt_double: <br>&#8230;; <br>break; <br>&#8230; <br>} <br>&#8230; <br>} <br>} <br>好家伙，又是一个组合爆炸。一步步来，我们先来处理这堆讨人嫌的switch&#8230;case&#8230;。一般而言，对于一个函数（操作符）内的的大量分派操作，可以使用包含函数指针的数组或者容器替代。如果标记值（这里的vt_...）是连续的，可以直接使用数组；如果标记值不连续，可以使用关联容器。这里vt_...是连续的，所以用数组比较方便： <br>typedef&nbsp;variant&nbsp;(*add_op_t)(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2); <br>add_op_t&nbsp;tbl_type_ops[3][3];//函数指针表，假设variant对应三种类型 <br>variant&nbsp;add_op_double_double(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2){&#8230;} <br>variant&nbsp;add_op_double_int(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2){&#8230;} <br>&#8230; <br>variant&nbsp;add_op_int_double(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2){&#8230;} <br>&#8230; <br>tbl_type_ops&nbsp;[vt_double][vt_double]=add_op_double_double; <br>tbl_type_ops&nbsp;[vt_double][vt_int]=add_op_double_int; <br>&#8230; <br>variant&nbsp;operator+(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>returntbl_type_ops&nbsp;[v1.get_type_code()][v2.get_type_code](v1,&nbsp;v2); <br>} <br>operator+的代码是简单了，但是它的代码实际上转嫁到每个专用操作函数add_op_...上去了。并没有简化多少。下一步，我们来处理这些add_op_...： <br>template&lt;typename&nbsp;VT1,&nbsp;typename&nbsp;VT2&gt; <br>variant&nbsp;add_op(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;v2)&nbsp;{ <br>throwexception(string(&#8220;cannot&nbsp;add&nbsp;type&nbsp;&#8221;)+typeid(VT1).typename() <br>+&#8221;to&#8221;+typeid(VT2).typename()); <br>}//主函数模板，对应不兼容类型的操作。抛出异常。 <br>template&lt;&gt; <br>variant&lt;double,&nbsp;double&gt;&nbsp;add_op(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;v2)&nbsp;{ <br>returnvariant(v1.dbval+v2.dbval); <br>}//针对double+double的操作 <br>&#8230; <br>tbl_type_ops&nbsp;[vt_double][vt_double]=add_op&lt;double,&nbsp;double&gt;; <br>tbl_type_ops&nbsp;[vt_double][vt_int]=add_op&lt;double,int&gt;; <br>&#8230; <br>利用函数模板，及其特化，消化掉一部分的冗余代码。利用主函数模板实现所有不能互操作的类型操作，而可操作的类型则使用特化的模板实现。当然，冗余代码还是存在，这部分我们一会儿再处理。先来看看tbl_type_ops的填充。这部分代码也存在组合爆炸。为消除这个问题，我请出了模板元编程（TMP）。当然，我没有那么好的本事去直接倒腾TMP，我&#8220;借用&#8221;了boost::mpl::vector来实现这步优化： <br>//使用mpl::vector存放variant包容的类型 <br>typedef&nbsp;boost::mpl::vector&lt;double,&nbsp;int,&nbsp;string&gt;op_types; <br>const&nbsp;int&nbsp;n_types=boost::mpl::size&lt;op_types&gt;::value; <br>//操作函数指针表 <br>typedef&nbsp;variant&nbsp;(*add_op_t)(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2); <br>add_op_t&nbsp;tbl_type_ops[n_types][n_types]; <br>//填充函数指针表单个元素 <br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n&gt; <br>inline&nbsp;void&nbsp;set_tbl_type()&nbsp;{ <br>typedefmpl::deref&lt;mpl::advance&lt;mpl::begin&lt;op_types&gt;::type,&nbsp; <br>mpl::int_&lt;m&gt;&nbsp;&gt;::type&gt;::typetype_1; <br>typedefmpl::deref&lt;mpl::advance&lt;mpl::begin&lt;op_types&gt;::type,&nbsp; <br>mpl::int_&lt;n&gt;&nbsp;&gt;::type&gt;::typetype_2; <br><br>tbl_type_ops&nbsp;[m][n]=add_op&lt;type_1,&nbsp;type_2&gt;; <br>} <br>//填充函数指针表单元的函数对象类 <br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n&gt; <br>struct&nbsp;fill_tbl_types_n <br>{ <br>void&nbsp;operator()()&nbsp;{ <br>set_tbl_type&lt;m-1,&nbsp;n-1&gt;();//填充函数指针单元 <br>fill_tbl_types_n&lt;m,&nbsp;n-1&gt;()();//递归 <br>} <br>}; <br>template&lt;int&nbsp;m&gt; <br>struct&nbsp;fill_tbl_types_n&lt;m,&nbsp;0&gt;//特化，递归结束 <br>{ <br>void&nbsp;operator()()&nbsp;{} <br>}; <br>//填充函数指针表行的函数对象类 <br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n&gt; <br>struct&nbsp;fill_tbl_types_m <br>{ <br>void&nbsp;operator()()&nbsp;{ <br>fill_tbl_types_n&lt;m,&nbsp;n&gt;()();//创建并调用fill_tbl_types_n函数对象 <br>fill_tbl_types_m&lt;m-1,&nbsp;n&gt;()();//递归 <br>} <br>}; <br>template&lt;int&nbsp;n&gt; <br>struct&nbsp;fill_tbl_types_m&lt;0,&nbsp;n&gt;//特化，递归结束 <br>{ <br>void&nbsp;operator()()&nbsp;{} <br>}; <br>void&nbsp;fill_tbl_op()&nbsp;{ <br>fill_tbl_types_m&lt;n_types,&nbsp;n_types&gt;()(); <br>} <br>这里运用函数对象类模板的特化，构造了函数指针表的填充自动函数。在需要时，只需调用fill_tbl_op()函数即可。该函数中创建fill_tbl_types_m&lt;n_types,&nbsp;n_types&gt;函数对象，然后调用。这个函数对象的operator()首先创建并调用fill_tbl_types_n&lt;m,&nbsp;n&gt;函数对象。后者先调用set_tbl_type&lt;m-1,&nbsp;n-1&gt;模板函数，执行填充tbl_type_op数组的[m-1,&nbsp;n-1]单元格。然后递归调用fill_tbl_types_n&lt;m,&nbsp;n-1&gt;函数对象。直到n-1==0，编译器便会选择特化版本的fill_tbl_types_n&lt;m,&nbsp;0&gt;函数对象。该特化的operator()操作符重载是空的，因此递归结束。这样完成一行的填充。然后，fill_tbl_types_m&lt;m,&nbsp;n&gt;则递归调用fill_tbl_types_m&lt;m-1,&nbsp;n&gt;函数对象，填充下一行。直到调用fill_tbl_types_m&lt;0,&nbsp;n&gt;特化版本，结束递归。 <br>现在需要仔细看一下set_tbl_type&lt;&gt;函数模板。该模板上来就是两个typedef。这两个typedef创建了两个类型别名，分别用m和n做索引，从boost::mpl::vector&lt;double,&nbsp;int,&nbsp;string&gt;中取出相应的类型： <br>typedefmpl::deref&lt;mpl::advance&lt;mpl::begin&lt;op_types&gt;::type,&nbsp; <br>mpl::int_&lt;m&gt;&nbsp;&gt;::type&gt;::typetype_1; <br>&#8230; <br>头晕是吧。我的头还有点晕呢。这就是模板元编程，不停地鼓捣类型。具体的操作可以参考boost文档或《The&nbsp;Template&nbsp;Meta-programming》一书，我这里就不多说了，反正就是从一个存放类型的vector中取出所需的类型。 <br>这样获得的两个类型用来实例化add_op&lt;&gt;()模板函数，并且填充到tbl_type_ops[m][n]元素中。 <br>这样，利用TMP和GP两种强大的机制，消除了tbl_type_ops填充的组合爆炸问题。如果我们需要向variant中加入新的类型，那么只需在mpl::vector&lt;double,&nbsp;int,&nbsp;string&gt;中直接加入类型即可： <br>typedef&nbsp;mpl::vector&lt;double,&nbsp;int,&nbsp;string,&nbsp;bool,&nbsp;datetime&gt;op_types; <br>OK，下面回过头，来处理add_op&lt;&gt;中存在的组合爆炸。对于每一对可以直接或间接相加的类型，都需要做一个add_op&lt;&gt;的特化版本。这当然不够好。我们可以进一步抽象add_op，然后加以优化。我把整个add_op&lt;&gt;模板改写成如下代码： <br>template&lt;typename&nbsp;VT1,&nbsp;typename&nbsp;VT2&gt; <br>variant&nbsp;add_op(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>typedeftype_ret&lt;VT1,&nbsp;VT2&gt;::typeRetT; <br>returnvariant(v1.operator&nbsp;RetT()+v2.operator&nbsp;RetT()); <br>} <br>这里，我首先利用type_ret模板（模板元函数）获得两个操作数相加后应有的返回类型。这个模板一会说明。然后，调用variant上的类型转换操作符，将两个操作数转换成返回类型。最后相加，并创建返回variant对象。代码非常简单，没法再简单了。 <br>再来看看type_ret&lt;&gt;： <br>template&lt;typename&nbsp;T1,&nbsp;typename&nbsp;T2&gt; <br>struct&nbsp;type_ret <br>{ <br>typedefT1type; <br>}; <br>template&lt;&gt; <br>struct&nbsp;type_ret&lt;int,&nbsp;double&gt; <br>{ <br>typedefdoubletype; <br>}; <br>template&lt;&gt; <br>struct&nbsp;type_ret&lt;string,&nbsp;double&gt; <br>{ <br>typedefdoubletype; <br>}; <br>&#8230;//其他类型对的返回类型 <br>type_ret&lt;&gt;是典型的模板元函数，没有任何实际代码，只有编译时计算的typedef。主模板将第一个类型参数typedef出一个别名。其后的模板特化对于一些特殊的情况做出定义，如int和double相加返回第二个操作数类型double（即所谓的类型提升）。 <br>我们现在已经优化了variant+varint的代码。现在来看看如何优化variant类型和其他类型的加法： <br>template&lt;typename&nbsp;T&gt; <br>variant&nbsp;operator+(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;T&amp;&nbsp;v2)&nbsp;{ <br>returnv1+variant(v2); <br>} <br>template&lt;typename&nbsp;T&gt; <br>variant&nbsp;operator+(const&nbsp;T&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>returnvariant(v1)+v2; <br>} <br>这非常简单，直接利用了variant+variant，将其它类型的操作数转换成variant类型，然后相加。 <br><br><br>----------------------------------------------------------------------<br><br>好，加法完成了。但还有其他操作符。每个操作符都做那么一个函数指针表，也不见得高明到哪里去。现在需要整合优化这些操作符。这里，我想到了两种方法：一种是将函数指针表和填充操作整个地封装在一个模板中，模板参数采用int&nbsp;op形式。每一种操作符对应一个整数（或枚举值），并利用某种手段（如singleton）唯一生成一组全局的函数表，以此处理每一种操作。另一种方法是为函数指针表加一个维度（二维扩展到三维），新的维度对应不同的操作符。前一种方法灵活性强些，而且有利于性能优化；而后一种方法实现简单。这里我使用后一种方法： <br>enum <br>{ <br>vt_op_add=0, <br>vt_op_add_assign=1, <br>vt_op_equal=2, <br>vt_op_not_equal=3 <br>&#8230; <br>}; <br>const&nbsp;int&nbsp;vt_op_num=10; <br><br>template&lt;typename&nbsp;T,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;var_op; <br><br>template&lt;typename&nbsp;T&gt; <br>struct&nbsp;var_op&lt;T,&nbsp;vt_op_add&gt; <br>{ <br>T&nbsp;operator()(const&nbsp;T&amp;&nbsp;v1,&nbsp;const&nbsp;T&amp;&nbsp;v2)&nbsp;{ <br>returnv1+v1; <br>} <br>} <br><br>template&lt;typename&nbsp;T&gt; <br>struct&nbsp;var_op&lt;T,&nbsp;vt_op_equal&gt; <br>{ <br>bool&nbsp;operator()(const&nbsp;T&amp;&nbsp;v1,&nbsp;const&nbsp;T&amp;&nbsp;v2)&nbsp;{ <br>returnv1==v1; <br>} <br>} <br>&#8230; <br>template&lt;typename&nbsp;VT1,&nbsp;typename&nbsp;VT2,&nbsp;int&nbsp;op&gt; <br>variant&nbsp;variant_op(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>typedeftype_ret&lt;VT1,&nbsp;VT2&gt;::typeRetT; <br>returnvariant(var_op&lt;RetT,op&gt;()(v1.operator&nbsp;RetT()+v2.operator&nbsp;RetT())); <br>} <br>我使用了一个函数对象模板var_op&lt;&gt;抽象各种算法（二元）。针对每一种运算符特化。抽象的variant_op函数模板实例化var_op&lt;&gt;，然后调用。获得相应的操作。 <br>观察variant_op的模板参数，会发现已经包含了一个操作的基本要素。（眼下这个形式正好符合逆波兰表达式）。 <br>接下来，只需将函数指针数组，及其填充算法加以扩展，便可大功告成： <br>add_op_t&nbsp;tbl_type_ops[n_types][n_types][vt_op_num]; <br>//填充函数指针表单个元素 <br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n,&nbsp;int&nbsp;op&gt; <br>inline&nbsp;void&nbsp;set_tbl_type()&nbsp;{ <br>typedefmpl::deref&lt;mpl::advance&lt;mpl::begin&lt;op_types&gt;::type,&nbsp; <br>mpl::int_&lt;m&gt;&nbsp;&gt;::type&gt;::typetype_1; <br>typedefmpl::deref&lt;mpl::advance&lt;mpl::begin&lt;op_types&gt;::type,&nbsp; <br>mpl::int_&lt;n&gt;&nbsp;&gt;::type&gt;::typetype_2; <br><br>tbl_type_ops&nbsp;[m][n][op]=add_op&lt;type_1,&nbsp;type_2,&nbsp;op&gt;; <br>} <br><br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;fill_tbl_types_op <br>{ <br>void&nbsp;operator()()&nbsp;{ <br>set_tbl_type&lt;m-1,&nbsp;n-1,&nbsp;op-1&gt;(); <br>fill_tbl_types_op&lt;m,&nbsp;n,&nbsp;op-1&gt;()();//递归 <br>} <br>}; <br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n&gt; <br>struct&nbsp;fill_tbl_types_op&lt;m,&nbsp;n,&nbsp;0&gt;//特化，递归结束 <br>{ <br>void&nbsp;operator()(){} <br>} <br><br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;fill_tbl_types_n <br>{ <br>void&nbsp;operator()()&nbsp;{ <br>fill_tbl_types_op&lt;m,&nbsp;n,&nbsp;op&gt;(); <br>fill_tbl_types_n&lt;m,&nbsp;n-1,&nbsp;op&gt;()();//递归 <br>} <br>}; <br>template&lt;int&nbsp;m,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;fill_tbl_types_n&lt;m,&nbsp;0,&nbsp;op&gt;//特化，递归结束 <br>{ <br>void&nbsp;operator()()&nbsp;{} <br>}; <br><br>template&lt;int&nbsp;m,&nbsp;int&nbsp;n,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;fill_tbl_types_m <br>{ <br>void&nbsp;operator()()&nbsp;{ <br>fill_tbl_types_n&lt;m,&nbsp;n,&nbsp;op&gt;()(); <br>fill_tbl_types_m&lt;m-1,&nbsp;n,&nbsp;op&gt;()();//递归 <br>} <br>}; <br>template&lt;int&nbsp;n,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;fill_tbl_types_m&lt;0,&nbsp;n,&nbsp;op&gt;//特化，递归结束 <br>{ <br>void&nbsp;operator()()&nbsp;{} <br>}; <br><br>void&nbsp;fill_tbl_op()&nbsp;{ <br>fill_tbl_types_m&lt;n_types,&nbsp;n_types,&nbsp;vt_op_num&gt;()(); <br>} <br><br>template&lt;typename&nbsp;RetT,&nbsp;int&nbsp;op&gt; <br>struct&nbsp;var_oper <br>{ <br>RetT&nbsp;operator()(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>returntbl_type_ops&nbsp;[v1.get_type_code()][v2.get_type_code] <br>[op](v1,&nbsp;v2).operator&nbsp;RetT(); <br>} <br>template&lt;int&nbsp;op&gt; <br>struct&nbsp;var_oper&lt;variant,&nbsp;op&gt; <br>{ <br>variant&nbsp;operator()(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>returntbl_type_ops&nbsp;[v1.get_type_code()][v2.get_type_code] <br>[op](v1,&nbsp;v2); <br>} <br>于是操作符的实现，成了以下形式： <br>variant&nbsp;operator+(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>returnvar_oper&lt;variant,&nbsp;vt_op_add&gt;(v1,&nbsp;v2); <br>} <br>bool&nbsp;operator==(const&nbsp;variant&amp;&nbsp;v1,&nbsp;const&nbsp;variant&amp;&nbsp;v2)&nbsp;{ <br>returnvar_oper&lt;bool,&nbsp;vt_op_equal&gt;(v1,&nbsp;v2); <br>} <br>&#8230; <br>如果还觉得复杂，那么可以进一步使用宏做一些包装。 <br>好了，variant的优化基本上完成了。当然还会有一些方面值得我们去进一步地优化，比如可以利用boost的type&nbsp;traits和标准库的limit优化type_ret模板的实现和类型转换操作的实现等等。这里不再赘述。 <br>需要说明的是，整个优化仅仅针对代码，并未考虑性能问题。在优化的过程中，某些手法的使用实际上降低的性能。比如函数指针表存在间接调用，不如直接使用inline函数来的高效。而且，函数指针表要求所有指向的函数必须以相同的类型返回。为了兼容+、-等操作，我使用了值返回。但对于+=等操作符完全可以利用引用返回，以提升性能。如果要解决这种问题，需要用前面提到的模板封装函数指针表的方案，为每一个操作符创建一个函数指针表加以解决。 <br>另一个性能问题主要是在variant与其它类型的操作中，其它类型转换成variant类型然后再计算。比起直接使用目标类型计算慢不少。这个问题也可以利用GP和TMP消除，但代码会复杂不少。 <br>理论上，利用inline和编译器优化，可以消除大部分性能问题。但不是所有的，函数指针表的间接调用，是无论如何也优化不掉的。 <br>此外，我在实现函数指针表的构造算法时，没有使用函数模板，而是使用了函数对象模板（重载operator()的模板）。这是因为函数模板目前不能局部特化，而这里是必须的。另一方面，由于使用了递归，函数模板无法做到inline()，而使用函数对象模板则不会有此限制。表达式fill_tbl_types_m()();最终（优化）编译后的结果会是这样（伪码）： <br>tbl_type_ops&nbsp;[2][2][0]=add_op&lt;string,&nbsp;string,&nbsp;0&gt;; <br>tbl_type_ops&nbsp;[2][1][0]=add_op&lt;string,&nbsp;int,&nbsp;0&gt;; <br>&#8230; <br>tbl_type_ops&nbsp;[1][2][0]=add_op&lt;int,&nbsp;string,&nbsp;0&gt;; <br>&#8230; <br>递归和函数对象的调用没有了，完全inline化了。inline函数有时却无法做到这一点。而fill_tbl_types_op等模板实际上起到了代码生成器的作用。这也是GP的一个鲜为人知的功能。如果你有一大堆代码需要编写，而这些代码有很强的规律性和重复性，那么请优先考虑使用模板来为你生成代码，又快又好。 <br>该总结了。如果审视一些代码，会发现只要存在重复和规律性，我们总能利用一些技术和方法加以优化，减少代码量，简化代码结构，减少潜在错误，最终提高开发效率。这里，我使用了C++的泛型编程和模板元编程技术，大幅优化了variant类型中的大量冗余代码。并且为variant类型构建了一个灵活，而又易于扩充的结构。此类技术有很广的应用，不仅仅局限在variant这种底层构件中。相关的一个应用就是构造抽象类工厂，在《Modren&nbsp;C++&nbsp;Design》一书中，有很完整的案例。 <br>此外，这类技术对于调和运行时多态（OOP）和编译时多态（GP）的矛盾有很大的作用。variant只有在运行时方能确定其具体的类型，而C++的模板只能提供编译时的GP。我利用函数指针数组（当然在更复杂的应用中，可以利用OOP的动多态机制），实现运行时分派操作。而利用GP和TMP大幅简化函数指针数组、操作实现函数，以及操作符的构造。这些技术和方法可以在大多数需要运行时多态，但又存在大量重复或雷同代码的地方得以应用。 <br><br></div>
</div>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/33854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-10-09 22:35 <a href="http://www.cppblog.com/sunraiing9/archive/2007/10/09/33854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数指针当参数传入的写法</title><link>http://www.cppblog.com/sunraiing9/archive/2007/10/08/33748.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Mon, 08 Oct 2007 03:28:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/10/08/33748.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/33748.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/10/08/33748.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/33748.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/33748.html</trackback:ping><description><![CDATA[<p>#include &lt;iostream&gt;<br>using namespace std;</p>
<p>int F1(int N);<br>int F2(int N);<br>int MyF(int (*pF)(int), int);</p>
<p>void main()<br>{<br>&nbsp;cout&lt;&lt;"函数指针调用F1，此时的结果为："&lt;&lt;MyF(F1, 4)&lt;&lt;endl;<br>&nbsp;cout&lt;&lt;"函数指针调用F2，此时的结果为："&lt;&lt;MyF(F2, 4)&lt;&lt;endl;<br>}</p>
<p>//函数F1、F2、pF的定义<br>int F1(int N)<br>{<br>&nbsp;return N*N;<br>}</p>
<p>int F2(int N)<br>{<br>&nbsp;return N+N;<br>}</p>
<p>int MyF(int (*pF)(int), int N)<br>{<br>&nbsp;return pF(N);<br>}</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/33748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-10-08 11:28 <a href="http://www.cppblog.com/sunraiing9/archive/2007/10/08/33748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Assert 宏</title><link>http://www.cppblog.com/sunraiing9/archive/2007/09/21/32595.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Thu, 20 Sep 2007 22:55:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/09/21/32595.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/32595.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/09/21/32595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/32595.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/32595.html</trackback:ping><description><![CDATA[<div class=postbody>Assert 宏应该大家都知道是干什么用的吧， 可能大家一般都用来检查下指针为空啊。 <br>不过assert还有许多使用技巧的。 <br><br>1.基本用法 <br><br>void VectorNormalize(Vec* src, Vec* dat) <br>{ <br>float length; <br>assert(src!=0);//检查src向量必须不为空 <br>assert(dst!=0);//检查dst向量必须不为空 <br><br>.................. <br>.................. <br>} <br><br>2.让assert嵌入更多的信息 <br><br>void VectorNormalize(Vec* src, Vec* dst) <br>{ <br>float length; <br>assert(src!=0 &amp;&amp; "VectorNormalize: src vector pointer is Null"); <br>assert(dst!=0 &amp;&amp; "VectorNormalize: dst vector pointer is Null"); <br><br>................... <br>................... <br>} <br>有了这个直观的字符串提示，就可以告诉当前的函数名，错误原因。 <br></div>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/32595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-09-21 06:55 <a href="http://www.cppblog.com/sunraiing9/archive/2007/09/21/32595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>虚拟继承</title><link>http://www.cppblog.com/sunraiing9/archive/2007/09/21/32594.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Thu, 20 Sep 2007 22:47:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/09/21/32594.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/32594.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/09/21/32594.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/32594.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/32594.html</trackback:ping><description><![CDATA[class &nbsp; shape &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shape(int){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; class &nbsp; circle: &nbsp; public &nbsp; shape &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; circle(int): &nbsp; shape(1){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; class &nbsp; square: &nbsp; public &nbsp; shape &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; square(int): &nbsp; shape(1){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; class &nbsp; bizzare: &nbsp; public &nbsp; circle, &nbsp; public &nbsp; square &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bizzare(): &nbsp; circle(1), &nbsp; square(1){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 这里用的就是一般的多重继承，没有虚拟继承的存在。在bizzare（之所以叫这个名字，因为&#8230;&#8230;从circle和square继承而来实在是够怪异的了，呵呵）类的member &nbsp; initialization &nbsp; list中，只需要写circle和square类的构造函数就可以了，后两者再分别调用它们的基类shape（分别的两个实例）的构造函数。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 而如果是虚拟继承： &nbsp; <br>&nbsp; class &nbsp; shape &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shape(int){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; class &nbsp; circle: &nbsp; public &nbsp; virtual &nbsp; shape &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; circle(int): &nbsp; shape(1){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; class &nbsp; square: &nbsp; public &nbsp; virtual &nbsp; shape &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; square(int): &nbsp; shape(1){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; class &nbsp; bizzare: &nbsp; public &nbsp; circle, &nbsp; public &nbsp; square &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bizzare(): &nbsp; circle(1), &nbsp; square(1), &nbsp; shape(1){} &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 则必须在most &nbsp; derived的派生类中初始化虚拟基类。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; TC++PL上肯定有说的，在class &nbsp; hierarchy那章。<br><br><br><br><br>这是语言规定。因为只有一个sharp对象，从哪个基类构造都有问题（因为它们可能调用虚基类的不同构造函数，产生二义性），所以标准规定必须在most &nbsp; derived构造时显式或隐式（虚基类有缺省构造函数时）构造虚基类。楼主的例子里sharp没有缺省构造函数，所以必须显式构造。 &nbsp; <br>&nbsp; TC++PL里有： &nbsp; <br>&nbsp; The &nbsp; constructor &nbsp; of &nbsp; a &nbsp; virtual &nbsp; base &nbsp; is &nbsp; invoked &nbsp; (implicitly &nbsp; or &nbsp; explicitly) &nbsp; from &nbsp; the &nbsp; constructor &nbsp; for &nbsp; the &nbsp; complete &nbsp; object &nbsp; (the &nbsp; constructor &nbsp; for &nbsp; the &nbsp; most &nbsp; derived &nbsp; class).<br><br><br>虚拟继承：发生在多重继承上，比如：一个类继承两类，但是这两个类都继承一个类。（类图出现环），即&#8220;孙子&#8221;到&#8220;爷爷&#8221;的<nobr oncontextmenu="return false;" onmousemove=kwM(3); id=key3 onmouseover="kwE(event,3, this);" style="COLOR: #6600ff; BORDER-BOTTOM: 0px dotted; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">路径</nobr>超过一条时，使用，要不会有两个&#8220;爷爷&#8221; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 虚函数：与继承完成多态工作。是面向对象关键中的关键。由于面向对象的设计是自顶向下的，先功能定义在实现。继承主要有实现继承和接口继承，都需要多态&nbsp;&nbsp; <br>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/32594.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-09-21 06:47 <a href="http://www.cppblog.com/sunraiing9/archive/2007/09/21/32594.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可变参数函数设计</title><link>http://www.cppblog.com/sunraiing9/archive/2007/09/02/31378.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sun, 02 Sep 2007 04:29:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/09/02/31378.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/31378.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/09/02/31378.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/31378.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/31378.html</trackback:ping><description><![CDATA[可变参数函数设计<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"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdarg.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;mul(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;num,</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;data1,<img src="http://www.cppblog.com/Images/dot.gif">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;total&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;data1;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;arg,i;<br>&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;ap;<br>&nbsp;&nbsp;&nbsp;&nbsp;va_start(ap,data1);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">num;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arg&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;va_arg(ap,</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total</span><span style="COLOR: #000000">*=</span><span style="COLOR: #000000">arg;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;va_end(ap);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;total;<br>}<br><br></span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;mul2(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i,<img src="http://www.cppblog.com/Images/dot.gif">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p,j;<br>&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">p指向参数列表下一个位置</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;(j</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;j</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">i;j</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;</span><span style="COLOR: #000000">*=</span><span style="COLOR: #000000">&nbsp;p[j];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;s;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,mul(</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">));<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,mul2(</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">));<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
<br><br><br>printf的设计<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"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdlib.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdarg.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;myprintf(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;fmt,&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">一个简单的类似于printf的实现，</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">参数必须都是int&nbsp;类型</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">char*&nbsp;pArg=NULL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">等价于原来的va_list</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;pArg;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;c;<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;pArg&nbsp;=&nbsp;(char*)&nbsp;&amp;fmt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">注意不要写成p&nbsp;=&nbsp;fmt&nbsp;!!因为这里要对参数取址，而不是取值<br>&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;pArg&nbsp;+=&nbsp;sizeof(fmt);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">等价于原来的va_start&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;va_start(pArg,fmt);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;</span><span style="COLOR: #000000">=*</span><span style="COLOR: #000000">fmt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(c&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putchar(c);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">照原样输出字符</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">按格式字符输出数据</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">switch</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">*++</span><span style="COLOR: #000000">fmt)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">d</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%d</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pArg));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">x</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%#x</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pArg));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">f</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%f</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">float</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pArg));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">default</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">pArg&nbsp;+=&nbsp;sizeof(int);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">等价于原来的va_arg</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_arg(pArg,</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">fmt;<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">fmt&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">pArg&nbsp;=&nbsp;NULL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">等价于va_end</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;va_end(pArg);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1234</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;j&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5678</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;myprintf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">the&nbsp;first&nbsp;test:i=%d</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,i,j);<br>&nbsp;&nbsp;&nbsp;&nbsp;myprintf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">the&nbsp;secend&nbsp;test:i=%f;&nbsp;%x;j=%d;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,i,</span><span style="COLOR: #000000">0xabcd</span><span style="COLOR: #000000">,j);<br>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
<br><br><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">可变参数在编译器中的处理</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">&nbsp;<br><br></span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;我们知道</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_start,va_arg,va_end</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">是在</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">stdarg.h</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">中被定义成宏的</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">, </span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">由于</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">1)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">硬件平台的不同</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> 2)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">编译器的不同</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">所以定义的宏也有所不同</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">下面以</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">VC++</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">中</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">stdarg.h</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">里</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">x86</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">平台的宏定义摘录如下</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">(&#8217;"&#8217;</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">号表示折行</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">): <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 alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">typedef&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;va_list;&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;_INTSIZEOF(n)&nbsp;\&nbsp;</span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>((</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(n)</span><span style="COLOR: #000000">+</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;~</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)&nbsp;)&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;va_start(ap,v)&nbsp;(&nbsp;ap&nbsp;=&nbsp;(va_list)&amp;v&nbsp;+&nbsp;_INTSIZEOF(v)&nbsp;)&nbsp;</span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;va_arg(ap,t)&nbsp;\&nbsp;</span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>(&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">(t&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)((ap&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;_INTSIZEOF(t))&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;_INTSIZEOF(t))&nbsp;)&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;va_end(ap)&nbsp;(&nbsp;ap&nbsp;=&nbsp;(va_list)0&nbsp;)&nbsp;</span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p class=MsoNormal><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;定义</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">_INTSIZEOF(n)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">主要是为了某些需要内存的对齐的系统</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.C</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">语言的函数是从右向左压入堆栈的</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">图</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">(1)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">是函数的参数在堆栈中的分布位置</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">我们看到</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_list</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">被定义成</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">char*,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">有一些平台或操作系统定义为</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">void*.</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">再看</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_start</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">的定义</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">定义为</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">&amp;v+_INTSIZEOF(v),</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">而</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">&amp;v</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">是固定参数在堆栈的地址</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">所以我们运行</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_start(ap, v)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">以后</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,ap</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">指向第一个可变参数在堆栈的地址</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">如图</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">: <br></p>
<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 alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">高地址</span><span style="COLOR: #000000">|-----------------------------|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">函数返回地址&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|-----------------------------|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"><img alt="" src="http://www.cnblogs.com/Images/dot.gif"><img alt="" src="http://www.cnblogs.com/Images/dot.gif">.&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|-----------------------------|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">第n个参数(第一个可变参数)&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|-----------------------------|&lt;--</span><span style="COLOR: #000000">va_start后ap指向&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">第n</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1个参数(最后一个固定参数)</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>低地址</span><span style="COLOR: #000000">|-----------------------------|&lt;--</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">v&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>图(&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;)&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p class=MsoNormal><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;然后</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">我们用</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_arg()</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">取得类型</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">t</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">的可变参数值</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">以上例为</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">int</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">型为例</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">我们看一下</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_arg</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">取</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">int</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">型的返回值</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">: j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) ); <br></span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">首先</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">ap+=sizeof(int),</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">已经指向下一个参数的地址了</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">然后返回</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">ap-sizeof(int)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">的</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">int*</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">指针</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">这正是第一个可变参数在堆栈里的地址</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">(</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">图</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">2).</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">然后用</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">*</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">取得这个地址的内容</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">(</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">参数值</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">)</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">赋给</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">j. <br></p>
<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 alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">高地址</span><span style="COLOR: #000000">|-----------------------------|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">函数返回地址&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|-----------------------------|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"><img alt="" src="http://www.cnblogs.com/Images/dot.gif"><img alt="" src="http://www.cnblogs.com/Images/dot.gif">.&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|-----------------------------|&lt;--</span><span style="COLOR: #000000">va_arg后ap指向&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">第n个参数(第一个可变参数)&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|-----------------------------|&lt;--</span><span style="COLOR: #000000">va_start后ap指向&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">第n</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1个参数(最后一个固定参数)</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>低地址</span><span style="COLOR: #000000">|-----------------------------|&lt;--</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">v&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>图(&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;)&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p class=MsoNormal><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;最后要说的是</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_end</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">宏的意思</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,x86</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">平台定义为</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">ap=(char*)0;</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">使</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">ap</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">不再指向堆栈</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">而是跟</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">NULL</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">一样</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">有些直接定义为</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">((void*)0),</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这样编译器不会为</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_end</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">产生代码</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">例如</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">gcc</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">linux</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">x86</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">平台就是这样定义的</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在这里大家要注意一个问题</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">:</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">由于参数的地址用于</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_start</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">宏</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">所以参数不能声明为寄存器变量或作为函数或数组类型</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">关于</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">va_start, va_arg, va_end</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的描述就是这些了</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们要注意的是不同的操作系统和硬件平台的定义有些不同</span><span lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">但原理却是相似的</span></p>
</span></span></span>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/31378.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-09-02 12:29 <a href="http://www.cppblog.com/sunraiing9/archive/2007/09/02/31378.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC  RTTI的三个宏</title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/29/31158.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 29 Aug 2007 07:18:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/29/31158.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/31158.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/29/31158.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/31158.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/31158.html</trackback:ping><description><![CDATA[<br><br>mfc的三个宏 &nbsp; &nbsp; <br>&nbsp; DECLARE_DYNAMIC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持RTTI &nbsp; <br>&nbsp; DECLARE_DYNCREATE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持RTTI &nbsp; 类动态创建 &nbsp; <br>&nbsp; DECLARE_SERIAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持RTTI &nbsp; 类动态创建 &nbsp; 及序列化&nbsp;&nbsp;&nbsp;&nbsp; <br>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/31158.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-29 15:18 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/29/31158.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程安全</title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/15/30046.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 15 Aug 2007 00:09:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/15/30046.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/30046.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/15/30046.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/30046.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/30046.html</trackback:ping><description><![CDATA[MFC对象不要跨线程使用，因为MFC不是线程安全的。比如CWnd对象不要跨线程使用,可以用窗口句柄（HWND）代替。CSocket/CAsyncSocket对象不要跨线程使用,用SOCKET句柄代替.那么到底什么是线程安全呢?什么时候需要考虑?如果程序涉及到多线程的话，就应该考虑线程安全问题。比如说设计的接口，将来需要在多线程环境中使用，或者需要跨线程使用某个对象时，这个就必须考虑了。关于线程安全也没什么权威定义。在这里我只说说我的理解：所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
<p>&nbsp;&nbsp;&nbsp; 一般而言&#8220;线程安全&#8221;由多线程对共享资源的访问引起。如果调用某个接口时需要我们自己采取同步措施来保护该接口访问的共享资源,则这样的接口不是线程安全的.MFC和STL都不是线程安全的. 怎样才能设计出线程安全的类或者接口呢?如果接口中访问的数据都属于私有数据,那么这样的接口是线程安全的.或者几个接口对共享数据都是只读操作,那么这样的接口也是线程安全的.如果多个接口之间有共享数据,而且有读有写的话,如果设计者自己采取了同步措施，调用者不需要考虑数据同步问题，则这样的接口是线程安全的，否则不是线程安全的</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/30046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-15 08:09 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/15/30046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>_stdcall(WINAPI) 与 _cdecl的区别</title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/15/30045.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 14 Aug 2007 23:56:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/15/30045.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/30045.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/15/30045.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/30045.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/30045.html</trackback:ping><description><![CDATA[_stdcall是新标准C/C++函数的调用方法.从底层上说,使用这种调用方法参数的进栈顺序和标准C调用(_cdecl方法)是一样的,都是从右到左,但是_stdcall采用自动清栈的方式,而_cdecl是手工清栈.<br><br>windows规定,凡事有它来负责调用的函数必须定义为_stdcall类型.<br><br>比如回调函数.<br><br>如果没有显试声明的话,函数的调用方法默认是_cdecl.
<img src ="http://www.cppblog.com/sunraiing9/aggbug/30045.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-15 07:56 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/15/30045.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EXPORTER LAB</title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/14/29995.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 14 Aug 2007 08:35:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/14/29995.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/29995.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/14/29995.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/29995.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/29995.html</trackback:ping><description><![CDATA[<h2>EXPORTER LAB</h2>
<p>Overview: This lab will work through the process of creating a simple &#8220;Exporter&#8221; MAX Plug-in. The goal of the lab will be to familiarize the developer with the basics of creating a MAX plug-in, and the basics of exporting 3ds max scene data.</p>
<p>This lab is composed of 5 phases. At the beginning of each phase you will find a link to a .zip file that contains source code for the exporter that is relevant to the topic of that phase. Phase 0 provides the basic Microsoft Visual C++ v6 project skeleton. Each phase builds upon what was discussed in the previous ones, so simply replace and add the files in the source of the current phase to the previous ones.</p>
<blockquote>
<h3>Table of Contents</h3>
<h5>PHASE 0: STARTING OUT</h5>
<h5>PHASE 1 : GEOMETRY</h5>
<h5>PHASE 2 : TEXTURES AND LIGHTING</h5>
<h5>PHASE 3: ANIMATION AND MODIFIERS</h5>
<h5>PHASE 4: CUSTOM DATA</h5>
<h5>OTHER STRATEGIES, FUTURE DIRECTIONS</h5>
</blockquote>
<hr>
</hr>
<h3>Legend</h3>
<p>In order to help in identifying the various entries in this document the following legend will be applied:</p>
<p>MaxSDK Classes are in this format: IDerivedObject</p>
<p>MaxSDK Methods are in this format: DoExport()</p>
<p>Filenames are in this format: export.cpp</p>
<p>Source code that is only relevant to this tutorial are in this format: PerFaceData</p>
<hr>
</hr>
<h3>PHASE 0: STARTING OUT</h3>
<p>Source code for Phase 0: phase0.zip</p>
<p>We&#8217;ll start with the process of creating our own &#8220;skeleton&#8221; plug-in from scratch.</p>
<p>In general, when creating plug-ins, I try the following steps in the following order:
<p>
<ol>
    <li>If a skeleton for the plug-in types exists, I start with that
    <li>If not, I use the AppWizard, if the wizard supports the plug-in type
    <li>Otherwise, I do the following </li>
</ol>
<p>Create a new Win32 DLL project in MSDEV. I usually put the plug-in project under the MAXSDK directory.</p>
<p>I setup the project configs to build the plugin DLL, with the appropriate extension, into the MAXSDK\PLUGIN directory. I use relative paths and add ..\include to the include path and ..\lib to the lib path. I setup the C Runtime settings as appropriate (Debug Multithreaded DLL for Debug and Multithreaded DLL for Release), and create the Hybrid project configuration (by copying the Debug config, but setting the C Runtime to release-mode Multithreaded DLL)</p>
<p>I usually add 2 CPPs ([PLUGINNAME].CPP and DLLENTRY.CPP), the former will hold the various implementation code for the actual plugin-type derived class(es), the latter will hold the requirement C-style plugin DLL exports. Likewise, I usually add a PLUGINNAME.H that has the class definitions of the plugin-type derived class(es).</p>
<p>I add the appropriate [PLUGINNAME].DEF file, with the appropriate 3ds max DLL exports. The def file looks something like:</p>
<blockquote>
<pre>LIBRARY MyPlugIn
EXPORTS
LibDescription		@1
LibNumberClasses	@2
LibClassDesc		@3
LibVersion		@4
SECTIONS
.data READ WRITE
</pre>
</blockquote>
<p>I add a string table to the resources, along with a version resource. If the plug-in has a dialog, I add one. For this simple exporter lab, there is no additional dialog (well, there&#8217;s the about box, which doesn&#8217;t really count).</p>
<h4>Plug-in Requirements</h4>
<p>I then proceed to add the basic classes that all plug-ins need. I start with coding the DLL exports, which are more or less boilerplate, into DLLENTRY.CPP. This in turn (via LibClassDesc) leads directly to the creation of the required plug-in ClassDesc.</p>
<p>The DLL exports are fairly self-explanatory. DLLMain (not an export per se) initializes some custom controls. LibDescription will return the localized string that describes the plugin. LibNumberClasses returns the number of plug-in type classes the plug-in DLL provides (for this example, we only provide 1). LibClassDesc returns the ClassDesc for 3ds max to use to identify and create plug-in type objects. LibVersion returns the version of MAX the plug-in works with, which is always defined in the 3ds max headers as VERSION_3DSMAX.</p>
<p>LibClassDesc often just returns the address of a single static ClassDesc. For this tutorial, I derived from ClassDesc2. In general, for those familiar with this process, I recommend working with ClassDesc2 and ParamBlock2 instead of their predecessors. In general, the previous versions will be phased out in the future.</p>
<p>As discussed earlier, the ClassDesc acts mainly as a class factory for the main derived plug-in class. In this case, the main plug-in class we will derive from SceneExport. In our plugin we declare derivations of both ClassDesc2 and SceneExport. Typically, a single static instance of the derived ClassDesc is created and returned by LibClassDesc. The derivation also returns category, class ID, and name information about our derivation of SceneExport. The SDK has a tool (GENCID.EXE) that provides an easy way to create unique Class Ids.</p>
<p>This brings us to the plug-in type object derivation. We provide a derivation for SceneExport in our header (MyExporter). The basic required overrides for SceneExport are briefly explained as follows:</p>
<blockquote>int ExtCount() : Returns the number of file extensions that the exporter provides (for our example, we provide 1, which I arbitrarily decided would be &#8220;MEP&#8221;).<br>const TCHAR * Ext(int n) : Returns the 3-letter file extension string for the given extension index (0-based).<br>const TCHAR * LongDesc() : Provides the &#8220;long&#8221; description of the file export format.<br>const TCHAR * ShortDesc() : Provides the &#8220;short&#8221; description of the file export format, shown in the file export dialog drop-down.<br>const TCHAR * AuthorName() : Provides the string that describes the author and/or company of the exporter plugin.<br>const TCHAR * CopyrightMessage() : Provides the string that shows the copyright for the given exporter and/or exporter format.<br>const TCHAR * OtherMessage1() : not used<br>const TCHAR * OtherMessage2() : not used<br>unsigned int Version() : Somewhat redundant, but returns a version number for the exporter.<br>void ShowAbout() : Shows an about box, accessible by the user from the main MAX export dialog.<br>int DoExport() : The actual export method. BOOL SupportsOptions() : Returns TRUE if the exporter supports some custom export options. Currently, only one option (export selected versus export entire scene) exists.<br></blockquote>
<p>Most of the methods are basic returns of localized strings from the string table, or constants/defines. The real &#8220;meat&#8221; of an exporter plugin is the DoExport method, which we&#8217;ll expand in the next sections. This example is simple and therefore has no custom exporter options. You may want to take a look at the exporter samples, and the skeleton exporter, for a simple way to provide a special &#8220;before export&#8221; dialog that has exporter-specific options.</p>
<p>I added some protected methods (DoHeader, DoNodes, DoTailer) in my basic plan of exporting scene-global information, followed by per-node information, followed by any &#8220;end delimiter&#8221; file information (if nececssary). I also added some cached pointer member variables, and a cached FILE pointer to open/write to during the actual export.</p>
<blockquote>
<ul>
    <li>Note: Some of the above can be read about in more detail in a section of the SDK helpfile titled &#8220;Creating a New Plug-In Project&#8221;.
    <li>Note 2: You may note that in the SDK samples, many different styles of code organization are used. Feel free to use the style you feel most comfortable with. </li>
</ul>
</blockquote>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Create a sub-directory off your MAXSDK directory called &#8220;Exporter&#8221;
    <li>Un-zip / Copy Phase0 project/source files into Exporter directory
    <li>Start MSDEV, and open Exporter project
    <li>Examine the Project and Build settings. Notice the extra Hybrid Build configuration. Notice the relative lib paths and the added MAX libraries, the output destination, and the C-Runtime type (Multithreaded DLL or Debug Multithreaded DLL)
    <li>Examine the project files. First, look at the EXPORTER.DEF file and notice the four DLL exports
    <li>Look at the DLLENTRY.CPP file, and examine each of the DLL exports closely, including the DLLMain. This CPP is complete, and we will not need to modify it for the remainder of the session
    <li>Look at EXPORTER.H. Notice the #define MYEXP_CLASSID , and the MyExporter declaration.
    <li>Look at EXPORTER.CPP. Notice the MyExporterClassDesc declaration and implementation. Notice the (mostly empty at this point) implementation of MyExporter.
    <li>Examine the Project resources, which at this point include a generic About Box Dialog resource, a generic Version resource, and a String Table resource.
    <li>If you have the compiler and 3ds max handy, feel free to go ahead and compile the plugin (suggested you use Hybrid Build Configuration at this point) and try using it. In 3ds max, you can either doa File-&gt;Export orFile-&gt;Export Selected (if there are objects selected), and get the File Export Dialog. In that dialog, if the plug-in is properly loaded, you should find the &#8220;*.MEP&#8221; MyExporter format. Naturally, at this point, if you export to this format, you&#8217;ll get an empty file. </li>
</ol>
</blockquote><!-- end of phase 0 ********************************************************************** -->
<hr>
</hr>
<h3>PHASE 1 : GEOMETRY</h3>
<p>Source code for Phase 1: phase1.zip</a></p>
<p>For the first actual 3ds max scene contents we export, we&#8217;ll concentrate on just the geometry of geometric scene objects.</p>
<p>To facilitate working with nodes in the 3ds max scene, we first need to create a node enumerator method that walks over and processes the nodes in the MAX scene. There are various ways to do this: provide our own method that walks the scene manually, or utilize IScene and TreeEnum callbacks via ExpInterface. For this example, we&#8217;ll code our own enumerator from scratch.</p>
<p>For some brief backgrounder information on 3ds max's Scene hierarchy, the basic layout is of a scene tree, with a single &#8220;root&#8221; Node, whose children are all the nodes in the scene. If a node has a heirarchy (via a 3ds max &#8220;link&#8221;, or perhaps based on the layout of the object, e.g. bones), this will be represented in the &#8220;tree&#8221; as well. The Schematic view gives a pretty good visual idea of what this more or less looks like.</p>
<p>The Root node is somewhat special, and can be accessed via the Interface::GetRootNode utility method. The Root node doesn&#8217;t represent any actual geometry or the like.</p>
<p>For our node walker, the basic pseudo-code looks something like:</p>
<blockquote>
<pre>nodeEnum(Node ptr)
If the ptr isn&#8217;t valid, exit
If the ptr isn&#8217;t selected, and we&#8217;re exporting only selected nodes, exit
If the user canceled (usually via ESC), exit
Otherwise
Evaluate the object, determine what type of object it is, and call
a specific helper method that exports that type of object
For each child of the current ptr Node
nodeEnum(child)
</pre>
</blockquote>
<p>The code that will call the &#8220;nodeEnum&#8221; will be in MyExporter::DoNodes, and look something like:</p>
<blockquote>
<pre>Get a count of the children of the Root Node
For each child of the Root Node
Check for cancel and break if cancelled
nodeEnum(child)
</pre>
</blockquote>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Based on the above pseudo-code, write the given portions of code. You&#8217;ll need to look at INode ( ::Selected(), ::NumberOfChildren(), ::GetChildNode(), ::EvalWorldState()), Interface ( ::GetRootNode(), ::GetCancel()) and possibly ObjectState and Object (::SuperClassID()) in the SDK docs
    <li>Compare your code with the code snippet from Phase 1 exporter-nodeenum.cpp </li>
</ol>
</blockquote>
<p>ObjectState and Node::EvalWorldState are probably worth a bit more explanation. As you may already know, the 3ds max geometry pipeline maintains a &#8220;Object&#8221; that flows up the pipeline, and can essentially be represented by different, animated states, starting with a &#8220;Base&#8221; object, then possibly into a &#8220;Derived&#8221; object with a modifier, and so on.</p>
<p>EvalWorldState tells the node to take it&#8217;s Object &#8220;stack&#8221; and effectively make a collapsed copy, such that the resulting ObjectState contains the final end-result of the stack. This is also what is effectively used at Render time.</p>
<blockquote>
<ul>
    <li>Note: I also added some code to MyExporter::DoHeader that exports some basic header file information (date/time created, title string, etc). Feel free to examine. </li>
</ul>
</blockquote>
<h4>Meshes</h4>
<p>3ds max Meshes are triangle polygonal meshes. Every geometric (renderable) object in a 3ds max scene must be able to convert itself to a triangle mesh. Anything in the scene collapsed to a editable mesh will already be in tri-mesh form, however primitives (modified or not) may not be. To get the triangle mesh, we use the Object::ConvertToType API and request a TRIOBJ_CLASS_ID.</p>
<p>When calling ConvertToType, it&#8217;s important to check the returned result pointer, and see if it&#8217;s the same as the original Object pointer. If so, this implies the Object didn&#8217;t generate any new stuff, and thus we shouldn&#8217;t delete the result. Otherwise, the Object did generate a new mesh, and we, the caller, are responsible for freeing the mesh.</p>
<p>Once we have a mesh, we extract and dump out the number of vertices and number of faces. This information is available as APIs off the Mesh class.</p>
<p>As the mesh data is in Object Space, we need to get the Node Transform Matrix (for the current frame). We export this first in generic row-major format.</p>
<p>We then export the world-space point of each mesh vertex, multiplying the vertices by the object TM.</p>
<p>We then export the faces, described by three indices into the vertex array. The vertices, taken in counter-clockwise order, describe the &#8220;front&#8221; (positive normal) of the face. We also export the &#8220;edge visibility&#8221;, which describes, for a given edgeA-&gt;B, if 3ds max draws a highlight line in the viewport or not, and also if in edit-mesh-edge mode, if the edge can be selected. Finally, we export the smoothing group for each face, which could be used with the vertex normals (which we don&#8217;t export for now, left as an exercise) to smooth the mesh via Phong or other shading method.</p>
<p>For this phase, we do not export any mesh material or UV information. This will be done in Phase 2. </p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>In the last part, we had nodeEnum call a utility method to export GeomObjects (in the code sample this is MyExporter::ExportGeomObject). Try implementing ExportGeomObject to export the Node Transform Matrix, and if the Node can convert itself to a TriObject, try exporting the Mesh information. You&#8217;ll need to look at Inode::GetNodeTM() and the Matrix3/Point3 classes in the SDK docs for getting the matrix information. You&#8217;ll need to look at the Object::ConvertToType() and TriObject and Mesh class in the docs for exporting the mesh information.
    <li>Compare the code with the code fragment exporter-geom.cpp. The code fragment has both the mesh and the patch (next) exporter code &#8211; the mesh exporter code is the second &#8220;chunk&#8221; in ExportGeomObject. </li>
</ol>
</blockquote>
<h4>Patches</h4>
<p>For patches, we provide an additional code path in ExportGeomObject that looks for PATCHOBJ_CLASS_ID and exports the patch information. Patches in the 3ds max scene can be patch grids, or any object converted to an editable patch.
<p>As with Meshes, we use ConvertToType to get the PatchObject out. The PatchObject will contain the PatchMesh object, which contains all the overall geometric information (total verts, vectors, edges). We export all the information for both triangular and quad patches. Note that a PatchMesh can contain a collection of actual tri/quad patches, described by indices into the various overall PatchVert/PatchVec/PatchEdge arrays.</p>
<p>Patches can be either TriPatch or QuadPatch, defined by either 3 or 4 bezier edge splines. 3ds max uses bicubic (degree 3, with effectively 4 &#8220;control&#8221; points) patches. It does something fairly tricky when connecting Tri and Quad patches together, which is to internally promote Tri patches to quadric (degree 4) to get good continuity between patches.</p>
<p>How you interpolate your patch geometry is up to you &#8211; the process 3ds max uses is somewhat beyond the scope of this tutorial, but this is documented in the SDK helpfile.</p>
<p>For this tutorial, we&#8217;re done with basic geometry information. There are various other geometric things that could be exported &#8211; for example, we could export NURBs data, Shapes (splines and the like), or export primitive information for game engines that have built in basic primitive support.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Try writing the code to export out the PatchObject information, added in a separate method or to the body of ExportGeomObject (I did the latter). You&#8217;ll need to examine PatchObject, PatchMesh, and Patch classes in the SDK docs.
    <li>Examine and compare to exporter-geom.cpp
    <li>Finally, compile and build the plug-in, and try exporting some scenes in 3ds max with either mesh or patch objects. </li>
</ol>
</blockquote><!-- end of phase 1 ********************************************************************** -->
<hr>
</hr>
<h3>PHASE 2 : TEXTURES AND LIGHTING</h3>
<p>Source code for Phase 2: phase2.zip</a></p>
<h4>Textures</h4>
<p>First, we need to actually export the materials used in the 3ds max scene. This is part of our &#8220;header&#8221; or global information.</p>
<p>We iterate over the list of Material used in the 3ds max scene via the Interface::GetSceneMtls() API. For each mtl, for this tutorial, we just print out basic name information. If the mtl has subtexmaps, we print out one-level deep information on the legal subtexmaps. Also, for the purposes of an example, if the subtexmap happens to be a Bitmap Texmap, we print out the filename of the bitmap.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Update DoHeader by exporting information about the Scene Materials, using the guidelines above.
    <li>Compare to exporter-scenemtls.cpp </li>
</ol>
</blockquote>
<h4>Texture Vertices in Meshes</h4>
<p>For meshes, we first add to the section of code that exports mesh Face information, and append the face&#8217;s Material ID number to the list of face information. This is specifically for multi-materials. Note that the ID is usually set up in advance by the user. Note also that the MatID should be mod&#8217;d by the number of submats in a multi-mat.</p>
<p>We then need to get the texture vertices out of the mesh. Each mesh can support up to 99 different texture &#8220;channels&#8221;, each channel having a different UVW mapping. The mapping information is contained in the texture vertices. Note that typically, the default UVW mapping is contained in map channel #1. Map channel #0 is usually reserved for color-per-vertex info, and for this tutorial, we will not export this information. Channels 2-99 can be used for almost any other purpose, but we&#8217;ll treat them the same as channel 1 for this exporter.</p>
<p>Each Mesh face has a corresponding Texture Face. The Texture Faces contained in the Mesh have the corresponding three texture vertices that make up that &#8220;face&#8221;. Note that each texture face can have different associated texture vertices, so there is not a one-to-one mapping between mesh vertices and mesh texture vertices (thankfully).</p>
<h4>Texture Vertices in Patches</h4>
<p>For patches, getting texture vertex information is actually similar to what we did for meshes &#8211; the APIs of PatchMesh are slightly different, but pretty close.</p>
<p>Each Patch within a PatchMesh should have a corresponding TVPatch, which in turn contains 4 (and always 4) corresponding texture vertex indices. This is similar to a TVFace in the Mesh class.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>For this step, the example code is somewhat embedded in the routine, so it&#8217;s easier to just look at the relevant portions of updated code in ExportGeomObject in exporter.cpp in phase2. Pay attention to the three portions which are:
    <ul>
        <li>Exporting the basic node material name (and wire color, if no material was assigned)
        <li>Exporting the texture vertices information for the texture channels for patches
        <li>Exporting the texture vertices information for the texture channels for meshes </li>
    </ul>
    </li>
</ol>
</blockquote>
<h4>Lighting</h4>
<p>For most engines/export formats, lighting data is just as important as material information. As such, we add the ability to export basic light information in our exporter.</p>
<p>We first add information about the color of the ambient light in the scene in the exporter header. We simply pull the Ambient light color at the current frame using Interface::GetAmbient.</p>
<p>We add another helper method ExportLightObject and a check for LIGHT_CLASS_ID in our node enumerator. In ExportLightObject, we extract the GenLight and LightState information from the evaluated (via GenLight::EvalLightState) object. Note that for this sample, we ignore the fact that many aspects of the light could be animated.</p>
<p>For this tutorial, we export the light type, the intensity and color, the TM of the light, and the TM of the target (if the light happens to have a target, like a targeted spot or directional light), and some basic shadow information. There are various other things that can be exported, including the exclusion list of objects the light affects and ignores. For simplicity, we don&#8217;t export this info, but see GenLight and LightState for more details.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Try adding code to export the global ambient light as described above to DoHeader.
    <li>Try updating nodeEnum to call a separate newly added method ExportLightObject.
    <li>Try implementing ExportLightObject as described above.
    <li>Compare with exporter-lights.cpp </li>
</ol>
</blockquote><!-- end of phase 2 ********************************************************************** -->
<hr>
</hr>
<h3>PHASE 3: ANIMATION AND MODIFIERS</h3>
<p>Source code for Phase 3: phase3.zip</p>
<p>We&#8217;ve managed to export a lot of &#8220;static&#8221; information in our exporter, but it&#8217;s now worth taking a quick look at exporting some of the more dynamic information in a 3ds max scene, including keyframe animation information, pipeline modifier information, and things like IK information.</p>
<p>The first thing we do is introduce the concept of frames of animation by adding basic number-of-frames info to our export file header &#8211; start and end frame numbers (thereby also exporting the number of frames), and the frame rate in seconds. This information is easily accessible via the Interface pointer.</p>
<p>As mentioned previously, there&#8217;s a number of things related to lights that can be animated, that we won&#8217;t export for simplicity.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Update DoHeader and export the number of frames in the scene animation as described above. You&#8217;ll need to read about the TimeValue and Interval classes, and utilize Interface::GetAnimRange(), GetTicksPerFrame() and possibly GetFrameRate().
    <li>Compare with the changes made to DoHeader in exporter.cpp in phase 3 (made at the end of the routine). </li>
</ol>
</blockquote>
<h4>Accessing Modifiers</h4>
<p>There may be some instances where you may need to extract modifier information on a particular scene object. One popular example is exporting information from the 3ds max R4.x &#8220;Skin&#8221; modifier.</p>
<p>Keeping things simple, we just want to export the &#8220;Bend&#8221; modifier data if found. To access the modifiers (if any) for a given scene node, we need to work with the &#8220;unevaluated&#8221; pipeline. That is, we want to access the derived or base objects within the pipeline without looking at the &#8220;final&#8221; world state object.</p>
<p>This is relatively simple. Given a node, we can look at the existing ObjectRef via INode::GetObjectRef(). If this Object is a Derived Object (super class ID is GEN_DERIVOB_CLASS_ID), then there exist modifiers in the pipeline. We can cast the Object as an IDerivedObject and iterate over the modifiers associated with the derived object in the pipeline.</p>
<p>The one trick with this is being able to access the given Modifier derived class once it is found (via looking for a given modifier class ID). For this example, as the Bend modifier is part of the collection of default 3ds max modifiers, we cut-n-paste the class definition of BendMod from BEND.CPP, and tweak some of the inline definitions to compile in our project. Clearly, there are a lot of problems with this &#8211; if we were to use any of the actual BendMod methods, we would have to link with the modifier properly, and have some sort of shared header, etc. This is what a number of &#8220;public&#8221; modifiers do (e.g. Physique, Morpher Modifier, COMSkin). Definitely take a look at the &#8220;MorpherView&#8221; sample in the SDK that uses an exported Morpher modifier API.</p>
<p>The other thing to consider when working with modifiers is that they could potentially store node-specific data separately from the modifier instance. This is often due to a single modifier being instanced for multiple nodes (e.g. single bend modifier applied to multiple selected objects with use-pivots unchecked results in a single &#8220;bend&#8221; applied to the bounding box of the collection of objects). The ModContext stores the local OS TM, bounding box of the application of the modifier instance, and a LocalModData ptr, which points to a cache of modifier info that needs to be kept separate for each node.</p>
<p>Normally, to retrieve the ModContexts for nodes, you have to start with a given instance of the actual modifier (or &#8220;modapp&#8221;) from the derived object, and use it to iterate over the various node-associated ModContexts that it &#8220;owns&#8221;. Alternatively, you can use Interface::GetModContexts to get a list of ModContexts and associated nodes. In general, it&#8217;s often easier for the developer if the original developer of the modifier provides APIs that essentially wrap this functionality, rather than having a developer manually iterate over a modifiers&#8217; ModContexts.</p>
<p>For this sample, we just want the basic class definition, to access the given paramblock at the right object offset. We do this and extract the bend angle out of the BendMod pblock. The bend angle will not be node specific (a single bend applied to multiple nodes has a single bend angle)</p>
<p>We then iterate over the remaining modifiers (since it&#8217;s legal to have multiple Bend modifiers associated with one derived object) and any other derived objects in the pipeline.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>For this part first look at the added BendMod declaration in exporter.h in Phase 3. Again, this isn&#8217;t necessarily the preferred way of doing things, as noted above.
    <li>Look then at the code added to the end of ExportGeomObject. Look specifically at the portion that gets the ObjectRef, and looks for IDerivedObjects and gets the modifiers, if any. Skip the rest (related to the key animations) for the next section. </li>
</ol>
</blockquote>
<h4>Animated Parameters</h4>
<p>3ds max makes heavy use of animated parameters in parameter blocks to make things easier for animators. Game engines typically don&#8217;t need this information, but it&#8217;s possible that they might.</p>
<p>For this tutorial, we&#8217;ll get the keyframe values of the just-recently-added bend angle, if any exist. We assume that the pblock bend angle value is controlled by a controller that supports keyframes, and we also assume that only the three basic float keyframe controllers (linear, bezier, and TCB) are supported. Given this, we get the keycontroller interface, get the number of keys, loop over the keys and output the angle value and frame for the given key.</p>
<p>Note that for animated TM information, the best bet is to either get TMController information, if the controller is keyframed and you can imitate the interpolation in your engine, or iterate over the TM in each frame and output the TM. The ASCIIEXP exporter demonstrates an example of this.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Now examine the part of the updated ExportGeomObject that gets the keyframes out of the bend modifier angle value. Notice that the code assumes a controller is available for the angle param that is keyframeable. If this were not the case, we&#8217;d have to sample.
    <li>If you have the phase3 project set, you can try building it, and creating a scene in 3ds max with a cylinder or other primitive that has an animated bend applied, then exporting the object to look at the results. </li>
</ol>
</blockquote>
<h4>Bones and IK</h4>
<p>Often useful for game engines is exporting bone and IK information. Unfortunately, 3ds max default Bones and IK system is mostly closed and we can only export minimal information from it. In general, 3ds max bones are best used via additional means, such as the Skin modifier. See COMSkin for a partial example of exporting skin information.</p>
<p>Since it&#8217;s non trivial, and we&#8217;re trying to keep this tutorial simple, we&#8217;ll just discuss some possible ways for exporting bones and IK information.</p>
<p>Bones are linked via node hierarchy. There is always a single base node, that is controlled by a IKMasterController. All other bones in the hierarchy are controlled by IKSlaveControllers. During IK solving, the system calls various Control level methods to determine the results on the IK end effector. 3ds max IK controllers computer the results, but use core code to do this, so the solution process is somewhat hidden.</p>
<!-- end of phase 3 ********************************************************************** -->
<hr>
</hr>
<h3>PHASE 4: CUSTOM DATA</h3>
<p>Source code for Phase 4: phase4.zip</p>
<p>With most game engine situations, you&#8217;ll want to export additional non-3ds max custom node data to be interpreted only by your engine. This can include anything from &#8220;power-up&#8221; object properties, to special global illumination data, to anything in-between.</p>
<p>As it turns, there are several ways to apply custom data in 3ds max . These can be broken up as follows:</p>
<ol>
    <li>Per-node custom data
    <li>Per-mesh-vertex custom data
    <li>Texture-channel custom data </li>
</ol>
<h4>Per-node custom data -- AppData</h4>
<p>One of the most basic ways to associate any extra custom data with a given 3ds max node is via something called &#8220;AppData&#8221;. AppData is basically a chunk of data associated with any animatable (note that this can include things like controllers, modifiers and materials, along with typical scene nodes) that can be attached and retrieved from an animatable, and will automatically get saved and loaded from the MAX scene file.</p>
<p>AppData is always specified and designed in advance by the 3ds max plug-in developer for a specific purpose &#8211; AppData associated with animatables have ClassIDs identifying the plugin/object that originally created and attached the appdata.</p>
<p>For this tutorial, we add a simple ExportAppData method, and only call it when processing geomobjects (again, for simplicity). We use the appdata classID defined in the SDK &#8220;AppData&#8221; utility sample SDK\SAMPLES\UTILITY\APPDATA.CPP, and cast the resulting appdatachunk (if found) to a TCHAR and output it.</p>
<blockquote>
<ul>
    <li>One notable caveat: AppData does not get copied if a scene node is copied by the user (via shift-drag or the like). </li>
</ul>
</blockquote>
<h4>Per-node custom data &#8211; UserProps</h4>
<p>Another way to associate custom data with a 3ds max node is using &#8220;UserProps&#8221;. There are APIs off Inode that support associating string, integer, float, or boolean data with a scene node.</p>
<p>The properties are &#8220;named&#8221;, and for this tutorial, we&#8217;ll use names &#8220;UserBool&#8221;, &#8220;UserFloat&#8221;, &#8220;UserInt&#8221;, &#8220;UserString&#8221;. Create another utility method (ExportUserProps) and call it after calling ExportAppData in GeomObject processing.</p>
<blockquote>
<ul>
    <li>Caveat 2: UserProp data does copy when nodes are copied. </li>
</ul>
</blockquote>
<h4>Per-Vertex custom data</h4>
<p>3ds max provides a way to embed basic numeric (float) information with each vertex in a polygonal mesh. This results in a single value per mesh vertex, so a simple box would usually have 8 possible custom values.</p>
<p>In 3ds max, there are up to 99 vertex-data channels. Don&#8217;t confuse these with the 99 texture channels (admittedly, this is pretty easy to confuse), accessed via APIs off the Mesh class (vDataSupport and vertexFloat). For 3ds max, channel 0 is normally the soft-selection data channel, and channel 1 is normally the vertex weight channel.</p>
<h4>Per-Face custom data</h4>
<p>Beginning in 3ds max R4.0 a new capability to host user-defined data on a per-face basis was introduced.</p>
<p>This feature allows a Mesh object to support up to 99 custom data channels for Faces.&nbsp; Each channel provides an array to store data as defined by the developer. The types of data will often be standard items such as floats and ints, however, pointers to more sophisticated objects may be stored as well. </p>
<p>There are already existing samples in the MaxSDK that cover this great detail.&nbsp; Two of these samples are the PerFaceData modifier (maxsdk\samples\howto\perfacedata) and its exporter&nbsp;FaceDataExport ( maxsdk\samples\howto\perfacedata\facedataexport ).</p>
<p>For purposes of this tutorial, the MyExporter code implements the same functionality that is found in FaceDataExport.&nbsp; So, if you apply the PerFaceData modifier to a test object in your scene, MyExporter will find that applied per-face data and export it.</p>
<p>Much more detailed information can be found in the MaxSDK help documentation under the topics "What's New in the Max 4.0 SDK :&nbsp; Custom Face Data Storage", "Class IFaceDataMgr", and "Class IFaceDataChannel".</p>
<h4>Texture-channel custom data</h4>
<p>The texture channels we talked about when exporting node texture information can, in fact, be used for any floating-point data, not necessarily just UVW data.</p>
<p>The important different herein between texture channel data and per-vertex data is that each mesh (and patch) face has its own &#8220;set&#8221; of texture &#8220;vertices&#8217;. So using the simple box example given previously, a single custom texture channel can contain 24 separate custom values.</p>
<p>We&#8217;ve already exported the texture channel data, so we won&#8217;t code this again. An ADN white paper details various strategies and ways to use the extra texture channels for custom data.</p>
<blockquote>
<h4>Try it</h4>
<ol>
    <li>Examine the exporter.cpp in Phase 4. The AppData example in the added ExportAppData method makes the assumption that the appdata was added from a separate utility plugin, and uses the ClassID from this plugin to both find and determine the type of appdata present.
    <li>ExportUserProps looks for userprop data named UserBool, UserInt, UserFloat, UserString. As noted in the code, you can actually experiment with this by building the exporter, and in 3ds max , on a given scene object, right-clicking on it, going to the user-defined properties tab, and in the large editbox, typing in something like &#8220;UserInt=45&#8221;. Doing an export of this should result in the proper userprops data exported.
    <li>ExportPerVertData&nbsp;exports the various per-vertex data in a manner similar to the way we exported the texture channel data.&nbsp; </li>
</ol>
</blockquote><!-- end of phase 4 ********************************************************************** -->
<hr>
</hr>
<h3>OTHER STRATEGIES, FUTURE DIRECTIONS</h3>
<p>The exporter plug-in we&#8217;ve created is a somewhat simple example, but provides a pretty broad spectrum of the various parts of the 3ds max architecture.</p>
<p>However, in some circumstances, an exporter may not be enough. The general problem behind the typical use of an exporter with any 3D application is that there is information loss between the application and the eventual game or game engine that uses the exported data. Since information is effectively getting translated between formats, there is bound to be some information that either won&#8217;t be possible to replicate in one of the formats.</p>
<p>Additionally, the process is somewhat manual, and prone to errors. A level designer would prefer to use 3ds max as the level engine, but will have to periodically export the data, check it in the game, and tweak. This is the usual process, but in many ways, things are changing to make this more of a way of the past.</p>
<p>The future of 3ds max is one of separation of graphics algorithms from 3D &#8220;Design&#8221; UI and application &#8220;wrappings&#8221;. In other words, the basic graphics algorithms will become &#8220;portable&#8221;.&nbsp; 3ds max itself will become mainly an application wrapper around portable graphics &#8220;modules&#8221; that can be used in other applications, including games.
<p>Many aspects of 3ds max are already like this. Remember that 3ds max uses the plug-in SDK for a large percentage of the application. SDK and ADN sample code exposes the graphics algorithms used for certain modifiers, etc. that can be ported to a game engine or the like. These sort of things will continue in the future releases of 3ds max .
<p>Already, additional samples emphasize this &#8220;separation&#8221; concept. The &#8220;COMSkin&#8221; example demonstrates a way to provide an &#8220;external&#8221; COM DLL that provides the graphics algorithms (in this case tessellation algorithms), and both 3ds max and Game engine &#8220;wrappers&#8221; around the external module. In this way, the exact same algorithms can be used by designers in 3ds max and players in the game, and the actual visible output is the same.
<p>As game developers, bear in mind that it can work both ways. If you have a finally tuned piece of code in your current game engine that does a great job with real-time subdivision surfaces, and you want game level designers to be able to see and use the same process in 3ds max , consider exporting the code into a separate module, and writing a 3ds max modifier that wraps around this.
<p>The idea of separating base-level implementation from application-level wrappers is nothing new. However, it&#8217;s a very useful idea that can save significant time in the long run.</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/29995.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-14 16:35 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/14/29995.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数用const修饰算不算重载</title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/12/29845.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sun, 12 Aug 2007 13:14:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/12/29845.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/29845.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/12/29845.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/29845.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/29845.html</trackback:ping><description><![CDATA[<p>#include "stdafx.h"</p>
<p>class cls<br>{<br>public:<br>&nbsp;int front( int a) const<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;return 20;<br>&nbsp;&nbsp;}<br>&nbsp;int front(int a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;{<br>&nbsp;&nbsp;return 10;<br>&nbsp;}</p>
<p>protected:<br>private:<br>};</p>
<p><br>int _tmain(int argc, _TCHAR* argv[])<br>{<br>&nbsp;/*const */cls b;<br>&nbsp;b.front(1);<br>&nbsp;<br>&nbsp;return 0;<br>}<br><br>实例b没有const修饰时:<br>如果有front() const和front()函数&nbsp; 运行时进入front()<br>如果只有front()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行时进入front()<br>如果只有front() const&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行时进入front() const<br><br>实例b有const修饰时:<br>如果有front() const和front()函数&nbsp; 运行时进入front() const<br><br>小弟C++语法不熟悉 谁能解释下<br><br><br><br><br></p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/29845.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-12 21:14 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/12/29845.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC类中获得其它类指针 </title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/11/29805.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sat, 11 Aug 2007 14:26:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/11/29805.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/29805.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/11/29805.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/29805.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/29805.html</trackback:ping><description><![CDATA[MFC类中获得其它类指针 &nbsp; <br>&nbsp; 成都：苏颖锋 &nbsp; <br>&nbsp; (vcmfc输入并转贴) &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; 当用VC++的Application &nbsp; Wizard生成除了CDialog &nbsp; Basiced以外的应用程序时，将自动产生视图类、文档类、主帧窗口类、应用程序类等等。一般来说，程序的核心数据及操作在文档类中实现。跟界面有关的数据及操作在视图类中实现。当需要在某个类中使用不属于该类的数据时，必须要取得该数据所属类的指针。从视图类获得文档类的指针是很容易的，用GetDocument即可，这在一般的MFC文档中有介绍，也是编程中极为常用的的操作，比如视图类在进行重画等操作时，往往要用到文档类中的数据。然而只能从视图类获得文档类的指针是远远不够的，每个类都有获得其它各个类指针的一套方法，现归纳如下： &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; 为方便说明，现假设已用Application &nbsp; Wizard生成一个SDI应用程序Test，包含如一几个类：CTestApp,CTestDoc,CTestView,CMainFrm. &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 1.从视图类获得文档类的指针 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; 如前所述，在视图类中需要引用文档类的地方之前，使用以下语句： &nbsp; <br>&nbsp; &nbsp; CTextDoc &nbsp; *pDoc=(CTestDoc*)GetDocument(); &nbsp; <br>&nbsp; 以后便可使用pDoc指针访问文档类。 &nbsp; <br>&nbsp; 此处的强制类型转换在Test应用程序中并不必需，因为该程序中只有一个视图类，并且在Initstance()中用SDI文档模板进行了装配，你可以在Test.cpp中的Initstance()方法中看到以下语句： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CSingleDocTemplate &nbsp; *pDocTemplate; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pDocTemplate=new &nbsp; CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CTestDoc),RUNTIME_CLASS(CMainFrame), &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RUNTIME_CLASS(CTestView)); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AddDocTemplate(pDocTemplate); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以及TestView.h中的线上定义： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inline &nbsp; CTestDoc* &nbsp; CTestView::GetDocument() &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; return &nbsp; (CTestDoc*)m_pDocument;} &nbsp; <br>&nbsp; &nbsp; &nbsp; 简而言之，就是说CTestView的GetDocument()函数自然而然地认为CTestDoc是与它&#8220;相配&#8221;的，当生成了一个具有多个视图类的应用程序时（如用CSplitterWnd)将窗口分为两栏，但这两栏并非从同一种视图类派生就属于这种情况。具体实现在本文讨论范围之外），只有一个视图类能与唯一的文档类用文档模板进行装配，那么在另外一个未经装配的类中要取得文档类的指针，则需时行强制类型转换。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 2.从文档类取得视图类的指针 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CDocument类提供了两个函数用于视图类的定位：GetFirstViewPosition()和GetNextView(),具体语法如下： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; virtual &nbsp; POSITION &nbsp; GetFirstViewPosition() &nbsp; const; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; virtual &nbsp; CView* &nbsp; GetNextView(POSITION&amp; &nbsp; rPosition) &nbsp; const; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 注意：GetNextView()括号中的参数用的是引用方式，因此执行后值可能改变。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetFirstViewPosition()用于返回第一个视图位置（返回的并非视图类指针，而是一个POSITION类型值），GetNextView()有两个功能：返回下一个视图类的指针以及用引用调动的方式来改变传入的POSITION类型参数的值。很明显，在Test程序中，只有一个视图类，因此只需将这两个函数调用一次即可得到CTestView的指针如下（需定义一个POSITION结构变量来辅助操作）： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CTestView* &nbsp; pTestView; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; POSITION &nbsp; pos=GetFirstViewPosition(); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pTestView=GetNextView(pos); &nbsp; <br>&nbsp; 这样，便可到了CTestView类的指针pTestView.执行完成几句后，变量pos=NULL,因为没有下一个视图类，自然也没有下一个视图类的POSITION. &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 但是之几条语句太简单，不具有太强的通用性和安全特征；当象前面说的那样，当要在多个视图为中返回某个指定类的指针时，我们需要遍历所有视图类，直到找到指定类为止。判断一个类指针指向的是否某个类的实例时，可用IsKindOf()成员函数时行检查，如： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pView-&gt;IsKindOf(RUNTIME_CLASS(CTestView)); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 即可检查pView所指是否是CTestView类。 &nbsp; <br>&nbsp; 有了以上基础，我们已经可以从文档类取得任何类的指针。为了方便，我们将其作为一个文档类的成员函数，它有一个参数，表示要获得哪个类的指针。实现如下： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CView* &nbsp; CTestDoc::GetVieww(CRuntimeClass* &nbsp; pClass) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; CView* &nbsp; pView; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; POSITION &nbsp; pos=GetFirstViewPosition(); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(pos!=NULL) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pView=GetNextView(pos); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(pView-&gt;IsKindOf(pClass)) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(!pView-&gt;IsKindOf(pClass)) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &nbsp; &nbsp; NULL; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &nbsp; pView;} &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其中用了两次视图类的成员函数IsKindOf()来判断，是因为退出while循环有三种可能： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.pos为NULL，即已经不存在下一个视图类供操作； &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.pView已符合要求。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.1和2同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图的位置同时返回当前视图指针，因此pos是pView的下一个视图类的POSITION,完全有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一个视图类时就如引。因此需采用两次判断。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用该函数应遵循如下格式（以取得CTestView指针为例）： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CTestView* &nbsp; pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView)); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RUNTIME_CLASS是一个宏，可以简单地理解它的作用：将类的名字转化为CRuntimeClass为指针。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 至于强制类型转换也是为了安全特性考虑的，因为从同一个基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要，但能避免一些可能出现的麻烦。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 3.从一个视图类取得另一视图类的指针 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 综合1和2，很容易得出视图类之间互相获得指针的方法：就是用文档类作中转，先用1的方法得到文档类的指针，再用2的方法，以文档类的视图定位函数取得另一个视图类。同样，可以实现成一个函数： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （假设要从CTestAView中取得指向其它视图类的指针） &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CView* &nbsp; CTestAView::GetView(CRuntimeClass* &nbsp; pClass) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; CTestDoc* &nbsp; pDoc=(CTestDoc*)GetDocument(); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CView* &nbsp; pView; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; POSITION &nbsp; pos=pDoc-&gt;GetFirstViewPosition(); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(pos!=NULL) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pView=pDoc-&gt;GetNextView(pos); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(pView-&gt;IsKindOf(pClass)) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(!pView-&gt;IsKindOf(pClass)) &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &nbsp; &nbsp; NULL; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &nbsp; pView;} &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这个函数和2中的GetView()相比，一是多了第一句以取得文档类指针，二是在GetFirstViewPosition()和GetNextView()前加上了文档类指针，以表示它们是文档类成员函数。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有了此函数；当要从CTestAView中取得CTestBView的指针时，只需如下： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CTestBView* &nbsp; pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView)); &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 4. &nbsp; 从主帧窗口类获得视图类指针 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对本文所举的Test这各SDI程序来说，这是简单的，只需用CFrameWnd类的GetActiveView()成员函数即可。格式如下： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CFrameWnd::GetActiveView() &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 但将此函数应用在MDI应用的CMDIFrameWnd为中时，并不象所想的那样获得当前活动子窗口的视图类，而是返回NULL，这是一个要领性问题。在MDI程序中，CMDIFrameWnd没有和任何视图类发生关系，也就是说没有视图类直接属于它，只有子帧窗口类CMDIChildWnd才是所有子窗口视图类的父窗口。而子帧窗口的父窗口才是CFrameWnd。因此，在MDI程序中获得活动视图类的正确方法应为：先获得活动子帧窗口，再从活动子帧窗口中获得活动视图类： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //获得活动子帧窗口 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CMDIChildWnd* &nbsp; pChild=(CMDIChildWnd*)GetActiveFrame(); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //或：CMDIChildWnd* &nbsp; pChild=MDIGetActive(); &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //获得活动子帧窗口的活动视图 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CMyView* &nbsp; pView=(CMyView*)pChild-&gt;GetActiveView(); &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 5.从视图类中获得主帧窗口类指针： &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 用函数：CWnd::GetParentFrame()或AfxGetMainWnd(); &nbsp; <br>&nbsp; 可达到目的。GetParentFrame()的工作原理是在父窗口链中搜索，直到找到CFrameWnd或其派生类为止，并返回其指针。用法在InfoViewer中有详细介绍。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 6.在任何类中获得应用程序类 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用MFC全局函数AfxGetApp()可做到。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 7.从应用程序类中获得主帧窗口类 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CWinThread类有一个数据成员叫m_pMainWnd，由于CWinApp类由CWinThread派生而来，我们的应用程序为又由CWinApp派生而来，所以我们的CTestApp类也有一个m_pMainWnd成员，它所指南的即是CMainFrame类。（需进行合适的强制类型转换）。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 总结起来有几点注意： &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; A.在类A中获得类B的指针时，类A应包含类B的头文件。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; B.在很多时候要进行强制类型转换，并要注意括号的括法。 &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由于派生类和父类指针类型的兼容，使明确区分各个类变得十分重要。在拿不准的时候，最好加上强制类型转换。&nbsp;&nbsp; 
<img src ="http://www.cppblog.com/sunraiing9/aggbug/29805.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-11 22:26 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/11/29805.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GetProcAddress</title><link>http://www.cppblog.com/sunraiing9/archive/2007/08/08/29603.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 08 Aug 2007 15:00:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/08/08/29603.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/29603.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/08/08/29603.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/29603.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/29603.html</trackback:ping><description><![CDATA[Visual C++<br>GetProcAddress<br>显式链接到 DLL 的进程调用 <a onclick="javascript:Track('ctl00_LibFrame_ctl05|ctl00_LibFrame_ctl06',this);" href="http://msdn2.microsoft.com/zh-cn/library/ms683212(VS.80).aspx">GetProcAddress</a> 来获取 DLL 导出函数的地址。使用返回的函数指针调用 DLL 函数。<strong>GetProcAddress</strong> 将（由 <strong>LoadLibrary</strong>、<strong>AfxLoadLibrary</strong> 或 <strong>GetModuleHandle</strong> 返回的）DLL 模块句柄和要调用的函数名或函数的导出序号用作参数。<br><br>
<p>由于是通过指针调用 DLL 函数并且没有编译时类型检查，需确保函数的参数是正确的，以便不会超出在堆栈上分配的内存和不会导致访问冲突。帮助提供类型安全的一种方法是查看导出函数的函数原型，并创建函数指针的匹配 typedef。例如： </p>
<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">typedef&nbsp;UINT&nbsp;(</span><span style="COLOR: #0000ff">CALLBACK</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;LPFNDLLFUNC1)(DWORD</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">UINT);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>HINSTANCE&nbsp;hDLL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Handle&nbsp;to&nbsp;DLL</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">LPFNDLLFUNC1&nbsp;lpfnDllFunc1;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Function&nbsp;pointer</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">DWORD&nbsp;dwParam1;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>UINT&nbsp;&nbsp;uParam2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;uReturnVal;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>hDLL&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;LoadLibrary(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">MyDLL</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(hDLL&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;lpfnDllFunc1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(LPFNDLLFUNC1)GetProcAddress(hDLL</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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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 style="COLOR: #000000">"</span><span style="COLOR: #000000">DLLFunc1</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;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">lpfnDllFunc1)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;handle&nbsp;the&nbsp;error</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeLibrary(hDLL);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;SOME_ERROR_CODE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;call&nbsp;the&nbsp;function</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uReturnVal&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;lpfnDllFunc1(dwParam1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;uParam2);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}</span></div>
<br>
<p>调用 <strong>GetProcAddress</strong> 时指定所需函数的方式取决于 DLL 的生成方式。</p>
<p>仅当要链接到的 DLL 是用模块定义 (.def) 文件生成的，并且序号在 DLL 的 .def 文件的 <strong>EXPORTS</strong> 部分中与函数一起列出时，才能获取导出序号。如果 DLL 具有许多导出函数，则相对于使用函数名，使用导出序号调用 <strong>GetProcAddress</strong> 的速度稍快一些，因为导出序号是 DLL 导出表的索引。使用导出序号，<strong>GetProcAddress </strong>可直接定位函数，而不是将指定名称与 DLL 导出表中的函数名进行比较。但是，仅当有权控制 .def 文件中导出函数的序号分配时，才应使用导出序号调用 <strong>GetProcAddress</strong>。</p>
<h1 class=heading>&nbsp;</h1>
<br><!---->
<img src ="http://www.cppblog.com/sunraiing9/aggbug/29603.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-08-08 23:00 <a href="http://www.cppblog.com/sunraiing9/archive/2007/08/08/29603.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用字符串件的类型转换</title><link>http://www.cppblog.com/sunraiing9/archive/2007/07/17/28180.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 17 Jul 2007 03:55:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/07/17/28180.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/28180.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/07/17/28180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/28180.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/28180.html</trackback:ping><description><![CDATA[<div><span style="FONT-SIZE: 10.5pt">常用字符串件的类型转换。</span></div>
<div>&nbsp;</div>
<table style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">From</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">To</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><span style="FONT-SIZE: 10.5pt">Sample</span></div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">字符串常量</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ::SysAllocString(_T("Test string"));</span></div>
            <div><span style="FONT-SIZE: 10.5pt">&#8230;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString();</span></div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = _T("Test string"); //ERROR</span></div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">LPWSTR /</span></div>
            <div><span style="FONT-SIZE: 10.5pt">LPCWSTR /</span></div>
            <div><span style="FONT-SIZE: 10.5pt">WCHAR* / </span></div>
            <div><span style="FONT-SIZE: 10.5pt">wchar_t</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">LPCTSTR sz1 = _T("Test String");</span></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ::SysAllocString(sz1);</span></div>
            <div><span style="FONT-SIZE: 10.5pt">&#8230;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString();</span></div>
            <div>&nbsp;</div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">LPTSTR sz1 = _T("Test String");</span></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = sz1; //ERROR</span></div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">LPCWSTR /</span></div>
            <div><span style="FONT-SIZE: 10.5pt">const WCHAR * /</span></div>
            <div><span style="FONT-SIZE: 10.5pt">const wchar_t *</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ...; //</span></div>
            <div><span style="FONT-SIZE: 10.5pt">...</span></div>
            <div><span style="FONT-SIZE: 10.5pt">LPCTSTR sz = static_cast&lt;LPCTSTR&gt;bs;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">...</span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString(bs); </span></div>
            <div><span style="FONT-SIZE: 10.5pt">//Never use sz after this line</span></div>
            <div>&nbsp;</div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ...; //</span></div>
            <div><span style="FONT-SIZE: 10.5pt">...</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">LPCTSTR sz = bs;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">...</span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString(bs); </span></div>
            <div><span style="FONT-SIZE: 10.5pt">//Never use sz after this line</span></div>
            <div><span style="FONT-SIZE: 10.5pt">_tcslen(sz); //ERROR</span></div>
            <div>&nbsp;</div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">LPWSTR /</span></div>
            <div><span style="FONT-SIZE: 10.5pt">WCHAR* /</span></div>
            <div><span style="FONT-SIZE: 10.5pt">wchar_t*</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ...; //</span></div>
            <div><span style="FONT-SIZE: 10.5pt">//...</span></div>
            <div><span style="FONT-SIZE: 10.5pt">UINT len = ::SysStringLen(bs);</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">// Do not modify the BSTR content by </span></div>
            <div><span style="FONT-SIZE: 10.5pt">// C/C++ string functions</span></div>
            <div><span style="FONT-SIZE: 10.5pt">LPTSTR sz = new TCHAR[len+1];</span></div>
            <div><span style="FONT-SIZE: 10.5pt">_tcsncpy(sz, bs, len); </span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString(bs);</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">delete []sz;</span></div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ...; //</span></div>
            <div><span style="FONT-SIZE: 10.5pt">//...</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">// Do not modify the BSTR content by </span></div>
            <div><span style="FONT-SIZE: 10.5pt">// C/C++ string functions</span></div>
            <div><span style="FONT-SIZE: 10.5pt">LPTSTR sz = bs; //Error</span></div>
            <div>&nbsp;</div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">CString</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">CString str1 = ...;</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = str1.AllocSysString();</span></div>
            <div><span style="FONT-SIZE: 10.5pt">SomeMethod(bs); </span></div>
            <div><span style="FONT-SIZE: 10.5pt">// void SomeMethod([in]BSTR)</span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString(bs);</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">CComBSTR bs1(static_cast&lt;LPCTSTR&gt;(str1)); </span></div>
            <div><span style="FONT-SIZE: 10.5pt">SomeMethod(static_cast&lt;BSTR&gt; (bs1) );</span></div>
            <div><span style="FONT-SIZE: 10.5pt">&nbsp;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">// void SomeMethod([in] BSTR )</span></div>
            <div><span style="FONT-SIZE: 10.5pt">_bstr_t bs2( static_cast&lt;LPCTSTR&gt;(str1));</span></div>
            <div><span style="FONT-SIZE: 10.5pt">SomeMethod(static_cast&lt;BSTR&gt; (bs2) ); </span></div>
            <div>&nbsp;</div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">CString str1 = ...;</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">SomeMethod(str1.AllocSysString()); </span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">// No one will releasee the return BSTR of </span></div>
            <div><span style="FONT-SIZE: 10.5pt">// str1.AllocSysString()</span></div>
            <div>&nbsp;</div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">BSTR </span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">CString</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = SysAllocString(_T(&#8220;Test&#8221;));</span></div>
            <div><span style="FONT-SIZE: 10.5pt">CString str1(bs);</span></div>
            <div><span style="FONT-SIZE: 10.5pt">CString str2;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">Str2 = bs;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">SysFreeString(bs); // Never forget this line</span></div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">char* / LPSTR / LPCSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div><em><span style="FONT-SIZE: 10.5pt">Solution 1</span></em><em><span style="FONT-SIZE: 10.5pt">：</span></em></div>
            <div><span style="FONT-SIZE: 10.5pt">char str[MAX_STR_LEN] = "ANSI string";</span></div>
            <div><span style="FONT-SIZE: 10.5pt">WCHAR wstr[MAX_WSTR_LEN];</span></div>
            <div><span style="FONT-SIZE: 10.5pt">// Convert ANSI to Unicode</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">MultiByteToWideChar( CP_ACP, 0, str,</span></div>
            <div><span style="FONT-SIZE: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strlen(str)+1, wstr,&nbsp;&nbsp; </span></div>
            <div><span style="FONT-SIZE: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp; sizeof(wstr)/sizeof(wstr[0]) );</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs1 = ::SysAllocString(wstr);</span></div>
            <div>&nbsp;</div>
            <div><span style="FONT-SIZE: 10.5pt">CString cs = str;</span></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs2 = cs.</span><span style="FONT-SIZE: 10pt">AllocSysString()</span></div>
            <div>&nbsp;</div>
            <div><em><span style="FONT-SIZE: 10.5pt">Solution 2</span></em><em><span style="FONT-SIZE: 10.5pt">：</span></em></div>
            <div><span style="FONT-SIZE: 10.5pt">char str[MAX_STR_LEN] = "ANSI string";</span></div>
            <div><span style="FONT-SIZE: 10.5pt">_bstr_t bs1(str);</span></div>
            <div><span style="FONT-SIZE: 10.5pt">CComBSTR bs2(str);</span></div>
            <div>&nbsp;</div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">char *str = "ANSI string";</span></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bstr1 = SysAllocString( </span></div>
            <div><span style="FONT-SIZE: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (const OLECHAR*) str);</span></div>
            </td>
        </tr>
        <tr>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 77.4pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=103>
            <div><span style="FONT-SIZE: 10.5pt">BSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 81pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=108>
            <div><span style="FONT-SIZE: 10.5pt">char* / LPSTR / LPCSTR</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: #ece9d8; PADDING-BOTTOM: 0cm; WIDTH: 297pt; BORDER-TOP-COLOR: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=396>
            <div><strong><span style="FONT-SIZE: 10.5pt">Right:</span></strong></div>
            <div><em><span style="FONT-SIZE: 10.5pt">Solution 1</span></em><em><span style="FONT-SIZE: 10.5pt">：</span></em></div>
            <div><span style="FONT-SIZE: 10.5pt">char str[MAX_STR_LEN];</span></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ::SysAllocString(L"Test");</span></div>
            <div><span style="FONT-SIZE: 10.5pt">// Convert ANSI to Unicode</span></div>
            <div><span style="FONT-SIZE: 10.5pt">WideCharToMultiByte( CP_ACP, 0, </span></div>
            <div><span style="FONT-SIZE: 10.5pt">&nbsp;&nbsp; (LPCWSTR)bs, -1,</span></div>
            <div><span style="FONT-SIZE: 10.5pt">&nbsp;&nbsp; str, MAX_STR_LEN, NULL, NULL );</span></div>
            <div><span style="FONT-SIZE: 10.5pt">::SysFreeString(bs);</span></div>
            <div>&nbsp;</div>
            <div><em><span style="FONT-SIZE: 10.5pt">Solution 2</span></em><em><span style="FONT-SIZE: 10.5pt">：</span></em></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bs = ::SysAllocString(L"Test");</span></div>
            <div><span style="FONT-SIZE: 10.5pt">_bstr_t bs1(bs, false);</span></div>
            <div><span style="FONT-SIZE: 10.5pt">const char* str = static_cast &lt;const char*&gt; bs1;</span></div>
            <div>&nbsp;</div>
            <div><strong><span style="FONT-SIZE: 10.5pt">Wrong:</span></strong></div>
            <div><span style="FONT-SIZE: 10.5pt">BSTR bstr1 = SysAllocString(L&#8221;ANSI string");</span></div>
            <div><span style="FONT-SIZE: 10.5pt">char *str = (char*) bstr1;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
            </td>
        </tr>
    </tbody>
</table>
<div>&nbsp;</div>
<div><span style="FONT-SIZE: 10.5pt">IMPORTANT: </span><span style="FONT-SIZE: 10.5pt">上面所有的例子都是按照</span><span style="FONT-SIZE: 10.5pt">UNICODE</span><span style="FONT-SIZE: 10.5pt">应用程序设计的。并且不考虑</span><span style="FONT-SIZE: 10.5pt">BSTR</span><span style="FONT-SIZE: 10.5pt">中包含多个字串的情况，也就是</span><span style="FONT-SIZE: 10.5pt">BSTR</span><span style="FONT-SIZE: 10.5pt">只在结束的位置有一个</span><span style="FONT-SIZE: 10.5pt">0</span><span style="FONT-SIZE: 10.5pt">结束符。对于</span><span style="FONT-SIZE: 10.5pt">MBCS/ANSI</span><span style="FONT-SIZE: 10.5pt">程序，可以参考上面的例子。主要区别是对于现在的</span><span style="FONT-SIZE: 10.5pt">COM</span><span style="FONT-SIZE: 10.5pt">版本</span><span style="FONT-SIZE: 10.5pt">OLECHAR</span><span style="FONT-SIZE: 10.5pt">是</span><span style="FONT-SIZE: 10.5pt">wchar_t</span><span style="FONT-SIZE: 10.5pt">，但是</span><span style="FONT-SIZE: 10.5pt">TCHAR&nbsp;</span><span style="FONT-SIZE: 10.5pt">对于</span><span style="FONT-SIZE: 10.5pt">UNICODE</span><span style="FONT-SIZE: 10.5pt">程序才是</span><span style="FONT-SIZE: 10.5pt">wchar_t</span><span style="FONT-SIZE: 10.5pt">。</span></div>
&nbsp;
<img src ="http://www.cppblog.com/sunraiing9/aggbug/28180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-07-17 11:55 <a href="http://www.cppblog.com/sunraiing9/archive/2007/07/17/28180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The PIMPL idiom</title><link>http://www.cppblog.com/sunraiing9/archive/2007/07/16/28124.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Mon, 16 Jul 2007 06:51:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/07/16/28124.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/28124.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/07/16/28124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/28124.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/28124.html</trackback:ping><description><![CDATA[<div class=sect1 lang=en>
<div class=titlepage>The PIMPL idiom</div>
<p>In C++ when anything in a header file changes, all code that includes the header (either directly or indirectly) must be recompiled. To minimalize this we use PIMPL idiom: </p>
<pre class=programlisting>// file x.h
class X
{
public:
// public members
protected:
// protected members
private:
// pointer to forward declared class
class XImpl *pimpl_;  // opaque pointer
};
</pre>
<p><span class=bold><strong>Questions:</strong></span> -- What should go into XImpl? Options are: </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>Put all private data but not functions into XImpl.: Not too bad, but there is better </p>
    <li>
    <p>Put all private members into XImpl.</p>
    <li>
    <p>Put all private and protected members into XImpl. Bad, protected members must be in X </p>
    <li>
    <p>Make XImpl entirely the class that X would have been, and write X as only the public interface made up entirely of simple forwarding functions (handle/body variant). </p>
    </li>
</ul>
</div>
<p>-- Does XImpl require a pointer back to the X object? </p>
<p><span class=bold><strong>Caveats:</strong></span> </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>You can't hide virtual member functions in the Pimpl (here private inheritance differs from membership) </p>
    <li>
    <p>Functions in Pimpl may require a "back pointer" to the visible object (by convention that is called: <span class=bold><strong>self_</strong></span>. </p>
    <li>
    <p>Often the best compromise is to use Option 2, and in addition to put into XImpl only rhose non-private functions that need to be called by private ones. </p>
    <li>
    <p>4th is better over 2nd not needed "back pointer", but X is useless for inheritance. </p>
    </li>
</ul>
</div>
<p>PIPML has some drawbacks, like allocating/deallocating objects in the heap, which could be slow. </p>
<p>What about this "optimalization"? </p>
<pre class=programlisting>// file: y.h
class Y
{
//...
static const size_t sizeofx = /* ... */;
char x_[sizeofx];
};
// file: y.cpp
#include "x.h"
Y::Y()
{
assert( sizeofx &gt;= sizeof(X) );
new(&amp;x_[0]) X;
}
Y::~Y()
{
(reinterpret_cast&lt;X*&gt;(&amp;x_[0]))-&gt;~X();
}
</pre>
<p><span class=bold><strong>Questions:</strong></span> </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>What is the Pimpl space overhead?</p>
    <li>
    <p>What is the performance overhead?</p>
    </li>
</ul>
</div>
<p>Space overhead: </p>
<pre class=programlisting>#include &lt;iostream&gt;
using namespace std;
struct X {
char c;
struct XImpl *pimpl_;
};
struct XImpl { char c; };
int main()
{
cout &lt;&lt; sizeof(XImpl) &lt;&lt; '\t' &lt;&lt; sizeof(X) &lt;&lt; endl;
return 0;
}
// result: 1    8
</pre>
<p>Runtime overhead: </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>allocation/deallocation cost: relativelly expensive</p>
    <li>
    <p>indirect access of private members (+ back pointer)</p>
    <li>
    <p>alignment problems: new guaranties, that object will align properly, <span class=bold><strong>char[]</strong></span> buffers doesn't! </p>
    <li>
    <p>X must not use the default assignment<span class=bold><strong>operator=() </strong></span></p>
    <li>
    <p>If <span class=bold><strong>sizeof(XImpl)</strong></span> grows greater then <span class=bold><strong>sizeofx</strong></span>, we need to update the source. </p>
    </li>
</ul>
</div>
<pre class=programlisting>// file x.h
class X
{
//...
struct XImpl *pimpl_;
};
// file x.cpp
#include "x.h"
struct XImpl
{
// private stuff here ...
static void *operator new(size_t)   { /*...*/ }
static void *operator delete(void*) { /*...*/ }
};
X::X() : pimpl_( new XImpl ) { }
X::~X() { delete pimpl_; pimpl_ = 0; }
</pre>
</div>
<div class=navfooter>
<hr>
</div>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/28124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-07-16 14:51 <a href="http://www.cppblog.com/sunraiing9/archive/2007/07/16/28124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL参考</title><link>http://www.cppblog.com/sunraiing9/archive/2007/05/27/24910.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sat, 26 May 2007 16:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/05/27/24910.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/24910.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/05/27/24910.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/24910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/24910.html</trackback:ping><description><![CDATA[<h2>&nbsp;</h2>
<div class=postbody>
<p>&nbsp;SQL参考</p>
<p>一、资料定义 ｄｄｌ（data definition language)<br>资料定语言是指对资料的格式和形态下定义的语言，他是每个资料库要建立时候时首先<br>要面对的，举凡资料分哪些表格关系、表格内的有什麽栏位主键、表格和表格之间互相<br>参考的关系等等，都是在开始的时候所必须规划好的。</p>
<p>１、建表格：<br>create table table_name(<br>column1 datatype [not null] [not null primary key],<br>column2 datatype [not null],<br>...）<br>说明：　<br>datatype --是资料的格式，详见表。<br>nut null --可不可以允许资料有空的（尚未有资料填入）。<br>primary key --是本表的主键。</p>
<p>２、更改表格　<br>alter table table_name<br>add column column_name datatype<br>说明：增加一个栏位（没有删除某个栏位的语法。<br>alter table table_name<br>add primary key (column_name)<br>说明：更改表得的定义把某个栏位设为主键。<br>alter table table_name<br>drop primary key (column_name)<br>说明：把主键的定义删除。</p>
<p>３、建立索引　<br>create index index_name on table_name (column_name)<br>说明：对某个表格的栏位建立索引以增加查询时的速度。</p>
<p>４、删除　<br>drop table_name<br>drop index_name</p>
<p>二、的资料形态 datatypes<br>smallint<br>16 位元的整数。<br>interger<br>32 位元的整数。<br>decimal(p,s)<br>p 精确值和 s 大小的十进位整数，精确值p是指全部有几个数(digits)大小值，s是指小<br>数<br>点後有几位数。如果没有特别指定，则系统会设为 p=5; s=0 。<br>float<br>32位元的实数。<br>double<br>64位元的实数。<br>char(n)<br>n 长度的字串，n不能超过 254。<br>varchar(n)<br>长度不固定且其最大长度为 n 的字串，n不能超过 4000。<br>graphic(n)<br>和 char(n) 一样，不过其单位是两个字元 double-bytes， n不能超过127。这个形态是<br>为<br>了支援两个字元长度的字体，例如中文字。<br>vargraphic(n)<br>可变长度且其最大长度为 n 的双字元字串，n不能超过 2000。<br>date<br>包含了 年份、月份、日期。<br>time<br>包含了 小时、分钟、秒。<br>timestamp<br>包含了 年、月、日、时、分、秒、千分之一秒。</p>
<p>三、资料操作 ｄｍｌ （data manipulation language)<br>资料定义好之後接下来的就是资料的操作。资料的操作不外乎增加资料（insert)、查询<br>资料（query）、更改资料（update) 、删除资料（delete）四种模式，以下分 别介绍<br>他们的语法：</p>
<p>１、增加资料：<br>insert into table_name (column1,column2,...)<br>values ( value1,value2, ...)<br>说明：<br>1.若没有指定column 系统则会按表格内的栏位顺序填入资料。<br>2.栏位的资料形态和所填入的资料必须吻合。<br>3.table_name 也可以是景观 view_name。</p>
<p>insert into table_name (column1,column2,...)<br>select columnx,columny,... from another_table<br>说明：也可以经过一个子查询（subquery）把别的表格的资料填入。</p>
<p>２、查询资料：<br>基本查询<br>select column1,columns2,...<br>from table_name<br>说明：把table_name 的特定栏位资料全部列出来<br>select *<br>from table_name<br>where column1 = xxx<br>[and column2 &gt; yyy] [or column3 &lt;&gt; zzz]<br>说明：<br>1.'*'表示全部的栏位都列出来。<br>2.where 之後是接条件式，把符合条件的资料列出来。</p>
<p>select column1,column2<br>from table_name<br>order by column2 [desc]<br>说明：order by 是指定以某个栏位做排序，[desc]是指从大到小排列，若没有指明，则<br>是从小到大<br>排列</p>
<p>组合查询<br>组合查询是指所查询得资料来源并不只有单一的表格，而是联合一个以上的<br>表格才能够得到结果的。<br>select *<br>from table1,table2<br>where table1.colum1=table2.column1<br>说明：<br>1.查询两个表格中其中 column1 值相同的资料。<br>2.当然两个表格相互比较的栏位，其资料形态必须相同。<br>3.一个复杂的查询其动用到的表格可能会很多个。</p>
<p>整合性的查询：<br>select count (*)<br>from table_name<br>where column_name = xxx<br>说明：<br>查询符合条件的资料共有几笔。<br>select sum(column1)<br>from table_name<br>说明：<br>1.计算出总和，所选的栏位必须是可数的数字形态。<br>2.除此以外还有 avg() 是计算平均、max()、min()计算最大最小值的整合性查询。<br>select column1,avg(column2)<br>from table_name<br>group by column1<br>having avg(column2) &gt; xxx<br>说明：<br>1.group by: 以column1 为一组计算 column2 的平均值必须和 avg、sum等整合性查询<br>的关键字<br>一起使用。<br>2.having : 必须和 group by 一起使用作为整合性的限制。</p>
<p>复合性的查询<br>select *<br>from table_name1<br>where exists (<br>select *<br>from table_name2<br>where conditions )<br>说明：<br>1.where 的 conditions 可以是另外一个的 query。<br>2.exists 在此是指存在与否。<br>select *<br>from table_name1<br>where column1 in (<br>select column1<br>from table_name2<br>where conditions )<br>说明：　<br>1. in 後面接的是一个集合，表示column1 存在集合里面。<br>2. select 出来的资料形态必须符合 column1。</p>
<p>其他查询<br>select *<br>from table_name1<br>where column1 like 'x%'<br>说明：like 必须和後面的'x%' 相呼应表示以 x为开头的字串。<br>select *<br>from table_name1<br>where column1 in ('xxx','yyy',..)<br>说明：in 後面接的是一个集合，表示column1 存在集合里面。<br>select *<br>from table_name1<br>where column1 between xx and yy<br>说明：between 表示 column1 的值介於 xx 和 yy 之间。</p>
<p>３、更改资料：<br>update table_name<br>set column1='xxx'<br>where conditoins<br>说明：<br>1.更改某个栏位设定其值为'xxx'。<br>2.conditions 是所要符合的条件、若没有 where 则整个 table 的那个栏位都会全部被<br>更改。</p>
<p>４、删除资料：<br>delete from table_name<br>where conditions<br>说明：删除符合条件的资料。</p>
<p>说明：关于where条件后面如果包含有日期的比较，不同数据库有不同的表达式。具体如<br>下：<br>(1)如果是access数据库，则为：where mydate&gt;#2000-01-01#<br>(2)如果是oracle数据库，则为：where mydate&gt;cast('2000-01-01' as date)<br>或：where mydate&gt;to_date('2000-01-01','yyyy-mm-dd')<br>在delphi中写成：<br>thedate='2000-01-01';<br>query1.sql.add('select * from abc where mydate&gt;cast('+''''+thedate+''''+' as<br>date)');</p>
<p>如果比较日期时间型，则为：<br>where mydatetime&gt;to_date('2000-01-01 10:00:01','yyyy-mm-dd hh24:mi:ss')</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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></p>
</div>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/24910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-05-27 00:23 <a href="http://www.cppblog.com/sunraiing9/archive/2007/05/27/24910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>宽度优先搜索</title><link>http://www.cppblog.com/sunraiing9/archive/2007/04/13/21800.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Fri, 13 Apr 2007 08:20:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/04/13/21800.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/21800.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/04/13/21800.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/21800.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/21800.html</trackback:ping><description><![CDATA[宽度优先搜索 BFS<br><br>宽度优先搜索算法（又称广度优先搜索）是最简便的图的搜索算法之一，这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。<br><br>已知图G=(V,E)和一个源顶点s，宽度优先搜索以一种系统的方式探寻G的边，从而&#8220;发现&#8221;s所能到达的所有顶点，并计算s到所有这些顶点的距离(最少边数)，该算法同时能生成一棵根为s且包括所有可达顶点的宽度优先树。对从s可达的任意顶点v，宽度优先树中从s到v的路径对应于图G中从s到v的最短路径，即包含最小边数的路径。该算法对有向图和无向图同样适用。<br><br>之所以称之为宽度优先算法，是因为算法自始至终一直通过已找到和末找到顶点之间的边界向外扩展，就是说，算法首先搜索和s距离为k的所有顶点，然后再去搜索和S距离为k+l的其他顶点。<br><br>为了保持搜索的轨迹，宽度优先搜索为每个顶点着色：白色、灰色或黑色。算法开始前所有顶点都是白色，随着搜索的进行，各顶点会逐渐变成灰色，然后成为黑色。在搜索中第一次碰到一顶点时，我们说该顶点被发现，此时该顶点变为非白色顶点。因此，灰色和黑色顶点都已被发现，但是，宽度优先搜索算法对它们加以区分以保证搜索以宽度优先的方式执行。若(u,v)&#8712;E且顶点u为黑色，那么顶点v要么是灰色，要么是黑色，就是说，所有和黑色顶点邻接的顶点都已被发现。灰色顶点可以与一些白色顶点相邻接，它们代表着已找到和未找到顶点之间的边界。<br><br>在宽度优先搜索过程中建立了一棵宽度优先树，起始时只包含根节点，即源顶点s.在扫描已发现顶点u的邻接表的过程中每发现一个白色顶点v，该顶点v及边(u,v)就被添加到树中。在宽度优先树中，我们称结点u 是结点v的先辈或父母结点。因为一个结点至多只能被发现一次，因此它最多只能有--个父母结点。相对根结点来说祖先和后裔关系的定义和通常一样：如果u处于树中从根s到结点v的路径中，那么u称为v的祖先，v是u的后裔。<br><br>下面的宽度优先搜索过程BFS假定输入图G=(V,E)采用邻接表表示，对于图中的每个顶点还采用了几种附加的数据结构，对每个顶点u&#8712;V，其色彩存储于变量color[u]中，结点u的父母存于变量&#960;[u]中。如果u没有父母(例如u=s或u还没有被检索到)，则 &#960;[u]=NIL，由算法算出的源点s和顶点u之间的距离存于变量d[u]中，算法中使用了一个先进先出队列Q来存放灰色节点集合。其中head[Q]表示队列Q的队头元素，Enqueue(Q,v)表示将元素v入队， Dequeue(Q)表示对头元素出队；Adj[u]表示图中和u相邻的节点集合。<br><br>procedure BFS(G,S);<br><br>begin<br><br>1.&nbsp; &nbsp;for 每个节点u&#8712;V[G]- do<br><br>begin<br><br>2.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;color[u]&#8592;White;<br><br>3.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;d[u]&#8592;&#8734;;<br><br>4.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&#960;[u]&#8592;NIL;<br><br>end;<br><br>5.&nbsp; &nbsp;color[s]&#8592;Gray;<br><br>6.&nbsp; &nbsp;d[s]&#8592;0;<br><br>7.&nbsp; &nbsp;&#960;[s]&#8592;NIL;<br><br>8.&nbsp; &nbsp;Q&#8592;<br><br>9.&nbsp; &nbsp;while Q&#8800;&#966; do<br><br>begin<br><br>10.&nbsp; &nbsp;&nbsp; &nbsp;u&#8592;head[Q];<br><br>11.&nbsp; &nbsp;&nbsp; &nbsp;for 每个节点v&#8712;Adj[u] do<br><br>12.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;if color[v]=White then<br><br>begin<br><br>13.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; color[v]&#8592;Gray;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br><br>14.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; d[v]&#8592;d[v]+1;<br><br>15.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &#960;[v]&#8592;u;<br><br>16.&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Enqueue(Q,v);<br><br>end;&nbsp; &nbsp;<br><br>17.&nbsp; &nbsp;&nbsp; &nbsp;Dequeue(Q);<br><br>18.&nbsp; &nbsp;&nbsp; &nbsp;color[u]&#8592;Black;<br><br>end;<br><br>end; <br><br>图1展示了用BFS在例图上的搜索过程。黑色边是由BFS产生的树枝。每个节点u内的值为d[u]，图中所示的队列Q是第9-18行while循环中每次迭代起始时的队列。队列中每个结点下面是该结点与源结点的距离。<br><br>图1 BFS在一个无向图上的执行过程<br><br>过程BFS按如下方式执行，第1-4行置每个结点为白色，置d[u]为无穷大，每个结点的父母置为NIL，第5行置源结点S为灰色，即意味着过程开始时源结点已被发现。第6行初始化d[s]为0，第7行置源结点的父母结点为NIL，第8行初始化队列0，使其仅含源结点s，以后Q队列中仅包含灰色结点的集合。<br><br>程序的主循环在9-18行中，只要队列Q中还有灰色结点，即那些已被发现但还没有完全搜索其邻接表的结点，循环将一直进行下去。第10行确定队列头的灰色结点为u。第11-16行的循环考察u的邻接表中的每一个顶点v。如果v是白色结点，那么该结点还没有被发现过，算法通过执行第13-16行发现该结点。首先它被置为灰色，距离d[v]置为d[u]+1，而后u被记为该节点的父母，最后它被放在队列Q的队尾。当结点u的邻接表中的所有结点都被检索后，第17 -18行使u弹出队列并置成黑色。<br><br>分析<br><br>在证明宽度优先搜索的各种性质之前，我们先做一些相对简单的工作 ——分析算法在图G=(V,E)之上的运行时间。在初始化后，再没有任何结点又被置为白色。因此第12行的测试保证每个结点至多只能迸人队列一次，因而至多只能弹出队列一次。入队和出队操作需要O(1)的时间，因此队列操作所占用的全部时间为O(V)，因为只有当每个顶点将被弹出队列时才会查找其邻接表，因此每个顶点的邻接表至多被扫描一次。因为所有邻接表的长度和为Q(E)，所以扫描所有邻接表所花费时间至多为O(E)。初始化操作的开销为O(V)，因此过程BFS的全部运行时间为O(V+E)，由此可见，宽度优先搜索的运行时间是图的邻接表大小的一个线性函数。
<img src ="http://www.cppblog.com/sunraiing9/aggbug/21800.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-04-13 16:20 <a href="http://www.cppblog.com/sunraiing9/archive/2007/04/13/21800.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式</title><link>http://www.cppblog.com/sunraiing9/archive/2007/04/10/21574.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 10 Apr 2007 01:59:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/04/10/21574.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/21574.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/04/10/21574.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/21574.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/21574.html</trackback:ping><description><![CDATA[<p>最近看编译原理，找了些正则表达式的资料,先贴上来，晚上看过了做个总结<a title=正则表达式入门 href="http://www.cppblog.com/Files/sunraiing9/正则表达式入门.rar"><br><br><span style="COLOR: #ff0000">正则表达式入门.rar</span></a>（.swf）<br><font style="COLOR: red" color=#002c99><a href="http://www.ultrapico.com/ExpressoBetaSetup.msi"><font style="COLOR: red" color=#002c99>ExpressoBetaSetup.msi</font></a></font><br><br><br></p>
<center>
<h1>正则表达式之道</h1>
</center>
<center>
<p>原著：Steve Mansour <br>sman@scruznet.com <br><font size=-1>Revised: June 5, 1999<br>(copied by jm /at/ jmason.org from http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! ) </font></p>
<p>翻译：Neo Lee<br>neo.lee@gmail.com<br><font size=-1>2004年10月16日</font></p>
</center>
<hr>
<p><a href="http://sitescooper.org/tao_regexps.html"><u><font color=#0000ff>英文版原文</font></u></a></p>
<p>译者按：原文因为年代久远，文中很多链接早已过期（主要是关于vi、sed等工具的介绍和手册），本译文中已将此类链接删除，如需检查这些链接可以查看上面链接的原文。除此之外基本照原文直译，括号中有&#8220;译者按&#8221;的部分是译者补充的说明。
<hr>
<p>&nbsp;</p>
<h1>目 录</h1>
<p><strong><a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#WhatAreRegularExpressions"><u><font color=#800080>什么是正则表达式</font></u></a></strong> <br><strong><a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#SimpleCommands"><u><font color=#800080>范例</font></u></a></strong> <br>&nbsp;&nbsp; <a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#SimpleCommands"><u><font color=#800080>简单</font></u></a> <br>&nbsp;&nbsp; <a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#MediumDifficultyExamples"><u><font color=#800080>中级（神奇的咒语）</font></u></a> <br>&nbsp;&nbsp; <a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#HardExamples"><font color=#800080><u>困难（不可思议的象形文字）</u></font></a><br><strong><a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#Regular_Expressions_In_Various_Tools"><u><font color=#800080>不同工具中的正则表达式</font></u></a></strong> </p>
<p>&nbsp;</p>
<hr width="100%">
<h1><a name=WhatAreRegularExpressions></a>什么是正则表达式</h1>
<p>一个正则表达式，就是用某种模式去匹配一类字符串的一个公式。很多人因为它们看上去比较古怪而且复杂所以不敢去使用——很不幸，这篇文章也不能够改变这一点，不过，经过一点点练习之后我就开始觉得这些复杂的表达式其实写起来还是相当简单的，而且，一旦你弄懂它们，你就能把数小时辛苦而且易错的文本处理工作压缩在几分钟（甚至几秒钟）内完成。正则表达式被各种文本编辑软件、类库（例如Rogue Wave的tools.h++）、脚本工具（像awk/grep/sed）广泛的支持，而且像Microsoft的Visual C++这种交互式IDE也开始支持它了。 </p>
<p>我们将在如下的章节中利用一些例子来解释正则表达式的用法，绝大部分的例子是基于<strong><tt>vi</tt></strong>中的文本替换命令和<strong><tt>grep</tt></strong>文件搜索命令来书写的，不过它们都是比较典型的例子，其中的概念可以在sed、awk、perl和其他支持正则表达式的编程语言中使用。你可以看看<a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#Regular_Expressions_In_Various_Tools"><u><font color=#800080>不同工具中的正则表达式</font></u></a>这一节，其中有一些在别的工具中使用正则表达式的例子。还有一个关于vi中文本替换命令（s）的<a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#ViSubstitutionCommandSyntax"><u><font color=#800080>简单说明</font></u></a>附在文后供参考。</p>
<h2>正则表达式基础</h2>
<p>正则表达式由一些普通字符和一些<em>元字符（metacharacters）</em>组成。普通字符包括大小写的字母和数字，而元字符则具有特殊的含义，我们下面会给予解释。 </p>
<p>在最简单的情况下，一个正则表达式看上去就是一个普通的查找串。例如，正则表达式"testing"中没有包含任何元字符，，它可以匹配"testing"和"123testing"等字符串，但是不能匹配"Testing"。</p>
<p>要想真正的用好正则表达式，正确的理解元字符是最重要的事情。下表列出了所有的元字符和对它们的一个简短的描述。
<p>
<table cellSpacing=2 cellPadding=2>
    <tbody>
        <tr vAlign=baseline>
            <th align=left><strong><em>元字符</em></strong></th>
            <td>&nbsp;</td>
            <th align=left><strong><em>描述</em></strong></th>
        </tr>
        <tr>
            <td>
            <hr width="100%">
            </td>
            <td></td>
            <td>
            <hr width="100%">
            </td>
        </tr>
        <tr>
            <td vAlign=top align=middle>
            <center><strong><tt><font face="Courier New"><font size=+1>.</font></font></tt></strong> </center></td>
            <td></td>
            <td>匹配任何单个字符。例如正则表达式<strong><tt>r.t</tt></strong>匹配这些字符串：<em>rat</em>、<em>rut</em>、<em>r t</em>，但是不匹配<em>root</em>。&nbsp;</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt><font face="Courier New"><font size=+1>$</font></font></tt></strong> </center></td>
            <td></td>
            <td>匹配行结束符。例如正则表达式<strong><tt>weasel$</tt></strong> 能够匹配字符串"<em>He's a weasel</em>"的末尾，但是不能匹配字符串"<em>They are a bunch of weasels.</em>"。&nbsp;</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><font size=+1>^</font></strong> </center></td>
            <td></td>
            <td>匹配一行的开始。例如正则表达式<strong><tt>^When in</tt></strong>能够匹配字符串"<em>When in the course of human events</em>"的开始，但是不能匹配"<em>What and When in the"。</em></td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt><font face="Courier New"><font size=+1>*</font></font></tt></strong> </center></td>
            <td></td>
            <td>匹配0或多个正好在它之前的那个字符。例如正则表达式<strong><tt></tt></strong><strong><tt>.*</tt></strong>意味着能够匹配任意数量的任何字符。</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt><font face="Courier New"><font size=+1>\</font></font></tt></strong> </center></td>
            <td></td>
            <td>这是引用府，用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式<strong><tt>\$</tt></strong>被用来匹配美元符号，而不是行尾，类似的，正则表达式<tt><strong>\.</strong></tt>用来匹配点字符，而不是任何字符的通配符。</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt><font face="Courier New"><font size=+1>[ ]&nbsp;</font></font></tt></strong> <br><strong><tt><font face="Courier New"><font size=+1>[c</font><font size=-1>1</font><font size=+1>-c</font><font size=-1>2</font><font size=+1>]</font></font></tt></strong> <br><strong><tt><font face="Courier New"><font size=+1>[^c</font><font size=-1>1</font><font size=+1>-c</font><font size=-1>2</font><font size=+1>]</font></font></tt></strong> </center></td>
            <td></td>
            <td>匹配括号中的任何一个字符。例如正则表达式<strong><tt>r[aou]t</tt></strong>匹配<em>rat</em>、<em>rot</em>和<em>rut</em>，但是不匹配<em>ret</em>。可以在括号中使用连字符-来指定字符的区间，例如正则表达式<strong><tt>[0-9]</tt></strong>可以匹配任何数字字符；还可以制定多个区间，例如正则表达式<strong><tt>[A-Za-z]</tt></strong>可以匹配任何大小写字母。另一个重要的用法是&#8220;排除&#8221;，要想匹配<em>除了</em>指定区间之外的字符——也就是所谓的补集——在左边的括号和第一个字符之间使用^字符，例如正则表达式<strong><tt>[^269A-Z]</tt></strong> 将匹配除了2、6、9和所有大写字母之外的任何字符。</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt><font face="Courier New"><font size=+1>\&lt; \&gt;</font></font></tt></strong> </center></td>
            <td></td>
            <td>匹配词（<em>word</em>）的开始（\&lt;）和结束（\&gt;）。例如正则表达式<strong><tt><font face="Courier New">\&lt;the</font></tt></strong>能够匹配字符串"<em>for the wise</em>"中的"the"，但是不能匹配字符串"<em>otherwise</em>"中的"the"。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt><font face="Courier New"><font size=+1>\( \)</font></font></tt></strong> </center></td>
            <td></td>
            <td>将 \( 和 \) 之间的表达式定义为&#8220;组&#8221;（<em>group</em>），并且将匹配这个表达式的字符保存到一个临时区域（一个正则表达式中最多可以保存9个），它们可以用 <strong><tt>\1</tt></strong> 到<strong><tt>\9</tt></strong> 的符号来引用。</td>
        </tr>
        <tr>
            <td vAlign=baseline>
            <center><strong><tt><font face="Courier New"><font size=+1>|</font></font></tt></strong> </center></td>
            <td></td>
            <td>将两个匹配条件进行逻辑&#8220;或&#8221;（<em>Or</em>）运算。例如正则表达式<strong><tt><font face="Courier New">(him|her)</font></tt></strong> 匹配"<em>it belongs to him</em>"和"<em>it belongs to her</em>"，但是不能匹配"<em>it belongs to them.</em>"。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
        <tr vAlign=baseline>
            <td>
            <center><strong><tt><font face="Courier New"><font size=+1>+</font></font></tt></strong> </center></td>
            <td></td>
            <td>匹配1或多个正好在它之前的那个字符。例如正则表达式<strong><tt></tt></strong><strong><tt></tt></strong><strong><tt>9+</tt></strong>匹配9、99、999等。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
        <tr vAlign=baseline>
            <td>
            <center><strong><tt><font size=+1>?</font></tt></strong> </center></td>
            <td></td>
            <td>匹配0或1个正好在它之前的那个字符。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
        <tr vAlign=baseline>
            <td>
            <center><strong><font size=+1><tt><font face="Courier New">\{</font></tt><em>i</em><tt><font face="Courier New">\}</font></tt></font></strong> <br><strong><font size=+1><tt><font face="Courier New">\{</font></tt><em>i</em><tt><font face="Courier New">,</font></tt><em>j</em><tt><font face="Courier New">\}</font></tt></font></strong> </center></td>
            <td></td>
            <td vAlign=baseline>匹配指定数目的字符，这些字符是在它之前的表达式定义的。例如正则表达式<strong><tt><font face="Courier New">A[0-9]\{3\}</font></tt></strong> 能够匹配字符"A"后面跟着正好3个数字字符的串，例如A123、A348等，但是不匹配A1234。而正则表达式<strong><tt><font face="Courier New">[0-9]\{4,6\}</font></tt></strong> 匹配连续的任意4个、5个或者6个数字字符。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<hr width="100%">
<p>最简单的元字符是点，它能够匹配任何单个字符（注意<strong>不</strong>包括新行符）。假定有个文件test.txt包含以下几行内容：</p>
<ul><tt>he is a rat</tt><br><tt>he is in a rut</tt><br><tt>the food is Rotten</tt><br><tt>I like root beer</tt> </ul>
    <p>我们可以使用grep命令来测试我们的正则表达式，grep命令使用正则表达式去尝试匹配指定文件的每一行，并将至少有一处匹配表达式的所有行显示出来。命令 </p>
    <ul><tt>grep r.t test.txt</tt> </ul>
        <p>在test.txt文件中的每一行中搜索正则表达式<strong><tt>r.t</tt></strong>，并打印输出匹配的行。正则表达式<strong><tt>r.t</tt></strong>匹配一个<strong><tt>r</tt></strong>接着任何一个字符再接着一个<strong><tt>t</tt></strong>。所以它将匹配文件中的<strong><tt>rat</tt></strong>和<strong><tt>rut</tt></strong>，而不能匹配<strong><tt>Rotten</tt></strong>中的<strong><tt>Rot</tt></strong>，因为正则表达式是大小写敏感的。要想同时匹配大写和小写字母，应该使用字符区间元字符（方括号）。正则表达式<strong><tt>[Rr]</tt></strong>能够同时匹配<strong><tt>R</tt></strong>和<strong><tt>r</tt></strong>。所以，要想匹配一个大写或者小写的<strong><tt>r</tt></strong>接着任何一个字符再接着一个<strong><tt>t</tt></strong>就要使用这个表达式：<strong><tt>[Rr].t</tt></strong>。 </p>
        <p>要想匹配行首的字符要使用抑扬字符（<em>^</em>）——又是也被叫做插入符。例如，想找到text.txt中行首"he"打头的行，你可能会先用简单表达式<strong><tt>he</tt></strong>，但是这会匹配第三行的<strong><tt>the</tt></strong>，所以要使用正则表达式<strong><tt>^he</tt></strong>，它只匹配在行首出现的<strong><tt>h</tt></strong>。 </p>
        <p>有时候指定&#8220;除了&#215;&#215;&#215;都匹配&#8221;会比较容易达到目的，当抑扬字符（<em>^</em>）出现在方括号中是，它表示&#8220;排除&#8221;，例如要匹配<strong><tt>he</tt></strong> ，但是排除前面是<strong><tt>t</tt></strong> or <strong><tt>s</tt></strong>的情性（也就是<strong><tt>the</tt></strong>和<strong><tt>s</tt></strong><strong><tt>he</tt></strong>），可以使用：<strong><tt>[^st]he</tt></strong>。 </p>
        <p>可以使用方括号来指定多个字符区间。例如正则表达式<strong><tt>[A-Za-z]</tt></strong>匹配任何字母，包括大写和小写的；正则表达式<strong><tt>[A-Za-z][A-Za-z]*</tt></strong> 匹配一个字母后面接着0或者多个字母（大写或者小写）。当然我们也可以用元字符<strong><tt>+</tt></strong>做到同样的事情，也就是：<strong><tt>[A-Za-z]+</tt></strong> ，和<strong><tt>[A-Za-z][A-Za-z]*</tt></strong>完全等价。但是要注意元字符<strong><tt>+</tt></strong> 并不是所有支持正则表达式的程序都支持的。关于这一点可以参考后面的<a href="http://net.pku.edu.cn/~yhf/tao_regexps_zh.html#Regular%20Expressions%20Syntax"><u><font color=#800080>正则表达式语法支持情况</font></u></a>。</p>
        <p>要指定特定数量的匹配，要使用大括号（注意必须使用反斜杠来转义）。想匹配所有<strong><tt>100</tt></strong>和<strong><tt>1000</tt></strong>的实例而排除<strong><tt>10</tt></strong>和<strong><tt>10000</tt></strong>，可以使用：<strong><tt>10\{2,3\}</tt></strong>，这个正则表达式匹配数字1后面跟着2或者3个0的模式。在这个元字符的使用中一个有用的变化是忽略第二个数字，例如正则表达式<strong><tt>0\{3,\}</tt></strong> 将匹配至少3个连续的0。</p>
        <h2><a name=SimpleCommands></a>简单的例子</h2>
        <p>这里有一些有代表性的、比较简单的例子。
        <p>
        <table cellSpacing=2 cellPadding=2>
            <tbody>
                <tr>
                    <td><strong><em>vi 命令</em></strong></td>
                    <td><strong><em>作用</em></strong></td>
                </tr>
                <tr>
                    <td>
                    <hr width="100%">
                    </td>
                    <td>
                    <hr width="100%">
                    </td>
                </tr>
                <tr>
                    <td><strong><tt><font face="Courier New"><font size=+1>:%s/ */ /g</font></font></tt></strong></td>
                    <td>把一个或者多个空格替换为一个空格。</td>
                </tr>
                <tr>
                    <td><strong><tt><font face="Courier New"><font size=+1>:%s/ *$//</font></font></tt></strong></td>
                    <td>去掉行尾的所有空格。</td>
                </tr>
                <tr>
                    <td><strong><tt><font face="Courier New"><font size=+1>:%s/^/ /</font></font></tt></strong></td>
                    <td>在每一行头上加入一个空格。</td>
                </tr>
                <tr>
                    <td><strong><tt><font face="Courier New"><font size=+1>:%s/^[0-9][0-9]* //</font></font></tt></strong></td>
                    <td>去掉行首的所有数字字符。</td>
                </tr>
                <tr>
                    <td><strong><tt><font face="Courier New"><font size=+1>:%s/b[aeio]g/bug/g</font></font></tt></strong></td>
                    <td>将所有的<em>bag</em>、<em>beg</em>、<em>big</em>和<em>bog</em>改为<em>bug</em>。&nbsp;</td>
                </tr>
                <tr>
                    <td><strong><tt><font face="Courier New"><font size=+1>:%s/t\([aou]\)g/h\1t/g</font></font></tt></strong></td>
                    <td>将所有<em>tag</em>、<em>tog</em>和<em>tug</em>分别改为<em>hat</em>、<em>hot</em>和<em>hug</em>（注意用group的用法和使用\1引用前面被匹配的字符）。</td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                </tr>
            </tbody>
        </table>
        <h2><a name=MediumDifficultyExamples></a>中级的例子（神奇的咒语）</h2>
        <h3>例1</h3>
        <p>将所有方法foo(<em>a,b,c</em>)的实例改为foo(<em>b,a,c</em>)。这里a、b和c可以是任何提供给方法foo()的参数。也就是说我们要实现这样的转换：
        <p>
        <table cellSpacing=4 cellPadding=0>
            <tbody>
                <tr>
                    <td><strong>之前</strong></td>
                    <td>&nbsp;</td>
                    <td><strong>之后</strong></td>
                </tr>
                <tr>
                    <td><tt>foo(10,7,2)</tt></td>
                    <td></td>
                    <td><tt>foo(7,10,2)</tt></td>
                </tr>
                <tr>
                    <td><tt>foo(x+13,y-2,10)</tt></td>
                    <td></td>
                    <td><tt>foo(y-2,x+13,10)</tt></td>
                </tr>
                <tr>
                    <td><tt>foo( bar(8), x+y+z, 5)</tt></td>
                    <td></td>
                    <td><tt>foo( x+y+z, bar(8), 5)</tt></td>
                </tr>
            </tbody>
        </table>
        <p>下面这条替换命令能够实现这一魔法：</p>
        <ul><strong><tt><font face="Courier New">:%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g</font></tt></strong> </ul>
            <p>现在让我们把它打散来加以分析。写出这个表达式的基本思路是找出foo()和它的括号中的三个参数的位置。第一个参数是用这个表达式来识别的：：<strong><tt><font face="Courier New">\([^,]*\)</font></tt></strong>，我们可以从里向外来分析它：&nbsp;
            <p>
            <table>
                <tbody>
                    <tr>
                        <td><strong><tt><font face="Courier New">[^,]</font></tt></strong></td>
                        <td>&nbsp;</td>
                        <td>除了逗号之外的任何字符</td>
                    </tr>
                    <tr>
                        <td><strong><tt><font face="Courier New">[^,]*</font></tt></strong></td>
                        <td></td>
                        <td>0或者多个非逗号字符</td>
                    </tr>
                    <tr>
                        <td><strong><tt><font face="Courier New">\([^,]*\)</font></tt></strong></td>
                        <td></td>
                        <td>将这些非逗号字符标记为<strong><tt>\1</tt></strong>，这样可以在之后的替换模式表达式中引用它</td>
                    </tr>
                    <tr vAlign=baseline>
                        <td><strong><tt><font face="Courier New">\([^,]*\),</font></tt></strong></td>
                        <td></td>
                        <td>我们必须找到0或者多个非逗号字符后面跟着一个逗号，并且非逗号字符那部分要标记出来以备后用。</td>
                    </tr>
                </tbody>
            </table>
            <p>现在正是指出一个使用正则表达式常见错误的最佳时机。为什么我们要使用<strong><tt><font face="Courier New">[^,]*</font></tt></strong>这样的一个表达式，而不是更加简单直接的写法，例如：<strong><tt><font face="Courier New">.*</font></tt></strong>，来匹配第一个参数呢？设想我们使用模式<strong><tt><font face="Courier New">.*</font></tt></strong>来匹配字符串"10,7,2"，它应该匹配"10,"还是"10,7,"？为了解决这个两义性（ambiguity），正则表达式规定一律按照最长的串来，在上面的例子中就是"10,7,"，显然这样就找出了两个参数而不是我们期望的一个。所以，我们要使用<strong><tt><font face="Courier New">[^,]*</font></tt></strong>来强制取出第一个逗号之前的部分。</p>
            <p>这个表达式我们已经分析到了：<strong><tt><font face="Courier New">foo(\([^,]*\)</font></tt></strong>，这一段可以简单的翻译为&#8220;当你找到<strong><tt>foo(</tt></strong>就把其后直到第一个逗号之前的部分标记为<strong><tt><font face="Courier New">\1</font></tt></strong>&#8221;。然后我们使用同样的办法标记第二个参数为<strong><tt><font face="Courier New">\2</font></tt></strong>。对第三个参数的标记方法也是一样，只是我们要搜索所有的字符直到右括号。我们并没有必要去搜索第三个参数，因为我们不需要调整它的位置，但是这样的模式能够保证我们只去替换那些有三个参数的foo()方法调用，在foo()是一个重载（overoading）方法时这种明确的模式往往是比较保险的。然后，在替换部分，我们找到foo()的对应实例，然后利用标记好的部分进行替换，是的第一和第二个参数交换位置。</p>
            <h3>例2</h3>
            <p>假设有一个CSV（comma separated value）文件，里面有一些我们需要的信息，但是格式却有问题，目前数据的列顺序是：姓名，公司名，州名缩写，邮政编码，现在我们希望讲这些数据重新组织，以便在我们的某个软件中使用，需要的格式为：姓名，州名缩写-邮政编码，公司名。也就是说，我们要调整列顺序，还要合并两个列来构成一个新列。另外，我们的软件不能接受逗号前后面有任何空格（包括空格和制表符）所以我们还必须要去掉逗号前后的所有空格。 </p>
            <p>这里有几行我们现在的数据：</p>
            <ul><tt>Bill Jones,&nbsp;&nbsp;&nbsp;&nbsp; HI-TEK Corporation ,&nbsp; CA, 95011</tt> <br><tt><font face="Courier New">Sharon Lee Smith,&nbsp; Design Works Incorporated,&nbsp; CA, 95012</font></tt> <br><tt><font face="Courier New">B. Amos&nbsp;&nbsp; ,&nbsp; Hill Street Cafe,&nbsp; CA, 95013</font></tt> <br><tt><font face="Courier New">Alexander Weatherworth,&nbsp; The Crafts Store,&nbsp; CA, 95014</font></tt> <br><tt><font face="Courier New">...</font></tt> </ul>
                <p>我们希望把它变成这个样子： </p>
                <ul><tt>Bill Jones,CA 95011,HI-TEK Corporation</tt> <br><tt><font face="Courier New">Sharon Lee Smith,CA 95012,Design Works Incorporated</font></tt> <br><tt><font face="Courier New">B. Amos,CA 95013,Hill Street Cafe</font></tt> <br><tt><font face="Courier New">Alexander Weatherworth,CA 95014,The Crafts Store</font></tt> <br><tt><font face="Courier New">...</font></tt> </ul>
                    <p>我们将用两个正则表达式来解决这个问题。第一个移动列和合并列，第二个用来去掉空格。 </p>
                    <p>下面就是第一个替换命令：</p>
                    <ul><strong><tt><font face="Courier New">:%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/</font></tt></strong> </ul>
                        <p>这里的方法跟例1基本一样，第一个列（姓名）用这个表达式来匹配：<strong><tt><font face="Courier New">\([^,]*\)</font></tt></strong>，即第一个逗号之前的所有字符，而姓名内容被用<strong><tt><font face="Courier New">\1</font></tt></strong>标记下来。公司名和州名缩写字段用同样的方法标记为<strong><tt><font face="Courier New">\2</font></tt></strong>和<strong><tt><font face="Courier New">\3</font></tt></strong>，而最后一个字段用<strong><tt><font face="Courier New">\(.*\)</font></tt></strong>来匹配（"匹配所有字符直到行末"）。替换部分则引用上面标记的那些内容来进行构造。 </p>
                        <p>下面这个替换命令则用来去除空格：</p>
                        <ul><strong><tt><font face="Courier New">:%s/[ \t]*,[ \t]*/,/g</font></tt></strong> </ul>
                            <p>我们还是分解来看：<strong><tt><font face="Courier New">[ \t]</font></tt></strong>匹配空格/制表符，<strong><tt><font face="Courier New">[ \t]*</font></tt></strong> 匹配0或多个空格/制表符，<strong><tt>[ \t]*</tt></strong>,匹配0或多个空格/制表符后面再加一个逗号，最后，<strong><tt><font face="Courier New">[ \t]*,[ \t]*</font></tt></strong>匹配0或多个空格/制表符接着一个逗号再接着0或多个空格/制表符。在替换部分，我们简单的我们找到的所有东西替换成一个逗号。这里我们使用了结尾的可选的<strong><tt>g</tt></strong>参数，这表示在每行中对所有匹配的串执行替换（而不是缺省的只替换第一个匹配串）。 </p>
                            <h3>例3</h3>
                            <p>假设有一个多字符的片断重复出现，例如： </p>
                            <blockquote><tt>Billy tried really hard</tt> <br><tt>Sally tried really really hard</tt> <br><tt>Timmy tried really really really hard</tt> <br><tt>Johnny tried really really really really hard</tt></blockquote>
                            <p>而你想把"really"、"really really"，以及任意数量连续出现的"really"字符串换成一个简单的"very"（simple is good!），那么以下命令： </p>
                            <blockquote><strong><tt>:%s/\(really \)\(really \)*/very /</tt></strong></blockquote>
                            <p>就会把上述的文本变成： </p>
                            <blockquote><tt>Billy tried very hard</tt> <br><tt>Sally tried very hard</tt> <br><tt>Timmy tried very hard</tt> <br><tt>Johnny tried very hard</tt></blockquote>
                            <p>表达式<strong><tt>\(really \)*</tt></strong>匹配0或多个连续的"really "（注意结尾有个空格），而<strong><tt>\(really \)\(really \)*</tt></strong> 匹配1个或多个连续的"really "实例。 </p>
                            <h2><a name=HardExamples></a>困难的例子（不可思议的象形文字）</h2>
                            <p><em>Coming soon</em>. </p>
                            <p>&nbsp;</p>
                            <hr>
                            <h1><a name=Regular_Expressions_In_Various_Tools></a>不同工具中的正则表达式</h1>
                            <p>OK，你已经准备使用RE（regular expressions，正则表达式），但是你并准备使用vi。所以，在这里我们给出一些在其他工具中使用RE的例子。另外，我还会总结一下你在不同程序之间使用RE可能发现的区别。 </p>
                            <p>当然，你也可以在Visual C++编辑器中使用RE。选择Edit-&gt;Replace，然后选择"Regular expression"选择框，Find What输入框对应上面介绍的vi命令<strong><tt>:%s/pat1/pat2/g</tt></strong>中的pat1部分，而Replace输入框对应pat2部分。但是，为了得到vi的执行范围和<strong><tt>g</tt></strong>选项，你要使用Replace All或者适当的手工Find Next and Replace（译者按：知道为啥有人骂微软弱智了吧，虽然VC中可以选中一个范围的文本，然后在其中执行替换，但是总之不够vi那么灵活和典雅）。</p>
                            <h2>sed</h2>
                            <p>Sed是<strong><u>S</u></strong>tream <strong><u>ED</u></strong>itor的缩写，是Unix下常用的基于文件和管道的编辑工具，可以在手册中得到关于sed的详细信息。 </p>
                            <p>这里是一些有趣的sed脚本，假定我们正在处理一个叫做price.txt的文件。注意这些编辑并不会改变源文件，sed只是处理源文件的每一行并把结果显示在标准输出中（当然很容易使用重定向来定制）：
                            <p>
                            <table>
                                <tbody>
                                    <tr>
                                        <td><strong><em>sed脚本</em></strong></td>
                                        <td>&nbsp;</td>
                                        <td><strong><em>描述</em></strong></td>
                                    </tr>
                                    <tr>
                                        <td>
                                        <hr width="100%">
                                        </td>
                                        <td></td>
                                        <td>
                                        <hr width="100%">
                                        </td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>sed 's/^$/d' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>删除所有空行</td>
                                    </tr>
                                    <tr>
                                        <td><strong><tt>sed 's/^[ \t]*$/d' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>删除所有只包含空格或者制表符的行</td>
                                    </tr>
                                    <tr>
                                        <td><strong><tt>sed 's/"//g' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>删除所有引号</td>
                                    </tr>
                                </tbody>
                            </table>
                            </p>
                            <h2>awk</h2>
                            <p>awk是一种编程语言，可以用来对文本数据进行复杂的分析和处理。可以在手册中得到关于awk的详细信息。这个古怪的名字是它作者们的姓的缩写（Aho，Weinberger和Kernighan）。 </p>
                            <p>在Aho，Weinberger和Kernighan的书<u>The AWK Programming Language</u>中有很多很好的awk的例子，请不要让下面这些微不足道的脚本例子限制你对awk强大能力的理解。我们同样假定我们针对price.txt文件进行处理，跟sed一样，awk也只是把结果显示在终端上。&nbsp;
                            <p>
                            <table>
                                <tbody>
                                    <tr>
                                        <td><strong><em>awk脚本</em></strong></td>
                                        <td>&nbsp;</td>
                                        <td><strong><em>描述</em></strong></td>
                                    </tr>
                                    <tr>
                                        <td>
                                        <hr width="100%">
                                        </td>
                                        <td></td>
                                        <td>
                                        <hr width="100%">
                                        </td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>awk '$0 !~ /^$/' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>删除所有空行</td>
                                    </tr>
                                    <tr>
                                        <td><strong><tt>awk 'NF &gt; 0' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>awk中一个更好的删除所有行的办法</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>awk '$2 ~ /^[JT]/ {print $3}' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有第二个字段是'J'或者'T'打头的行中的第三个字段</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td noWrap><strong><tt>awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>针对所有第二个字段不包含'Misc'或者'misc'的行，打印第3和第4列的和（假定为数字）</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有第三个字段不是数字的行，这里数字是指<tt>d.d</tt>或者<tt>d这样的形式，其中</tt><tt>d</tt>是0到9的任何数字</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>awk '$2 ~ /John|Fred/ {print $0}' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>如果第二个字段包含'John'或者'Fred'则打印整行</td>
                                    </tr>
                                </tbody>
                            </table>
                            </p>
                            <h2>grep</h2>
                            <p>grep是一个用来在一个或者多个文件或者输入流中使用RE进行查找的程序。它的name编程语言可以用来针对文件和管道进行处理。可以在手册中得到关于grep的完整信息。这个同样古怪的名字来源于vi的一个命令，<strong><tt>g/</tt></strong><em>re</em><strong><tt>/p</tt></strong>，意思是<strong>g</strong>lobal <strong>r</strong>egular <strong>e</strong>xpression <strong>p</strong>rint。 </p>
                            <p>下面的例子中我们假定在文件phone.txt中包含以下的文本，——其格式是姓加一个逗号，然后是名，然后是一个制表符，然后是电话号码：</p>
                            <ul>
                                <p><tt>Francis, John&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-3871</tt> <br><tt>Wong, Fred&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4-4123</tt> <br><tt>Jones, Thomas&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1-4122</tt> <br><tt>Salazar, Richard&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-2522</tt></p>
                            </ul>
                            <p>
                            <table>
                                <tbody>
                                    <tr>
                                        <td><strong><em>grep命令</em></strong></td>
                                        <td><strong><em>&nbsp;</em></strong></td>
                                        <td><strong><em>描述</em></strong></td>
                                    </tr>
                                    <tr>
                                        <td>
                                        <hr width="100%">
                                        </td>
                                        <td></td>
                                        <td>
                                        <hr width="100%">
                                        </td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>grep '\t5-...1' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>把所有电话号码以5开头以1结束的行打印出来，注意制表符是用<strong><tt>\t</tt></strong>表示的</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td noWrap><strong><tt>grep '^S[^ ]* R' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有姓以S打头和名以R打头的行</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>grep '^[JW]' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有姓开头是J或者W的行</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>grep ', ....\t' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有姓是4个字符的行，注意制表符是用<strong><tt>\t</tt></strong>表示的</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>grep -v '^[JW]' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有不以J或者W开头的行</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>grep '^[M-Z]' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有姓的开头是M到Z之间任一字符的行</td>
                                    </tr>
                                    <tr vAlign=baseline>
                                        <td><strong><tt>grep '^[M-Z].*[12]' phone.txt</tt></strong></td>
                                        <td></td>
                                        <td>打印所有姓的开头是M到Z之间任一字符，并且点号号码结尾是1或者2的行</td>
                                    </tr>
                                </tbody>
                            </table>
                            <h2>egrep</h2>
                            <p>egrep是grep的一个扩展版本，它在它的正则表达式中支持更多的元字符。下面的例子中我们假定在文件phone.txt中包含以下的文本，——其格式是姓加一个逗号，然后是名，然后是一个制表符，然后是电话号码： </p>
                            <ul><tt>Francis, John&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-3871</tt> <br><tt>Wong, Fred&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4-4123</tt> <br><tt>Jones, Thomas&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1-4122</tt> <br><tt>Salazar, Richard&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5-2522</tt> </ul>
                                <p>
                                <table>
                                    <tbody>
                                        <tr>
                                            <td><strong><em>egrep command</em></strong></td>
                                            <td><strong><em>&nbsp;</em></strong></td>
                                            <td><strong><em>Description</em></strong></td>
                                        </tr>
                                        <tr>
                                            <td>
                                            <hr width="100%">
                                            </td>
                                            <td></td>
                                            <td>
                                            <hr width="100%">
                                            </td>
                                        </tr>
                                        <tr vAlign=baseline>
                                            <td><strong><tt>egrep '(John|Fred)' phone.txt</tt></strong></td>
                                            <td></td>
                                            <td>打印所有包含名字<em>John</em>或者<em>Fred</em>的行</td>
                                        </tr>
                                        <tr vAlign=baseline>
                                            <td noWrap><strong><tt>egrep 'John|22$|^W' phone.txt</tt></strong></td>
                                            <td></td>
                                            <td>打印所有包含<em>John</em> 或者以22结束或者以<em>W</em>的行</td>
                                        </tr>
                                        <tr>
                                            <td><strong><tt>egrep 'net(work)?s' report.txt</tt></strong></td>
                                            <td></td>
                                            <td>从report.txt中找到所有包含<em>networks</em>或者<em>nets</em>的行</td>
                                        </tr>
                                    </tbody>
                                </table>
                                <h2>
                                <hr width="100%">
                                </h2>
                                <h1><a name="Regular Expressions Syntax"></a>正则表达式语法支持情况</h1>
                                <p>
                                <table cellSpacing=0 border=1>
                                    <tbody>
                                        <tr>
                                            <td><strong>命令或环境</strong></td>
                                            <td><strong><tt><font face="Courier New">.</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">[ ]</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">^</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">$</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">\( \)</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">\{ \}</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">?</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">+</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">|</font></tt></strong></td>
                                            <td><strong><tt><font face="Courier New">( )</font></tt></strong></td>
                                        </tr>
                                        <tr>
                                            <td>vi</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>Visual C++</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>awk</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>sed</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>Tcl</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>ex</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>grep</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>egrep</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>fgrep</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;X&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>perl</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                            <td>&nbsp;X</td>
                                        </tr>
                                    </tbody>
                                </table>
                                </p>
                                <p>&nbsp;</p>
                                <hr>
                                <h1><a name=ViSubstitutionCommandSyntax></a>vi替换命令简介</h1>
                                <p>Vi的替换命令： </p>
                                <ul><strong><tt>:</tt></strong><em>range</em><strong><tt>s/</tt></strong><em>pat1</em><strong><tt>/</tt></strong><em>pat2</em><strong><tt>/g</tt></strong> </ul>
                                    <p>其中 </p>
                                    <ul><strong><tt>:</tt></strong> 这是Vi的命令执行界面。 </ul>
                                        <ul><em>range </em>是命令执行范围的指定，可以使用百分号（%）表示所有行，使用点（.）表示当前行，使用美元符号（$）表示最后一行。你还可以使用行号，例如<strong><tt>10,20</tt></strong>表示第10到20行，<strong><tt>.,$</tt></strong>表示当前行到最后一行，<strong><tt>.+2,$-5</tt></strong>表示当前行后两行直到全文的倒数第五行，等等。
                                            <p><strong><tt>s</tt></strong> 表示其后是一个替换命令。</p>
                                            <p><em>pat1 </em>这是要查找的一个正则表达式，这篇文章中有一大堆例子。</p>
                                        </ul>
                                        <ul><em>pat2 </em>这是希望把匹配串变成的模式的正则表达式，这篇文章中有一大堆例子。
                                            <p><strong><tt>g</tt></strong> 可选标志，带这个标志表示替换将针对行中每个匹配的串进行，否则则只替换行中第一个匹配串。</p>
                                        </ul>
                                        <p>网上有很多vi的在线手册，你可以访问他们以获得更加完整的信息。 </p>
                                        <p>&nbsp;</p>
                                        <hr width="100%">
                                        <center>
                                        <p>&nbsp;</p>
                                        </center>
                                        <p><br><br>&nbsp;</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/21574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-04-10 09:59 <a href="http://www.cppblog.com/sunraiing9/archive/2007/04/10/21574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dumpbin.exe调试命令</title><link>http://www.cppblog.com/sunraiing9/archive/2007/04/02/21077.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Mon, 02 Apr 2007 01:31:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/04/02/21077.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/21077.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/04/02/21077.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/21077.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/21077.html</trackback:ping><description><![CDATA[<font face=宋体 size=4>在使用VC时，可以用DUMPBIN。EXE来得到某个DLL中所输出的符号的清单。如下面的</font>
<p><font face=宋体 color=#000000 size=4>命令：dumpbin -exports Cmpnt1.dll<br>如：<br><br>C:\WINDOWS\system32&gt;dumpbin -exports msgsvc.dll<br>Microsoft (R) COFF Binary File Dumper Version 6.00.8447<br>Copyright (C) Microsoft Corp 1992-1998. All rights reserved.</font></p>
<p><br><font face=宋体 color=#000000 size=4>Dump of file msgsvc.dll</font></p>
<p><font face=宋体 color=#000000 size=4>File Type: DLL</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp; Section contains the following exports for msgsvc.dll</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 characteristics<br>&nbsp;&nbsp;&nbsp; 41107F60 time date stamp Wed Aug 04 14:17:04 2004<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.00 version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 ordinal base<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 number of functions<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 number of names</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp;&nbsp;&nbsp; ordinal hint RVA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0 00004ABF ServiceMain<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1 00004595 SvchostPushServiceGlobals</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp; Summary</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000 .data<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000 .reloc<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000 .rsrc<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8000 .text<br><br><br>C:\&gt;dumpbin<br>Microsoft (R) COFF Binary File Dumper Version 6.00.844<br>Copyright (C) Microsoft Corp 1992-1998. All rights res</font></p>
<p><font face=宋体 color=#000000 size=4>usage: DUMPBIN [options] [files]</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp;&nbsp; options:</font></p>
<p><font face=宋体 color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /ALL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /ARCH<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /ARCHIVEMEMBERS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /DEPENDENTS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /DIRECTIVES<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /DISASM<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /EXPORTS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /FPO<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /HEADERS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /IMPORTS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /LINENUMBERS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /LINKERMEMBER[:{1|2}]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /LOADCONFIG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /OUT:filename<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /PDATA<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /RAWDATA[:{NONE|BYTES|SHORTS|LONGS}[,#]]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /RELOCATIONS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /SECTION:name<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /SUMMARY<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /SYMBOLS<br><br><br></font></p>
<p><font face=宋体 color=#000000 size=4>若要运行 DUMPBIN，请使用下列语法：</font></p>
<pre class=syntax><font face=宋体 color=#000000 size=4>DUMPBIN [<em>options</em>] <em>files</em>...</font>
<p><font face=宋体 color=#000000 size=4>指定一个或多个二进制文件，以及控制信息所需的任何选项。DUMPBIN 将该信息显示到标准输出。可以将输出重定向到文件，或者使用 /OUT 选项为输出指定文件名。</font></p>
<p><font face=宋体 color=#000000 size=4>当在文件上运行 DUMPBIN 但未指定选项时，DUMPBIN 显示 /SUMMARY 输出。</font></p>
<p><font face=宋体 color=#000000 size=4>当键入命令 <code class=ce>dumpbin</code> 但没有任何其他命令行输入时，DUMPBIN 显示汇总其选项的用法语句。<br><br></font></p>
<p><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_core_dumpbin_options.asp"'><font face=宋体 color=#ff0000 size=4><u>DUMPBIN 选项</u></font></a><br></p>
<!-- End Content --><!-- Topic Status -->
<pre class=syntax><font face=宋体 color=#006400 size=4>/ALL</font>
<p><font face=宋体 color=#000000 size=4>此选项显示除代码反汇编外的所有可用信息。使用 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.disasm.asp"'><font face=宋体 color=#000000 size=4><u>/DISASM</u></font></a><font face=宋体 color=#000000 size=4> 显示反汇编。可以与 /ALL 一起使用 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.rawdata.asp"'><font face=宋体 color=#000000 size=4><u>/RAWDATA</u></font></a><font face=宋体 color=#000000 size=4>:NONE 来省略文件的原始二进制详细资料。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/ARCHIVEMEMBERS</font>
<p><font face=宋体 color=#000000 size=4>此选项显示有关库成员对象的最少信息。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font size=4><font face=宋体><font color=#006400>/CLRHEADER <em>file</em></font></font></font>
<p><font face=宋体 color=#000000 size=4>此处： </font>
<dl>
<dt><font size=4><font face=宋体><font color=#000000><em>file</em> </font></font></font>
<dd><font face=宋体 color=#000000 size=4>用 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcrefeecomcompilation.asp"'><font face=宋体 color=#000000 size=4><u>/clr</u></font></a><font face=宋体 color=#000000 size=4> 生成的图像文件。 </font></dd></dl>
<h4 class=dtH4><font face=宋体 color=#000000 size=4>备注</font></h4>
<p><font face=宋体 color=#000000 size=4>CLRHEADER 显示有关在任何托管程序中使用的 .NET 头的信息。输出显示 .NET 头及其中各节的位置和大小（以字节计）。</font></p>
<p><font face=宋体 color=#000000 size=4>File Format Spec.doc 描述 .NET 头中的信息。NET SDK 将 File Format Spec.doc 安装在 Tools Developers Guide 目录中。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/DIRECTIVES</font>
<p><font face=宋体 color=#000000 size=4>此选项转储图像中由编译器生成的 .directive 节。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/DEPENDENTS</font>
<p><font face=宋体 color=#000000 size=4>转储图像从中导入函数的 DLL 的名称。不要转储导入函数名。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/DISASM</font>
<p><font face=宋体 color=#000000 size=4>此选项显示代码段的反汇编，如果出现在文件中则使用符号。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/EXPORTS</font>
<p><font face=宋体 color=#000000 size=4>此选项显示从可执行文件或 DLL 导出的所有定义。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/FPO</font>
<p><font face=宋体 color=#000000 size=4>此选项显示框架指针优化 (FPO) 记录。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/HEADERS</font>
<p><font face=宋体 color=#000000 size=4>此选项显示文件头和每节的头。当用于库时，显示每个成员对象的头。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp?frame=true#_dumpbin_.2f.headers"' target=_self><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/IMPORTS[:<em>file</em>]</font>
<p><font face=宋体 color=#000000 size=4>此选项显示导入到可执行文件或 DLL 的 DLL 列表（静态链接的和</font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcconlinkersupportfordelayedloadingofdlls.asp"'><font face=宋体 color=#000000 size=4><u>延迟加载</u></font></a><font face=宋体 color=#000000 size=4>）和上述每个 DLL 的各个导入。</font></p>
<p><font face=宋体 color=#000000 size=4>可选 <em>file</em> 规范允许指定仅显示某个 DLL 的导入。例如：</font></p>
<pre class=code><font face=宋体 color=#000000 size=4>dumpbin /IMPORTS:msvcrt.dll</font>
<p><font face=宋体 color=#000000 size=4>此选项显示的输出与 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.exports.asp"'><font face=宋体 color=#000000 size=4><u>/EXPORTS</u></font></a><font face=宋体 color=#000000 size=4> 输出相似。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/LINENUMBERS</font>
<p><font face=宋体 color=#000000 size=4>此选项显示 COFF 行号。如果对象文件是用程序数据库 (/Zi)、C7 兼容 (/Z7) 或仅限行号 (/Zd) 编译的，则它包含行号。如果可执行文件或 DLL 是与生成调试信息 (/DEBUG) 链接的，则它包含 COFF 行号。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/LINKERMEMBER[:{1|2}]</font>
<p><font face=宋体 color=#000000 size=4>此选项显示库中定义的公共符号。指定参数 1 将按对象顺序显示符号及其偏移量。指定参数 2 将显示对象的偏移量和索引号，然后按字母顺序列出这些符号及每个符号的对象索引。若要两个输出都获得，指定不带数字参数的 /LINKERMEMBER。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/LOADCONFIG</font>
<p><font face=宋体 color=#000000 size=4>此选项转储 IMAGE_LOAD_CONFIG_DIRECTORY 结构，此结构是由 Windows NT 加载程序使用并在 WINNT.H 中定义的可选结构。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font size=4><font face=宋体><font color=#006400>/OUT:<em>filename</em></font></font></font>
<p><font face=宋体 color=#000000 size=4>此选项指定输出的 <em>filename</em>。默认情况下，DUMPBIN 将信息显示到标准输出。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font size=4><font face=宋体><font color=#006400>/PDBPATH[:VERBOSE] <em>filename</em></font></font></font>
<p><font face=宋体 color=#000000 size=4>此处： </font>
<dl>
<dt><font size=4><font face=宋体><font color=#000000><em>filename</em> </font></font></font>
<dd><font face=宋体 color=#000000 size=4>要为其查找匹配 .pdb 文件的 .dll 或 .exe 文件名。 </font>
<dt><font face=宋体 color=#000000 size=4>VERBOSE（可选） </font>
<dd><font face=宋体 color=#000000 size=4>报告曾尝试在其中定位 .pdb 文件的所有目录。 </font></dd></dl>
<h4 class=dtH4><font face=宋体 color=#000000 size=4>备注</font></h4>
<p><font face=宋体 color=#000000 size=4>/PDBPATH 将沿调试器搜索 .pdb 文件的同一路径搜索计算机，并将报告哪些 .pdb 文件（若有）和 <em>filename</em> 中指定的文件相对应。</font></p>
<p><font face=宋体 color=#000000 size=4>使用 Visual Studio 调试器时可能会遇到问题，这是因为调试器对调试文件的不同版本使用 .pdb 文件。</font></p>
<p><font face=宋体 color=#000000 size=4>/PDBPATH 将沿下列路径搜索 .pdb 文件： </font>
<ul type=disc>
    <li><font face=宋体 color=#000000 size=4>检查可执行文件驻留的位置。 </font>
    <li><font face=宋体 color=#000000 size=4>检查写入可执行文件的 PDB 的位置。这通常是图像被链接时的位置。 </font>
    <li><font face=宋体 color=#000000 size=4>沿 Visual Studio IDE 中配置的搜索路径检查。 </font>
    <li><font face=宋体 color=#000000 size=4>沿 _NT_SYMBOL_PATH 和 _NT_ALT_SYMBOL_PATH 环境变量中的路径检查。 </font>
    <li><font face=宋体 color=#000000 size=4>在 Windows 目录中检查。 </font></li>
</ul>
<pre class=syntax><font face=宋体 color=#006400 size=4>/PDATA</font>
<p><font face=宋体 color=#000000 size=4>仅用于 RISC 处理器。</font></p>
<p><font face=宋体 color=#000000 size=4>此选项从图像或对象转储异常表 (.pdata)。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/RAWDATA[:{1|2|4|8|NONE[<strong>,</strong><em>number</em>]]</font>
<p><font face=宋体 color=#000000 size=4>此选项显示文件中每节的原始内容。参数控制显示格式，如下所示：</font></p>
<div class=tablediv>
<table class=dtTABLE cellSpacing=0>
    <tbody>
        <tr vAlign=top>
            <th width='"20%"'><font face=宋体 color=#000000 size=4>参数</font></th><th width='"80%"'><font face=宋体 color=#000000 size=4>结果</font></th>
        </tr>
        <tr vAlign=top>
            <td width='"20%"'><font face=宋体 color=#000000 size=4>1</font></td>
            <td width='"80%"'><font face=宋体 color=#000000 size=4>默认值。内容以十六进制字节显示，如果内容具有打印的表示形式，则还显示为 ASCII 字符。</font></td>
        </tr>
        <tr vAlign=top>
            <td width='"20%"'><font face=宋体 color=#000000 size=4>2</font></td>
            <td width='"80%"'><font face=宋体 color=#000000 size=4>内容显示为十六进制的 2 字节值。</font></td>
        </tr>
        <tr vAlign=top>
            <td width='"20%"'><font face=宋体 color=#000000 size=4>4</font></td>
            <td width='"80%"'><font face=宋体 color=#000000 size=4>内容显示为十六进制的 4 字节值。</font></td>
        </tr>
        <tr vAlign=top>
            <td width='"20%"'><font face=宋体 color=#000000 size=4>8</font></td>
            <td width='"80%"'><font face=宋体 color=#000000 size=4>内容显示为十六进制的 8 字节值。</font></td>
        </tr>
        <tr vAlign=top>
            <td width='"20%"'><font face=宋体 color=#000000 size=4>NONE</font></td>
            <td width='"80%"'><font face=宋体 color=#000000 size=4>取消显示原始数据。此参数对控制 /ALL 输出很有用。</font></td>
        </tr>
        <tr vAlign=top>
            <td width='"20%"'><em><font face=宋体 color=#000000 size=4>Number</font></em></td>
            <td width='"80%"'><font face=宋体 color=#000000 size=4>显示的行被设置为每行具有 <em>number</em> 个值的宽度。</font></td>
        </tr>
    </tbody>
</table>
</div>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/RELOCATIONS</font>
<p><font face=宋体 color=#000000 size=4>此选项显示对象或图像中的任何重定位。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font size=4><font face=宋体><font color=#006400>/SECTION:<em>section</em></font></font></font>
<p><font face=宋体 color=#000000 size=4>此选项限制与指定的 <em>section</em> 有关的信息的输出。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/SUMMARY</font>
<p><font face=宋体 color=#000000 size=4>此选项显示有关节的最少信息（包括总大小）。如果未指定其他选项，则此选项为默认值。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<pre class=syntax><font face=宋体 color=#006400 size=4>/SYMBOLS</font>
<p><font face=宋体 color=#000000 size=4>此选项显示 COFF 符号表。符号表存在于所有对象文件中。而对于图像文件，只有当它是与 /DEBUG 链接的时，它才包含 COFF 符号表。</font></p>
<p><font face=宋体 color=#000000 size=4>下面是关于 /SYMBOLS 输出的说明。通过查阅 winnt.h（IMAGE_SYMBOL 和 IMAGE_AUX_SYMBOL）或 COFF 文档，可找到有关 /SYMBOLS 输出含义的附加信息。</font></p>
<p><font face=宋体 color=#000000 size=4>假设有下列示例转储：</font></p>
<pre class=code><font face=宋体 color=#000000 size=4>Dump of file main.obj
File Type: COFF OBJECT
COFF    SYMBOL    TABLE
000    00000000   DEBUG      notype      Filename      | .file
main.cpp
002   000B1FDB   ABS      notype      Static      | @comp.id
003   00000000   SECT1      notype      Static      | .drectve
Section length       26, #relocs   0, #linenums    0, checksum 722C964F
005   00000000   SECT2      notype      Static      | .text
Section length      23, #relocs      1, #linenums    0, checksum 459FF65F, selection    1 (pick no duplicates)
007   00000000   SECT2      notype ()   External      | _main
008   00000000   UNDEF      notype ()   External      | ?MyDump@@YAXXZ (void __cdecl MyDump(void))
String Table Size = 0x10 bytes
Summary
26 .drectve
23 .text</font>
<p><font face=宋体 color=#000000 size=4>对于以符号号码开头的行，下列说明描述了含有与用户相关的信息的列： </font>
<ul type=disc>
    <li><font face=宋体 color=#000000 size=4>开头的 3 位数字是符号索引/号码。 </font>
    <li><font face=宋体 color=#000000 size=4>如果第三列包含 SECT<em>x</em>，则符号在对象文件的那一节中定义。但如果出现 UNDEF，则它不在那个对象中定义并且必须在其他地方被解析。 </font>
    <li><font face=宋体 color=#000000 size=4>第五列 (Static, External) 说明符号是否只在那个对象的内部可见，或者是否是公共的（外部可见）。静态符号 _sym 不会链接到公共符号 _sym；这些符号是名为 _sym 的函数的两种不同实例。 </font></li>
</ul>
<p><font face=宋体 color=#000000 size=4>编号行中的最后一列是符号名（修饰名和未修饰名）。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
<font face=宋体 color=#006400 size=4>/UNWINDINFO</font>
<p><font face=宋体 color=#000000 size=4>在程序图像（例如 exe 和 dll）中转储结构化异常处理 (SEH) 表的展开描述符。/UNWINDINFO 仅适用于 IA64 图像。</font></p>
<p><font face=宋体 color=#000000 size=4>只有 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/_dumpbin_.2f.headers.asp"'><font face=宋体 color=#000000 size=4><u>/HEADERS</u></font></a><font face=宋体 color=#000000 size=4> DUMPBIN 选项可用于由 </font><a href='http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/"http://msdn.microsoft.com/library/chs/vccore/html/vcgrfglwholeprogramoptimization.asp"'><font face=宋体 color=#000000 size=4><u>/GL</u></font></a><font face=宋体 color=#000000 size=4> 编译器选项产生的文件。</font></p>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
</pre>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/21077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-04-02 09:31 <a href="http://www.cppblog.com/sunraiing9/archive/2007/04/02/21077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于封装中virtual的消耗问题</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/31/20983.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Fri, 30 Mar 2007 18:44:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/31/20983.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20983.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/31/20983.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20983.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20983.html</trackback:ping><description><![CDATA[晚上翻了翻《Inside th C++ object Model》<br /><br />里面在 讨论C和C++定义Point3d类型，C++加封装后的布局成本提高了多少。<br /><br />作者分析来分析去，最后把C++在布局和存取时间上主要的额外负担是有virtual引起的<br /><br />包括 virtual function 和 virtual base class .<br /><br />书上就几句话，没太说清楚原因，各位路过多多指教啊：）<img src ="http://www.cppblog.com/sunraiing9/aggbug/20983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-31 02:44 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/31/20983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>位运算 </title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/29/20859.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Thu, 29 Mar 2007 04:35:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/29/20859.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20859.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/29/20859.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20859.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20859.html</trackback:ping><description><![CDATA[位运算 (自己最近用的多 做个复习 记录)<br /><br />　　 前面介绍的各种运算都是以字节作为最基本位进行的。 但在很多系统程序中常要求在位(bit)一级进行运算或处理。C语言提供了位运算的功能， 这使得C语言也能像汇编语言一样用来编写系统程序。 <br /><br />　　 一、位运算符C语言提供了六种位运算符： <br /><br />　　 &amp; 按位与 <br />　　 | 按位或 <br />　　 ^ 按位异或 <br />　　 ~ 取反 <br />　　 &lt;&lt; 左移 <br />　　 &gt;&gt; 右移 <br /><br />　　 1. 按位与运算 按位与运算符"&amp;"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时，结果位才为1 ，否则为0。参与运算的数以补码方式出现。 <br /><br />　　 例如：9&amp;5可写算式如下： 00001001 (9的二进制补码)&amp;00000101 (5的二进制补码)　00000001 (1的二进制补码)可见9&amp;5=1。 <br /><br />　　 按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 ， 保留低八位， 可作 a&amp;255 运算 ( 255 的二进制数为0000000011111111)。 <br /><br />main(){ <br />　 int a=9,b=5,c; <br />　 c=a&amp;b; <br />　 printf("a=%d\nb=%d\nc=%d\n",a,b,c); <br />} <br /><br />　　 2. 按位或运算 按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时，结果位就为1。参与运算的两个数均以补码出现。 <br /><br />　　 例如：9|5可写算式如下： <br /><br />00001001|00000101 <br />00001101 (十进制为13)可见9|5=13 <br />main(){ <br />　 int a=9,b=5,c; <br />　 c=a|b; <br />　 printf("a=%d\nb=%d\nc=%d\n",a,b,c); <br />} <br /><br />　　 3. 按位异或运算 按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或，当两对应的二进位相异时，结果为1。参与运算数仍以补码出现，例如9^5可写成算式如下： <br /><br />00001001^00000101 00001100 (十进制为12) <br />main(){ <br />　 int a=9; <br />　 a=a^15; <br />　 printf("a=%d\n",a); <br />} <br /><br />　　 4. 求反运算 求反运算符～为单目运算符，具有右结合性。 其功能是对参与运算的数的各二进位按位求反。例如～9的运算为： ~(0000000000001001)结果为：1111111111110110 <br /><br />　　 5. 左移运算 左移运算符“&lt;&lt;”是双目运算符。其功能把“&lt;&lt; ”左边的运算数的各二进位全部左移若干位，由“&lt;&lt;”右边的数指定移动的位数， <br /><br />　　 高位丢弃，低位补0。例如： a&lt;&lt;4 指把a的各二进位向左移动4位。如a=00000011(十进制3)，左移4位后为00110000(十进制48)。6. 右移运算 右移运算符“&gt;&gt;”是双目运算符。其功能是把“&gt;&gt; ”左边的运算数的各二进位全部右移若干位，“&gt;&gt;”右边的数指定移动的位数。 <br /><br />　　 例如：设 a=15，a&gt;&gt;2　表示把000001111右移为00000011(十进制3)。 应该说明的是，对于有符号数，在右移时，符号位将随同移动。当为正数时， 最高位补0，而为负数时，符号位为1，最高位是补0或是补1 取决于编译系统的规定。Turbo C和很多系统规定为补1。 <br /><br />main(){ <br />　 unsigned a,b; <br />　 printf("input a number: "); <br />　 scanf("%d",&amp;a); <br />　 b=a&gt;&gt;5; <br />　 b=b&amp;15; <br />　 printf("a=%d\tb=%d\n",a,b); <br />} <br /><br />　　 请再看一例! <br /><br />main(){ <br />　 char a='a',b='b'; <br />　 int p,c,d; <br />　 p=a; <br />　 p=(p&lt;&lt;8)|b; <br />　 d=p&amp;0xff; <br />　 c=(p&amp;0xff00)&gt;&gt;8; <br />　 printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d); <br />} <br /><img src ="http://www.cppblog.com/sunraiing9/aggbug/20859.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-29 12:35 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/29/20859.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc中的数据类型 </title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/25/20581.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sun, 25 Mar 2007 15:59:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/25/20581.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20581.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/25/20581.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20581.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20581.html</trackback:ping><description><![CDATA[
		<h2>
				<a id="viewpost1_TitleUrl" href="http://www.cnblogs.com/hone/archive/2004/09/24/46213.html">vc中的数据类型</a>
		</h2>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
				<div>
						<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						<span style="COLOR: #000000">1</span>
						<span style="COLOR: #000000">、CString to </span>
						<span style="COLOR: #0000ff">char</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000">经过类型强制转换，可以将CString类型转换成char*，例如：</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
						<span style="COLOR: #000000">CString cStr </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Hello,world!</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #0000ff">char</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> zStr </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">char</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">)(LPCTSTR)cStr;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> cstring与int转换</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> StringToInt(CString source)<br /><img id="Codehighlighter1_170_293_Open_Image" onclick="this.style.display='none'; Codehighlighter1_170_293_Open_Text.style.display='none'; Codehighlighter1_170_293_Closed_Image.style.display='inline'; Codehighlighter1_170_293_Closed_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_170_293_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_170_293_Closed_Text.style.display='none'; Codehighlighter1_170_293_Open_Image.style.display='inline'; Codehighlighter1_170_293_Open_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
						<span id="Codehighlighter1_170_293_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cnblogs.com/Images/dot.gif" />
						</span>
						<span id="Codehighlighter1_170_293_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">char</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">*</span>
								<span style="COLOR: #000000">buff </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> source.GetBuffer(source.GetLength());<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000"> i </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> atoi(buff);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />    source.ReleaseBuffer();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> i;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
				</div>
		</div>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
				<div>
						<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						<span style="COLOR: #000000">2</span>
						<span style="COLOR: #000000">、</span>
						<span style="COLOR: #0000ff">char</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> to CString<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000">char*类型可以直接给CString，完成自动转换，例如：</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">char</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> zStr </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Hello,world!</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />CString cStr </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> zStr;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #000000">3</span>
						<span style="COLOR: #000000">、CString to LPCSTR<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000">将CString转换成LPCSTR，需要获得CString的长度CString cStr = _T("Hello,world!");</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> nLen </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> cStr.GetLength();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />LPCSTR lpszBuf </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> cStr.GetBuffer(nLen);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #000000">4</span>
						<span style="COLOR: #000000">、CString to LPSTR<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000">这个和第3个技巧是一样的，例如：</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />
						</span>
						<span style="COLOR: #000000">CString cStr </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> _T(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Hello,world!</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> nLen </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> str.GetLength();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" />LPSTR lpszBuf </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> str.GetBuffer(nLen);</span>
				</div>
		</div>在vc中关于类型的转换比较麻烦，新手开发vc程序遇到的第一个问题往往和这个有关。<br />近日从网上以及自己的经验,搜索了一些相关资料。<br /><font style="BACKGROUND-COLOR: #d3d3d3"><strong>PCXSTR</strong>，如果不是在 Unicode 下，<b>PCXSTR </b>与 <b>const char*</b> 是相同的;<br /><strong>CString </strong>作为指向字符的非常数指针来直接访问时，请使用 GetBuffer 和 ReleaseBuffer 成员函数。<br />使用 AllocSysString 和 SetSysString 成员函数来分配和设置用于自动化（以前称为 OLE 自动化）中的 <b>BSTR</b> 对象。<br />一个 <b>CString</b> 对象可存储多达 <b>INT_MAX</b> (2,147,483,647) 个字符。<b>TCHAR</b> 数据类型用来获取或设置 <b>CString</b> 对象中的单个字符。与字符数组不同，<b>CString</b> 类具有内置内存分配能力。 
<p>从 MFC 4.0 版本开始，当复制 CString 对象时，MFC 增加引用计数而不是复制数据。这使得按值传递参数和按值返回 <b>CString</b> 对象更为高效。这些操作将调用复制构造函数，有时甚至不只一次。增加引用计数会减少这些普通操作的系统开销，并且使人更愿意使用 <b>CString</b>。</p><p>随着每个副本的销毁，原对象中的引用计数也会相应减少。直到原 <b>CString</b> 对象的引用计数减少到零时才会销毁该对象。</p><p>可使用 <b>CString</b> 成员函数 LockBuffer 和 UnlockBuffer 来禁用或启用引用计数。<br /></p></font><img src ="http://www.cppblog.com/sunraiing9/aggbug/20581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-25 23:59 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/25/20581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>请达人提示一下</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/22/20348.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Thu, 22 Mar 2007 03:58:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/22/20348.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20348.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/22/20348.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20348.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20348.html</trackback:ping><description><![CDATA[
		<p>最近公司让我写个小模块，完成序列化的底层设计<br /><br />现在XMLFormatter已经完成，要继续完成BinaryFormatter<br /><br />在网上搜索了一下，到处都是关于framework里面Formatter的使用的说明，没有原理方面的介绍，实在不知道该如何下手<br /><br />基本就是要实现将类转换成二进制信息序列化进文件里面<br />   <br />String str;<br /><br />BinaryFormatter xml;</p>
		<p>File file;<br />xml.Serialize(&amp;file,&amp;str);<br /><br />呵呵 还有反序列化 省略了<br /></p>
		<p>
				<br /> </p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/20348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-22 11:58 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/22/20348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中文件流的操作方法</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/21/20299.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 21 Mar 2007 08:12:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/21/20299.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20299.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/21/20299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20299.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20299.html</trackback:ping><description><![CDATA[hehe,做点记载  转的<br /><br /><br /><br /><br />在C++中，有一个stream这个类，所有的I/O都以这个“流”类为基础的，包括我们要认识的文件I/O，stream这个类有两个重要的运算符： <br /><br />1、插入器(&lt;&lt;) <br />向流输出数据。比如说系统有一个默认的标准输出流(cout)，一般情况下就是指的显示器，所以，cout&lt;&lt;"Write Stdout"&lt;&lt;'n';就表示把字符串"Write Stdout"和换行字符('n')输出到标准输出流。 <br /><br />2、析取器(&gt;&gt;) <br />从流中输入数据。比如说系统有一个默认的标准输入流(cin)，一般情况下就是指的键盘，所以，cin&gt;&gt;x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。 <br /><br />在C++中，对文件的操作是通过stream的子类fstream(file stream)来实现的，所以，要用这种方式操作文件，就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。 <br /><br />一、打开文件 <br />在fstream类中，有一个成员函数open()，就是用来打开文件的，其原型是： <br /><br />void open(const char* filename,int mode,int access); <br /><br />参数： <br /><br />filename： 要打开的文件名 <br />mode： 要打开文件的方式 <br />access： 打开文件的属性 <br />打开文件的方式在类ios(是所有流式I/O类的基类)中定义，常用的值如下： <br /><br />ios::app： 以追加的方式打开文件 <br />ios::ate： 文件打开后定位到文件尾，ios:app就包含有此属性 <br />ios::binary： 以二进制方式打开文件，缺省的方式是文本方式。两种方式的区别见前文 <br />ios::in： 文件以输入方式打开 <br />ios::out： 文件以输出方式打开 <br />ios::nocreate： 不建立文件，所以文件不存在时打开失败 <br />ios::noreplace：不覆盖文件，所以打开文件时如果文件存在失败 <br />ios::trunc： 如果文件存在，把文件长度设为0 <br />可以用“或”把以上属性连接起来，如ios::out|ios::binary <br /><br />打开文件的属性取值是： <br /><br />0：普通文件，打开访问 <br />1：只读文件 <br />2：隐含文件 <br />4：系统文件 <br />可以用“或”或者“+”把以上属性连接起来 ，如3或1|2就是以只读和隐含属性打开文件。 <br /><br />例如：以二进制输入方式打开文件c:config.sys <br /><br />fstream file1; <br />file1.open("c:config.sys",ios::binary|ios::in,0); <br /><br />如果open函数只有文件名一个参数，则是以读/写普通文件打开，即： <br /><br />file1.open("c:config.sys");&lt;=&gt;file1.open("c:config.sys",ios::in|ios::out,0); <br /><br />另外，fstream还有和open()一样的构造函数，对于上例，在定义的时侯就可以打开文件了： <br /><br />fstream file1("c:config.sys"); <br /><br />特别提出的是，fstream有两个子类：ifstream(input file stream)和ofstream(outpu file stream)，ifstream默认以输入方式打开文件，而ofstream默认以输出方式打开文件。 <br /><br />ifstream file2("c:pdos.def");//以输入方式打开文件 <br />ofstream file3("c:x.123");//以输出方式打开文件 <br /><br />所以，在实际应用中，根据需要的不同，选择不同的类来定义：如果想以输入方式打开，就用ifstream来定义；如果想以输出方式打开，就用ofstream来定义；如果想以输入/输出方式来打开，就用fstream来定义。 <br /><br />二、关闭文件 <br />打开的文件使用完成后一定要关闭，fstream提供了成员函数close()来完成此操作，如：file1.close();就把file1相连的文件关闭。 <br /><br />三、读写文件 <br />读写文件分为文本文件和二进制文件的读取，对于文本文件的读取比较简单，用插入器和析取器就可以了；而对于二进制的读取就要复杂些，下要就详细的介绍这两种方式 <br /><br />1、文本文件的读写 <br />文本文件的读写很简单：用插入器(&lt;&lt;)向文件输出；用析取器(&gt;&gt;)从文件输入。假设file1是以输入方式打开，file2以输出打开。示例如下： <br /><br />file2&lt;&lt;"I Love You";//向文件写入字符串"I Love You" <br />int i; <br />file1&gt;&gt;i;//从文件输入一个整数值。 <br /><br />这种方式还有一种简单的格式化能力，比如可以指定输出为16进制等等，具体的格式有以下一些 <br /><br />操纵符 功能 输入/输出 <br />dec 格式化为十进制数值数据 输入和输出 <br />endl 输出一个换行符并刷新此流 输出 <br />ends 输出一个空字符 输出 <br />hex 格式化为十六进制数值数据 输入和输出 <br />oct 格式化为八进制数值数据 输入和输出 <br />setpxecision(int p) 设置浮点数的精度位数 输出 <br /><br />比如要把123当作十六进制输出：file1&lt;&lt;hex&lt;&lt;123;要把3.1415926以5位精度输出：file1&lt;&lt;setpxecision(5)&lt;&lt;3.1415926。 <br /><br />2、二进制文件的读写 <br />①put() <br />put()函数向流写入一个字符，其原型是ofstream &amp;put(char ch)，使用也比较简单，如file1.put('c');就是向流写一个字符'c'。 <br /><br />②get() <br />get()函数比较灵活，有3种常用的重载形式： <br /><br />一种就是和put()对应的形式：ifstream &amp;get(char &amp;ch);功能是从流中读取一个字符，结果保存在引用ch中，如果到文件尾，返回空字符。如file2.get(x);表示从文件中读取一个字符，并把读取的字符保存在x中。 <br /><br />另一种重载形式的原型是： int get();这种形式是从流中返回一个字符，如果到达文件尾，返回EOF，如x=file2.get();和上例功能是一样的。 <br /><br />还有一种形式的原型是：ifstream &amp;get(char *buf,int num,char delim='n')；这种形式把字符读入由 buf 指向的数组，直到读入了 num 个字符或遇到了由 delim 指定的字符，如果没使用 delim 这个参数，将使用缺省值换行符'n'。例如： <br /><br />file2.get(str1,127,'A');//从文件中读取字符到字符串str1，当遇到字符'A'或读取了127个字符时终止。 <br /><br />③读写数据块 <br />要读写二进制数据块，使用成员函数read()和write()成员函数，它们原型如下： <br /><br />read(unsigned char *buf,int num); <br />write(const unsigned char *buf,int num); <br /><br />read()从文件中读取 num 个字符到 buf 指向的缓存中，如果在还未读入 num 个字符时就到了文件尾，可以用成员函数 int gcount();来取得实际读取的字符数；而 write() 从buf 指向的缓存写 num 个字符到文件中，值得注意的是缓存的类型是 unsigned char *，有时可能需要类型转换。 <br /><br />例： <br /><br />unsigned char str1[]="I Love You"; <br />int n[5]; <br />ifstream in("xxx.xxx"); <br />ofstream out("yyy.yyy"); <br />out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中 <br />in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数，注意类型转换 <br />in.close();out.close(); <br /><br />四、检测EOF <br />成员函数eof()用来检测是否到达文件尾，如果到达文件尾返回非0值，否则返回0。原型是int eof(); <br /><br />例： if(in.eof())ShowMessage("已经到达文件尾！"); <br /><br />五、文件定位 <br />和C的文件操作方式不同的是，C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针，它说明输入操作在文件中的位置；另一个是写指针，它下次写操作的位置。每次执行输入或输出时，相应的指针自动变化。所以，C++的文件定位分为读位置和写位置的定位，对应的成员函数是 seekg()和 seekp()，seekg()是设置读位置，seekp是设置写位置。它们最通用的形式如下： <br /><br />istream &amp;seekg(streamoff offset,seek_dir origin); <br />ostream &amp;seekp(streamoff offset,seek_dir origin); <br /><br />streamoff定义于 iostream.h 中，定义有偏移量 offset 所能取得的最大值，seek_dir 表示移动的基准位置，是一个有以下值的枚举： <br /><br />ios::beg： 文件开头 <br />ios::cur： 文件当前位置 <br />ios::end： 文件结尾 <br />这两个函数一般用于二进制文件，因为文本文件会因为系统对字符的解释而可能与预想的值不同。 <br /><br />例： <br /><br />file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节 <br />file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节 <br /><br /><img src ="http://www.cppblog.com/sunraiing9/aggbug/20299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-21 16:12 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/21/20299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MultiByteToWideChar和WideCharToMultiByte用法详解 </title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/21/20281.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 21 Mar 2007 04:01:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/21/20281.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20281.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/21/20281.html#Feedback</comments><slash:comments>41</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20281.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20281.html</trackback:ping><description><![CDATA[
		<div class="postTitle">
				<a href="">
						<img height="13" src="http://blog.csdn.net/images/authorship.gif" width="15" border="0" /> MultiByteToWideChar和WideCharToMultiByte用法详解</a>
		</div>
		<div class="postText">//========================================================================<br />//TITLE:<br />//    MultiByteToWideChar和WideCharToMultiByte用法详解<br />//AUTHOR:<br />//    norains<br />//DATE:<br />//    第一版:Monday  25-December -2006<br />//    增补版:Wednesday 27-December -2006<br />//    修订版:Wednesday 14-March-2007 (修正之前的错误例子)<br />//Environment:<br />//  EVC4.0 + Standard SDK<br />//========================================================================<br />  <br />1.使用方法详解<br /><br />  在本文开始之处,先简要地说一下何为短字符和宽字符.<br />  所谓的短字符,就是用8bit来表示的字符,典型的应用是ASCII码.而宽字符,顾名思义,就是用16bit表示的字符,典型的有UNICODE.关于windows下的ASCII和UNICODE的更多信息,可以参考这两本经典著作:《windows 程序设计》,《windows 核心编程》.这两本书关于这两种字符都有比较详细的解说.<br />  <br />  宽字符转换为多个短字符是一个难点,不过我们只要掌握到其中的要领,便可如鱼得水.<br />  好吧,那就让我们开始吧.<br />  <br />  这个是我们需要转化的多字节字符串:  <br />  char sText[20] = {"多字节字符串!OK!"};<br />  <br />  我们需要知道转化后的宽字符需要多少个数组空间.虽然在这个里程里面,我们可以直接定义一个20*2宽字符的数组,并且事实上将运行得非常轻松愉快.但假如多字节字符串更多,达到上千个乃至上万个,我们将会发现其中浪费的内存将会越来越多.所以以多字节字符的个数的两倍作为宽字符数组下标的声明绝对不是一个好主意.<br />  所幸,我们能够确知所需要的数组空间.<br />  我们只需要将MultiByteToWideChar()的第四个形参设为-1,即可返回所需的短字符数组空间的个数:<br />  DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, sText, -1, NULL, 0);<br />  <br />  接下来,我们只需要分配响应的数组空间:<br />  wchar_t *pwText;<br />  pwText = new wchar_t[dwNum];<br />  if(!pwText)<br />  {<br />   delete []pwText;<br />  }<br />  <br />  接着,我们就可以着手进行转换了.在这里以转换成ASCII码做为例子:<br />  MultiByteToWideChar (CP_ACP, 0, psText, -1, sText, dwSize);<br />  <br />  最后,使用完毕当然要记得释放占用的内存:<br />  delete []psText;<br />  <br /> <br />  同理,宽字符转为多字节字符的代码如下:  <br />  wchar_t wText[20] = {L"宽字符转换实例!OK!"};<br />  DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);<br />  char *psText;<br />  psText = new char[dwNum];<br />  if(!psText)<br />  {<br />   delete []psText;<br />  }<br />  WideCharToMultiByte (CP_OEMCP,NULL,lpcwszStr,-1,psText,dwNum,NULL,FALSE);<br />  delete []psText;<br />  <br />   如果之前我们已经分配好空间,并且由于字符串较短,可以不理会浪费的空间,仅仅只是想简单地将短字符和宽字符相互转换,那有没有什么简便的方法呢?<br />   WIN32 API里没有符合这种要求的函数,但我们可以自己进行封装:<br />     <br />  //-------------------------------------------------------------------------------------<br />  //Description:<br />  // This function maps a character string to a wide-character (Unicode) string<br />  //<br />  //Parameters:<br />  // lpcszStr: [in] Pointer to the character string to be converted <br />  // lpwszStr: [out] Pointer to a buffer that receives the translated string. <br />  // dwSize: [in] Size of the buffer<br />  //<br />  //Return Values:<br />  // TRUE: Succeed<br />  // FALSE: Failed<br />  // <br />  //Example:<br />  // MByteToWChar(szA,szW,sizeof(szW)/sizeof(szW[0]));<br />  //---------------------------------------------------------------------------------------<br />  BOOL MByteToWChar(LPCSTR lpcszStr, LPWSTR lpwszStr, DWORD dwSize)<br />  {<br />    // Get the required size of the buffer that receives the Unicode <br />    // string. <br />    DWORD dwMinSize;<br />    dwMinSize = MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, NULL, 0);<br />  <br />    if(dwSize &lt; dwMinSize)<br />    {<br />     return FALSE;<br />    }<br />  <br />    <br />    // Convert headers from ASCII to Unicode.<br />    MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, lpwszStr, dwMinSize);  <br />    return TRUE;<br />  }<br />  <br />  //-------------------------------------------------------------------------------------<br />  //Description:<br />  // This function maps a wide-character string to a new character string<br />  //<br />  //Parameters:<br />  // lpcwszStr: [in] Pointer to the character string to be converted <br />  // lpszStr: [out] Pointer to a buffer that receives the translated string. <br />  // dwSize: [in] Size of the buffer<br />  //<br />  //Return Values:<br />  // TRUE: Succeed<br />  // FALSE: Failed<br />  // <br />  //Example:<br />  // MByteToWChar(szW,szA,sizeof(szA)/sizeof(szA[0]));<br />  //---------------------------------------------------------------------------------------<br />  BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize)<br />  {<br />   DWORD dwMinSize;<br />   dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);<br />   if(dwSize &lt; dwMinSize)<br />   {<br />    return FALSE;<br />   }<br />   WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE);<br />   return TRUE;<br />  }<br />  <br />  <br />  使用方法也很简单,示例如下:<br />  wchar_t wText[10] = {L"函数示例"};<br />  char sText[20]= {0};<br />  WCharToMByte(wText,sText,sizeof(sText)/sizeof(sText[0]));<br />  MByteToWChar(sText,wText,sizeof(wText)/sizeof(wText[0]));<br />  <br />  这两个函数的缺点在于无法动态分配内存,在转换很长的字符串时可能会浪费较多内存空间;优点是,在不考虑浪费空间的情况下转换较短字符串非常方便.<br /><br />  <br />2.MultiByteToWideChar()函数乱码的问题<br /><br />  有的朋友可能已经发现,在标准的WinCE4.2或WinCE5.0 SDK模拟器下,这个函数都无法正常工作,其转换之后的字符全是乱码.及时更改MultiByteToWideChar()参数也依然如此.<br />  不过这个不是代码问题,其结症在于所定制的操作系统.如果我们定制的操作系统默认语言不是中文,也会出现这种情况.由于标准的SDK默认语言为英文,所以肯定会出现这个问题.而这个问题的解决,不能在简单地更改控制面板的"区域选项"的"默认语言",而是要在系统定制的时候,选择默认语言为"中文".<br />  系统定制时选择默认语言的位置于:<br />  Platform -&gt; Setting... -&gt; locale -&gt; default language ,选择"中文",然后编译即可.<br /></div>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/20281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-21 12:01 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/21/20281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于gcnew  （转）</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/20/20201.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 20 Mar 2007 04:52:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/20/20201.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/20201.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/20/20201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/20201.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/20201.html</trackback:ping><description><![CDATA[关于gcnew   (转)<br /><br /><br />C++/CLI中使用gcnew关键字表示在托管堆上分配内存，并且为了与以前的指针区分，用^来替换* ，就语义上来说他们的区别大致如下:<br /><div></div><div><br />　　1.     gcnew返回的是一个句柄(Handle)，而new返回的是实际的内存地址. <br /></div><div>　　2.     gcnew创建的对象由虚拟机托管，而new创建的对象必须自己来管理和释放.</div><div> </div><div>　　当然，从程序员的角度来说，管它是句柄还是什么其他的东西，总跑不掉是对某块内存地址的引用，实际上我们都可以理解成指针.下面我们就写一段代码来测试一下好了.</div><div> </div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div align="left">using namespace System;</div><div align="left"> </div><div align="left">ref class Foo</div><div align="left">{</div><div align="left">public:</div><div align="left">    Foo()</div><div align="left">    {</div><div align="left">       System::Console::WriteLine("Foo::Foo");</div><div align="left">    }</div><div align="left">    ~Foo()</div><div align="left">    {</div><div align="left">       System::Console::WriteLine("Foo::~Foo");</div><div align="left">    }</div><div align="left">public:</div><div align="left">    int m_iValue;</div><div align="left">};</div><div align="left"> </div><div align="left">int _tmain()</div><div align="left">{</div><div align="left">    int* pInt = new int;</div><div align="left">    int^ rInt = gcnew int;</div><div align="left">    Foo^ rFoo = gcnew Foo;</div><div align="left"> </div><div align="left">    delete rFoo; </div><div align="left">    delete rInt;</div><div align="left">    delete pInt;</div><div>} </div></td></tr></tbody></table><div> </div><div>　　我把调试的时候JIT编译的汇编代码择录了部分如下显示（请注意红色部分）：<br /><br /></div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div align="left">    int* pInt = new int;</div><div align="left">0000004c  mov         ecx，4 </div><div align="left">00000051  call        dword ptr ds:[03B51554h] </div><div align="left">00000057  mov         esi，eax </div><div align="left">00000059  mov         dword ptr [esp+18h]，esi </div><div align="left">    int^ rInt = gcnew int;</div><div align="left">0000005d  mov         ecx，788EF9D8h </div><div align="left">00000062  call        FCFAF66C </div><div align="left">00000067  mov         esi，eax </div><div align="left">00000069  mov         dword ptr [esi+4]，0 </div><div align="left">00000070  mov         edi，esi </div><div align="left">    Foo^ rFoo = gcnew Foo;</div><div align="left">00000072  mov         ecx，3B51768h </div><div align="left">00000077  call        FCFAF66C </div><div align="left">0000007c  mov         esi，eax </div><div align="left">0000007e  mov         ecx，esi </div><div align="left">00000080  call        dword ptr ds:[03B517ACh] </div><div align="left">00000086  mov         dword ptr [esp+1Ch]，esi </div><div align="left"> </div><div align="left">    delete rFoo; </div><div align="left">0000008a  mov         ebx，dword ptr [esp+1Ch] </div><div align="left">0000008e  test        ebx，ebx </div><div align="left">00000090  je          000000A4 </div><div align="left">00000092  mov         ecx，ebx </div><div align="left">00000094  call        dword ptr ds:[03FD0028h] </div><div align="left">0000009a  mov         dword ptr [esp+14h]，0 </div><div align="left">000000a2  jmp         000000AC </div><div align="left">000000a4  mov         dword ptr [esp+14h]，0 </div><div align="left">    delete rInt;</div><div align="left">000000ac  mov         edx，edi </div><div align="left">000000ae  mov         ecx，788F747Ch </div><div align="left">000000b3  call        FC8D20FD </div><div align="left">000000b8  mov         ebp，eax </div><div align="left">000000ba  test        ebp，ebp </div><div align="left">000000bc  je          000000D0 </div><div align="left">000000be  mov         ecx，ebp </div><div align="left">000000c0  call        dword ptr ds:[03FD0020h] </div><div align="left">000000c6  mov         dword ptr [esp+10h]，0 </div><div align="left">000000ce  jmp         000000D8 </div><div align="left">000000d0  mov         dword ptr [esp+10h]，0 </div><div align="left">    delete pInt;</div><div align="left">000000d8  mov         ecx，dword ptr [esp+18h] </div><div align="left">000000dc  call        dword ptr ds:[03B51540h] </div><div> </div></td></tr></tbody></table><div> </div><div> 　　我们先看分配内存这部分的代码</div><div> </div><div>　　1．调用new方式分配<br /></div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div>int* pInt = new int;</div><div align="left">0000004c  mov         ecx，4 </div><div>00000051  call        dword ptr ds:[03B51554h]</div></td></tr></tbody></table><div><br />　　可以看到，和以前在vc6中一样，分配内存的步骤如下：<br /></div><div>　　1．  首先把sizeof(int) = 4 放到ecx中<br /></div><div>　　2．  调用operator new 去分配4个字节<br /></div><div>　　3．  调用构造函数等等......(这里不是我们的重点)</div><div><br />　　成功分配后，会把返回地址放在eax中。</div><div> </div><div>　　2．调用gcnew方式分配<br /></div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div align="left">    int^ rInt = gcnew int;</div><div align="left">0000005d  mov         ecx，788EF9D8h </div><div>00000062  call        FCFAF66C</div><div>。。。</div><div align="left">    Foo^ rFoo = gcnew Foo;</div><div align="left">00000072  mov         ecx，3B51768h </div><div>00000077  call        FCFAF66C</div></td></tr></tbody></table><div><br />　　可以看到gcnew也是通过把一个参数放到ecx中，然后再调用一个函数来完成分配的操作，显然0x788EF9D8应该是一个地址，而不可能是一个数值。我们可以看到这里gcnew创建两个不同类型的变量，调用的函数地址却都是0xFCFAF66C，而存放到ecx中的两个地址就不一样。究竟这几个地址代表什么呢？</div><div> </div><div>　　和new一样gcnew也是把返回地址放在eax中。我们直接从内存窗口看eax指向的内存块好了。Aha，看到了没有？</div><div><br />　　这次的eax = 0x00F73404  对应的内存块为</div><div> </div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div>0x00F73404  d8 f9 8e 78 00 00 00 00 。。。</div></td></tr></tbody></table><div> </div><div>　　这个不就是 mov 到 ecx中的值么？再回忆昨天写的分析Object对象布局的文章，可以肯定这个就是 MethodTable地址了，对于这个int来说，后面的4个字节对应的就是存放它的RawData，比如如果你初始化为 4 那么内存对应的就变化为 d8 f9 8e 79 04 00 00 00</div><div> </div><div>　　分析清楚存放到ecx中的是 MethodTable指针，我们再分析那个对应的call函数，从vm的代码可以看出，有三个全局函数用来根据MethodTable创建对象，同时MethodTable本身也提供一个成员函数Allocate()，只不过这个成员函数也是调用的下面的函数：</div><div align="left"><br />OBJECTREF AllocateObject( MethodTable *pMT )</div><div align="left">OBJECTREF AllocateObjectSpecial( MethodTable *pMT )</div><div align="left">OBJECTREF FastAllocateObject( MethodTable *pMT )</div><div> </div><div>　　其中AllocateObject又是调用AllocateObjectSpecial来完成工作。那么我们调用的应该就是AllocateObject或者FastAllocateObject了。</div><div><br />　　在我们的例子里面两个call的地址都一样，但是你如果写下代码 double ^ pDouble = gcnew double;这个时候的地址是多少？它和int 的一样么？</div><div><br />　　目前我还没有仔细去研究这个地址到底对应的是该类型的MethodTable::Allocate()或是上面的这三个全局函数，如果对应MethodTable::Allocate()，那么2.0中应该有个MethodTable::FastAllocate()吧，否则应该就是对应的全局函数AllocateObject 以及FastAllocateObject了。过几天一定要抽空再好好研究一下。</div><div> </div><div>　　下面看对应的delete函数。<br /></div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div align="left">    delete pInt;</div><div align="left">000000d8  mov         ecx，dword ptr [esp+18h] </div><div>000000dc  call        dword ptr ds:[03B51540h]</div><div> </div><div>比较简单，就是传入地址，然后调用operator delete来释放类存，会调用析构函数</div></td></tr></tbody></table><div> </div><div>　　对应的，释放gcnew创建的对象的代码如下：<br /></div><table cellspacing="0" cellpadding="0" align="center" border="1"><tbody><tr><td valign="top" width="568"><div align="left">    delete rInt;</div><div align="left">000000ac  mov         edx，edi </div><div align="left">000000ae  mov         ecx，788F747Ch </div><div>000000b3  call        FC8D20FD</div></td></tr></tbody></table><div><br />　　这个也相对简单，它对应vm里面的一个函数：<br /></div><div align="left">void  CallFinalizer(Thread* FinalizerThread， Object* fobj)</div><div><br />　　那么也就是<br /></div><div>fobjà edx</div><div>FinalizerThread à ecx</div><div>Call CallFinalizer</div><div> </div><div>　　但是，请注意！！！！！！！一个类包含析构函数和不包含析构函数，它对应的delete代码是不一样的，这点可以通过汇编代码比较得到，我这里就不多说了。</div><img src ="http://www.cppblog.com/sunraiing9/aggbug/20201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-20 12:52 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/20/20201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>debug调试中，AssertValid和Dump   这两个函数怎么进行工作的？</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19370.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 07 Mar 2007 08:41:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19370.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19370.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19370.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19370.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19370.html</trackback:ping><description><![CDATA[&lt;转自csdn相关问题回复&gt;<br /><br />CObject::AssertValid   成员函数提供对对象内部状态的运行时检查。尽管从   CObject   派生类时不需要重写   AssertValid，但可以通过重写使您的类更安全可靠。AssertValid   应在对象的所有成员变量上执行断言，以验证它们包含有效值。例如，它应检查指针成员变量不为   NULL。   <br />    <br />  下面的示例显示如何声明   AssertValid   函数：   <br />  class   CPerson   :   public   CObject   <br />  {   <br />  protected:   <br />        CString   m_strName;   <br />        float       m_salary;   <br />  public:   <br />  #ifdef   _DEBUG   <br />        virtual   void   AssertValid()   const;       //   Override   <br />  #endif   <br />        //   ...   <br />  };   <br />  当重写   AssertValid   时，在执行您自己的检查之前请调用   AssertValid   的基类版本。然后使用   ASSERT   宏检查您的派生类特有的成员，如下所示：   <br />    <br />  #ifdef   _DEBUG   <br />  void   CPerson::AssertValid()   const   <br />  {   <br />        //   call   inherited   AssertValid   first   <br />        CObject::AssertValid();   <br />    <br />        //   check   CPerson   members...   <br />        ASSERT(   !m_strName.IsEmpty());   //   Must   have   a   name   <br />        ASSERT(   m_salary   &gt;   0   );   //   Must   have   an   income   <br />  }   <br />  #endif   <br />  如果任何成员变量存储对象，则可以使用   ASSERT_VALID   宏测试它们的内部有效性（如果它们的类重写了   AssertValid）。   <br />    <br />  例如，考虑   CMyData   类，该类在其成员变量之一中存储了一个   CObList。CObList   变量   m_DataList   存储了一个   CPerson   对象的集合。CMyData   的简化声明如下所示：   <br />    <br />  class   CMyData   :   public   CObject   <br />  {   <br />        //   Constructor   and   other   members   ...   <br />        protected:   <br />              CObList*   m_pDataList;   <br />        //   Other   declarations   ...   <br />        public:   <br />  #ifdef   _DEBUG   <br />              virtual   void   AssertValid(   )   const;   //   Override   <br />  #endif   <br />        //   Etc.   ...   <br />  };   <br />  CMyData   中重写的   AssertValid   如下所示：   <br />    <br />  #ifdef   _DEBUG   <br />  void   CMyData::AssertValid(   )   const   <br />  {   <br />        //   Call   inherited   AssertValid   <br />        CObject::AssertValid(   );   <br />        //   Check   validity   of   CMyData   members   <br />        ASSERT_VALID(   m_pDataList   );   <br />        //   ...   <br />  }   <br />  #endif   <br />  CMyData   使用   AssertValid   机制测试其数据成员中存储的对象的有效性。CMyData   中重写的   AssertValid   为它自己的   m_pDataList   成员变量调用   ASSERT_VALID   宏。   <br />    <br />  因为   CObList   类也重写   AssertValid，所以有效性测试不在该级别停止。该重写对列表的内部状态执行附加有效性测试。因此，对   CMyData   对象的有效性测试将导致对存储的   CObList   列表对象内部状态的附加有效性测试。   <br />    <br />  再多进行一些操作，还可以添加对存储在列表中的   CPerson   对象的有效性测试。可以从   CObList   派生   CPersonList   类，并重写   AssertValid。在重写中可调用   CObject::AssertValid，然后循环访问列表，在列表中存储的每个   CPerson   对象上调用   AssertValid。本主题开始所示的   CPerson   类已重写了   AssertValid。   <br />    <br />  当为调试生成时，这是一种功能极强的机制。当接着为发布生成时，该机制自动关闭。   <br />    <br />  AssertValid   的限制   <br />  给定类的   AssertValid   函数的用户应注意该函数的限制。触发的断言指示对象一定有误，并且执行将暂停。但是，缺少断言只指示未找到任何问题，并不保证对象是好的。   <br /><br />当从   CObject   派生类时，在使用   DumpAllObjectsSince   将对象转储到“输出”窗口时，可以重写   Dump   成员函数以提供附加信息。   <br />    <br />  Dump   函数将对象的成员变量的文本化表示形式写入转储上下文   (CDumpContext)。转储上下文类似于   I/O   流。可以使用插入运算符   (&lt;&lt;)   向   CDumpContext   发送数据。   <br />    <br />  重写   Dump   函数时，应先调用   Dump   的基类版本以转储基类对象的内容。然后为派生类的每个成员变量输出文本化说明和值。   <br />    <br />  Dump   函数的声明如下所示：   <br />    <br />  class   CPerson   :   public   CObject   <br />  {   <br />  public:   <br />  #ifdef   _DEBUG   <br />        virtual   void   Dump(   CDumpContext&amp;   dc   )   const;   <br />  #endif   <br />    <br />        CString   m_firstName;   <br />        CString   m_lastName;   <br />        //   And   so   on...   <br />  };   <br />  由于对象转储只在调试程序时有意义，所以   Dump   函数的声明用   #ifdef   _DEBUG   /   #endif   块括起来。   <br />    <br />  在下面的示例中，Dump   函数先为其基类调用   Dump   函数。然后，它将每个成员变量的简短说明与该成员的值一起写入诊断流。   <br />    <br />  #ifdef   _DEBUG   <br />  void   CPerson::Dump(   CDumpContext&amp;   dc   )   const   <br />  {   <br />        //   Call   the   base   class   function   first.   <br />        CObject::Dump(   dc   );   <br />    <br />        //   Now   do   the   stuff   for   our   specific   class.   <br />        dc   &lt;&lt;   "last   name:   "   &lt;&lt;   m_lastName   &lt;&lt;   "\n"   <br />              &lt;&lt;   "first   name:   "   &lt;&lt;   m_firstName   &lt;&lt;   "\n";   <br />  }   <br />  #endif   <br />  必须提供   CDumpContext   参数以指定转储输出的目的地。MFC   的“Debug”版本提供名为   afxDump   的预定义   CDumpContext   对象，它将输出发送到调试器。   <br />    <br />  CPerson*   pMyPerson   =   new   CPerson;   <br />  //   Set   some   fields   of   the   CPerson   object.   <br />  //...   <br />  //   Now   dump   the   contents.   <br />  #ifdef   _DEBUG   <br />  pMyPerson-&gt;Dump(   afxDump   );   <br />  #endif   <br />  在   MFC   程序中，可以使用   DumpAllObjectsSince   转储有关堆中尚未释放的所有对象的说明。DumpAllObjectsSince   转储自上个   CMemoryState::Checkpoint   以来分配的所有对象。如果未发生   Checkpoint   调用，则   DumpAllObjectsSince   将转储当前在内存中的所有对象和非对象。   <br />    <br />  注意       必须先启用诊断跟踪，然后才能使用   MFC   对象转储。   <br />  注意       程序退出时   MFC   将自动转储所有泄漏的对象，因此不必创建代码在该点转储对象。   <br />  以下代码通过比较两个内存状态来测试内存泄漏，并在检测到泄漏时转储所有对象：   <br />    <br />  if(   diffMemState.Difference(   oldMemState,   newMemState   )   )   <br />  {   <br />        TRACE(   "Memory   leaked!\n"   );   <br />        diffMemState.DumpAllObjectsSince();   <br />  }   <br />  转储的内容如下所示：   <br />    <br />  Dumping   objects   -&gt;   <br />    <br />  {5}   strcore.cpp(80)   :   non-object   block   at   $00A7521A,   9   bytes   long   <br />  {4}   strcore.cpp(80)   :   non-object   block   at   $00A751F8,   5   bytes   long   <br />  {3}   strcore.cpp(80)   :   non-object   block   at   $00A751D6,   6   bytes   long   <br />  {2}   a   CPerson   at   $51A4   <br />    <br />  Last   Name:   Smith   <br />  First   Name:   Alan   <br />  Phone   #:   581-0215   <br />    <br />  {1}   strcore.cpp(80)   :   non-object   block   at   $00A7516E,   25   bytes   long   <br />  大多数行开始处的大括号中的数字指定对象的分配顺序。最近分配的对象具有最高编号，并显示在转储的顶部。   <br />  <img src ="http://www.cppblog.com/sunraiing9/aggbug/19370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-07 16:41 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/07/19370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LPSTR LPCSTR LPWSTR LPCWSTR区别</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19351.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 07 Mar 2007 04:06:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19351.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19351.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19351.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19351.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19351.html</trackback:ping><description><![CDATA[  LPSTR   一个32位的指向字符串的指针   <br />  LPCSTR   一个32位的指向字符串常量的指针   <br />  LPWSTR   一个32位的指向unicode字符串的指针   <br />  LPCWSTR   个32位的指向unicode字符串常量的指针   <br />    <br />  前面的L代表LONG,P就是指针的意思,C就是constant的意思   <br />  W是wide的意思，STR就是string的意思   <br /><br /><img src ="http://www.cppblog.com/sunraiing9/aggbug/19351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-07 12:06 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/07/19351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>#if _MSC_VER &gt; 1000</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19346.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 07 Mar 2007 03:25:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19346.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19346.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/07/19346.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19346.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19346.html</trackback:ping><description><![CDATA[
		<p>自己对<br />#if _MSC_VER &gt; 1000<br />#pragma once<br />#endif // _MSC_VER &gt; 1000用法不清楚  找些资料做些总结<br /><br />当编译器版本号大于1000的时候，改.h文件只包含一次，是这样吗？<br /><br /><br /><br />解析#pragma指令     <br />  在所有的预处理指令中，#Pragma   指令可能是最复杂的了，它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。     <br />  其格式一般为:   #Pragma   Para     <br />  其中Para   为参数，下面来看一些常用的参数。     <br />    <br />  (1)message   参数。   Message   参数是我最喜欢的一个参数，它能够在编译信息输出窗     <br />  口中输出相应的信息，这对于源代码信息的控制是非常重要的。其使用方法为：     <br />  #Pragma   message(“消息文本”)     <br />  当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。     <br />  当我们在程序中定义了许多宏来控制源代码版本的时候，我们自己有可能都会忘记有没有正确的设置这些宏，此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法     <br />  #ifdef   _X86     <br />  #Pragma   message(“_X86   macro   activated!”)     <br />  #endif     <br />  当我们定义了_X86这个宏以后，应用程序在编译时就会在编译输出窗口里显示“_     <br />  X86   macro   activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了     <br />  。     <br />    <br />  (2)另一个使用得比较多的pragma参数是code_seg。格式如：     <br />  #pragma   code_seg(   ["section-name"[,"section-class"]   ]   )     <br />  它能够设置程序中函数代码存放的代码段，当我们开发驱动程序的时候就会使用到它。     <br />    <br />  (3)#pragma   once   (比较常用）     <br />  只要在头文件的最开始加入这条指令就能够保证头文件被编译一次，这条指令实际上在VC6中就已经有了，但是考虑到兼容性并没有太多的使用它。     <br />    <br />  (4)#pragma   hdrstop表示预编译头文件到此为止，后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度，但如果所有头文件都进行预编译又可能占太多磁盘空间，所以使用这个选项排除一些头文件。     <br />  有时单元之间有依赖关系，比如单元A依赖单元B，所以单元B要先于单元A编译。你可以用#pragma   startup指定编译优先级，如果使用了#pragma   package(smart_init)   ，BCB就会根据优先级的大小先后编译。     <br />    <br />  (5)#pragma   resource   "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体     <br />  外观的定义。     <br />    <br />  (6)#pragma   warning(   disable   :   4507   34;   once   :   4385;   error   :   164   )     <br />  等价于：     <br />  #pragma   warning(disable:4507   34)   //   不显示4507和34号警告信息     <br />  #pragma   warning(once:4385)   //   4385号警告信息仅报告一次     <br />  #pragma   warning(error:164)   //   把164号警告信息作为一个错误。     <br />  同时这个pragma   warning   也支持如下格式：     <br />  #pragma   warning(   push   [   ,n   ]   )     <br />  #pragma   warning(   pop   )     <br />  这里n代表一个警告等级(1---4)。     <br />  #pragma   warning(   push   )保存所有警告信息的现有的警告状态。     <br />  #pragma   warning(   push,   n)保存所有警告信息的现有的警告状态，并且把全局警告     <br />  等级设定为n。     <br />  #pragma   warning(   pop   )向栈中弹出最后一个警告信息，在入栈和出栈之间所作的     <br />  一切改动取消。例如：     <br />  #pragma   warning(   push   )     <br />  #pragma   warning(   disable   :   4705   )     <br />  #pragma   warning(   disable   :   4706   )     <br />  #pragma   warning(   disable   :   4707   )     <br />  //.......     <br />  #pragma   warning(   pop   )     <br />  在这段代码的最后，重新保存所有的警告信息(包括4705，4706和4707)。     <br />  （7）pragma   comment(...)     <br />  该指令将一个注释记录放入一个对象文件或可执行文件中。     <br />  常用的lib关键字，可以帮我们连入一个库文件。   <br />    <br />  (8)#pragma   pack()     <br />  我们知道在VC中，对于想结构体Struct这样的类型，VC采用8字节对齐的方式，如果我们不想使用8字节对齐（在网络变成中经常需要这样），我们可以在结构体前面加上     <br />  #pragma   pack(1)     <br />  struct     <br />  {     <br />  ......     <br />  }     <br />  #pragma   pack()     <br /></p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/19346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-07 11:25 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/07/19346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC CButton封装的问题</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/06/19266.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Mon, 05 Mar 2007 16:55:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/06/19266.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19266.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/06/19266.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19266.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19266.html</trackback:ping><description><![CDATA[
		<p>我现在想把CButton重新封装下,一开始就遇见了问题,希望大家帮忙指导下<br />////////////////////////////////////////TCButton.h<br />#ifndef TCButton_H_<br />#define TCButton_H_<br />class TCButton:public CButton<br />{<br />public:<br /> //! Standard constructor.<br /> TCButton();<br /> //! Standard destructor.<br /> virtual ~TCButton();<br />};<br />#endif<br /><br />////////////////////////////////////////TCButton.cpp<br />#include "stdafx.h"<br />#include "TCButton.h"<br />TCButton::TCButton()<br />{<br /> Create(_T("My button"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(0,0,40,20), this, 1);<br />}<br />TCButton::~TCButton()<br />{<br />}<br /><br />现在我想在另外的Dailog中使用这个Button的话,我想实现<br /><br />我想在堆内存中TCButton myButton;<br />然后再进行父窗口的指定myButton.SetParent(CWnd* pWnd);<br /><br />这样的效果怎么做啊?<br /><br />如果是new出来的好办,我可以引用带参数的构造函数,传入<br />Create(_T("My button"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(0,0,40,20), this, 1)的第3个参数CWnd* pParentCwnd<br />,但是如果我声明在.h文件中呢  我不知道怎么做 呵呵</p>
		<p>希望能给点提示:)</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/19266.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-06 00:55 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/06/19266.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>女人们的友谊 与 男人们的友谊 （轻松下）</title><link>http://www.cppblog.com/sunraiing9/archive/2007/03/02/19136.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Fri, 02 Mar 2007 10:54:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/03/02/19136.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19136.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/03/02/19136.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19136.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19136.html</trackback:ping><description><![CDATA[
		<p>女人们的友谊：  </p>
		<p>一个女人有一晚没回家  　　  <br />隔天她跟老公说他睡在一个女性朋友那边  　　  <br />她老公打电话给她最好的10个朋友，没有一个知道这件事！  </p>
		<p>男人们的友谊：  <br />一个男人有一晚没回家睡  　　  <br />隔天他跟老婆说他睡在一个兄弟那边  　　  <br />她老婆打电话给他最好的10个朋友，有八个好兄弟确定他老公睡在他们家......  　　  <br />还有2个说“他老公还在他那儿！”  </p>
		<p>某网友的回帖：昨完把此帖给我老婆看，没想到她兴致大发；立刻打电话给我朋友问我是否在他们那里．结果可想而知，再次论证了上诉观点！更离谱的是有一哥们竟然说我在他家喝醉了，正睡着呢，还问我老婆要不要喊我起来接电话？在挂了电话后，那哥们的电话马上打到我手机上，一接通没等我说话就大喊：在哪呢，快回家吧，你老婆找你呢  ！！！</p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/19136.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-03-02 18:54 <a href="http://www.cppblog.com/sunraiing9/archive/2007/03/02/19136.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>friend随笔</title><link>http://www.cppblog.com/sunraiing9/archive/2007/02/28/19056.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 28 Feb 2007 10:00:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/02/28/19056.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19056.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/02/28/19056.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19056.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19056.html</trackback:ping><description><![CDATA[
		<p>//////////////////////TestClass.h<br />#ifndef _TEST_H_<br />#define _TEST_H_</p>
		<p>class TestClass2;<br />class TestClass1<br />{<br />private:<br />       int i;<br />public:<br />       TestClass1()<br />       {<br />              i = 10;<br />       }</p>
		<p>       void ChangePrivate(TestClass2&amp; test,int change_i);</p>
		<p>};</p>
		<p>
				<br />class TestClass2 <br />{<br />private:<br />       int i;<br />public:</p>
		<p>       TestClass2()<br />       {<br />           i = 20;<br />       }</p>
		<p>       friend void TestClass1::ChangePrivate(TestClass2&amp; test,int change_i);<br />};</p>
		<p>#endif<br /><br />///////////////////////////TestClass.cpp<br />#include "stdafx.h"<br />#include "TestClass.h"<br /><br />void TestClass1::ChangePrivate(TestClass2&amp; test,int change_i)<br />{<br />    test.i = change_i;<br />}<br /><br />/////////////////////Main.cpp<br />#include "TestClass.h"<br />using namespace std;</p>
		<p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> <br />       TestClass1 test1;<br />       TestClass2 test2;</p>
		<p>       test1.ChangePrivate(test2,1);</p>
		<p>       getchar();<br />       getchar();<br />       return 0;<br />}</p>
		<p>现在我不明白的是TestClass.cpp里的<br />void TestClass1::ChangePrivate(TestClass2&amp; test,int change_i)<br />{<br />    test.i = change_i;<br />}<br />我如果放在TestClass.h里面  就link错误，如果哪位仁兄能指导下不胜感激，错误提示如下：<br />Generating Code...<br />Linking...<br />TsetClass.obj : error LNK2005: "public: void __thiscall TestClass1::ChangePrivate(class TestClass2 &amp;,int)" (<a href="mailto:?ChangePrivate@TestClass1@@QAEXAAVTestClass2@@H@Z">?ChangePrivate@TestClass1@@QAEXAAVTestClass2@@H@Z</a>) already defined in thinking test.obj<br />E:\随便\thinking test\Debug\thinking test.exe : fatal error LNK1169: one or more multiply defined symbols found<br />Build log was saved at "<a href="file://e:\">file://e:\</a>随便\thinking test\thinking test\Debug\BuildLog.htm"<br />thinking test - 2 error(s), 0 warning(s)<br />========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========<br /><br /></p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/19056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-02-28 18:00 <a href="http://www.cppblog.com/sunraiing9/archive/2007/02/28/19056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>空struct为何有大小？（求解释）</title><link>http://www.cppblog.com/sunraiing9/archive/2007/02/28/19052.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Wed, 28 Feb 2007 08:34:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/02/28/19052.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/19052.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/02/28/19052.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/19052.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/19052.html</trackback:ping><description><![CDATA[
		<p>struct A <br />{<br /> int a;<br /> int b;<br /> int c;<br />};</p>
		<p>struct B <br />{</p>
		<p>};<br />int _tmain(int argc, _TCHAR* argv[])<br />{<br /> cout&lt;&lt;sizeof(A)&lt;&lt;endl;</p>
		<p> cout&lt;&lt;sizeof(B)&lt;&lt;endl;</p>
		<p> getchar();<br /> getchar();<br /> return 0;<br />}</p>
		<p> </p>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/19052.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-02-28 16:34 <a href="http://www.cppblog.com/sunraiing9/archive/2007/02/28/19052.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>完美的C++：C++/CLI</title><link>http://www.cppblog.com/sunraiing9/archive/2007/02/10/18620.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sat, 10 Feb 2007 11:13:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/archive/2007/02/10/18620.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/18620.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/archive/2007/02/10/18620.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/18620.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/18620.html</trackback:ping><description><![CDATA[转自:CSDN   自己做记录  大家不要砸砖头 明年中旬研究这块<br /><br /><br />什么是C++/CLI呢？C++当然指的是Bjarne Stroustrup在BELL实验室发明的C++语言，它实现了运行时取得速度和尺寸最佳化的静态对象模型，然而它除了堆分配外不支持程序的动态修改，它准许无限地接近底层设备，但在程序运行过程中几乎无法操作活动类型，也无法操作与程序相关联的底层结构。Herb Sutter，C++/CLI的主要构造者之一，称C++是一门“混凝土”式的语言。<br /><br />　　CLI指的是通用语言结构，一种支持动态组件编程模型的多重结构，在许多情况下，这代表了一个与C++对象模型完全颠倒了的模式。一个时实的软件层，有效地执行系统，在底层操作系统与程序之间运行。操作底层的设备受到一定的限制，操作执行程序中的活动类型及与程序相关联的下部结构得到了支持。反斜杠（/）代表C++和CLI的捆绑，这个捆绑带来的细节问题是本文主要讨论的问题。<br /><br />　　所以，“什么是C++/CLI”问题的最初、最接近答案是：它是静态C++对象模型到CLI的动态组件对象编程模型的捆绑。简而言之，它就是你如何用C++在.NET中编程，而不是C#或Visual Basic.NET。象C#和CLI本身一样，C++/CLI正在ECMA（欧洲计算机制造商协会）主持下进行标准化，以最终符合ISO标准。<br /><br />　　实时通用语言（CLR）是CLI的微软版本，它非常适用于微软的Windows操作系统，相似地，Visual C++2005是C++/CLI的实现。<br /><br />　　作为第二个近似的答案，我认为C++/CLI是.NET编程模式与C++的结合，正如以前将模板与C++结合起来产生的泛型编程。所有这种结合中，企业所拥有的C++的投资以及开发人员使用C++的经验将得到保存，而这恰恰是使用C++/CLI进行开发的重要基础。<br /><br />　　阅读导航<br /><br />　　学习C++/CLI的方法 <br />　　在设计C++/CLI语言中涉及三个方面问题，这同样贯彻于所有的其他程序开发语言：一是语言级的语法向底层通用类型系统（简称CTS）的映射；二是向程序开发人员提供的CLI的底层细节结构的级别选择；三是超越CLI的直接支持，提供额外的功能性函数的选择。 <br /><br />　　从C++/CLI到CTS的映射？<br />　　使用C++/CLI编程时间了解底层的CTS非常重要。CTS包括以下三种常用类的类型：<br /><br />　　1、多态引用类型，这正是对于所有继承类所要使用的。<br /><br />　　2、非多态值类型，这用于实时高效的具体类型，例如数值类型。<br /><br />　　3、抽象的接口类型，这用于定义一个操作集，也可以用于实现接口的引用或值类型集合。<br /><br />　　CLI的细节<br />　　设计一个CLI语言时第二个必须要考虑的问题是将CLI的底层执行模式融入到语言的细节级别。这种语言用于解决什么问题？这种语言是否有必须的工具来解决这些问题？这种语言可能吸引什么样的程序开发人员？<br /><br />　　存在的问题 <br />　　在垃圾收集器扫描紧缩状态下，位于托管堆上的任何对象非常可能面对重新定位问题。指向对象的指针可以实时跟踪并修改。开发人员不能自己手动跟踪，所以，如果你获许取得一个可能位于托管堆上的值类型的地址时，除了本地指针外，还需要有一个跟踪形态的指针。<br /><br />　　额外增加的功能<br />　　在垃圾收集器扫描紧缩状态下，位于托管堆上的任何对象非常可能面对重新定位问题。指向对象的指针可以实时跟踪并修改。开发人员不能自己手动跟踪，所以，如果你获许取得一个可能位于托管堆上的值类型的地址时，除了本地指针外，还需要有一个跟踪形态的指针。<br /><br />　　小结<br /><br />　　C++/CLI代表托管与本地编程的结合，这种综合已经通过元级相对独立但又相互平等地组件和二进制元素得到了完成，包括混合模式（本地和CTS类型的元级混合，还有一个本地及CLI对象文件的二进制混合），纯模式（本地和CTS类型的源代码级混合，所有的都被编译为CLI对象文件），本地分类（可以通过一个特定的打包类来保持CTS类型），和CTS分类（可以保持本地类型为指针）。<br /><br />　　当然，C++/CLI开发人员也可以单独使用CLI类型来编程，并通过这种方式来提供伺服状态下的可校验代码，例如可以作为SQL Server2005的一个SQL存储过程。<br /><br />　　现在，还是回到这个问题上来，什么是C++/CLI？它是进行.NET编程模式的最佳切入点。对于C++/CLI，有一个来自C++的迁移路径，它不仅包含C++的底层基础，而且也需要C++编程经验，对于这些，我感到非常满意。<br /><br />　　学习C++/CLI的方法 <br /><br />　　在设计C++/CLI语言中涉及三个方面问题，这同样贯彻于所有的其他程序开发语言：一是语言级的语法向底层通用类型系统（简称CTS）的映射；二是向程序开发人员提供的CLI的底层细节结构的级别选择；三是超越CLI的直接支持，提供额外的功能性函数的选择。 <br /><br />　　第一条对于所有的CLI语言来说都大致相同，第二条和第三条对于不同的CLI语言来说是不同的，相互区别的。根据你需要解决什么样的问题，你将选择这种或那种语言，也有可能混合使用多种CLI语言。学习C++/CLI涉及到了解它在设计过程中的所有这些涉及方面。<br /><br />　　从C++/CLI到CTS的映射？<br /><br />　　使用C++/CLI编程时间了解底层的CTS非常重要。CTS包括以下三种常用类的类型：<br /><br />　　1、多态引用类型，这正是对于所有继承类所要使用的。<br /><br />　　2、非多态值类型，这用于实时高效的具体类型，例如数值类型。<br /><br />　　3、抽象的接口类型，这用于定义一个操作集，也可以用于实现接口的引用或值类型集合。<br /><br />　　这个设计方面的问题，即将CTS映射到语言内建的数据类型集合，通常同样贯穿于所有的CLI语言，虽然不同的CLI语言语法不同。所以，在C#中你可能这么写：<br /><br />abstract class Shape { ... } // C# <br /><br />　　来定义了一个Shape基类，从该类将导出几何对象，然而在C++/CLI你将这么写：<br /><br />ref class Shape abstract { ... }; // C++/CLI <br /><br />　　上述代码说明了底层的C++/CLI引用类型。这两种声明在内层代表的意思是一样的。相似地，在C#中你这么写：<br /><br />struct Point2D { ... } // C# <br /><br />　　来定义一个具体的Point2D 类，然而在C++/CLI中这么写：<br /><br />value class Point2D { ... }; // C++/CLI <br /><br />　　C++/CLI支持的类型集合代表了CTS与本地设备的综合，这决定了你的语法选择，例如：<br /><br />class native {};<br />value class V {};<br />ref class R {};<br />interface class I {}; <br /><br />　　CTS也支持与本地列举类型稍微不同的列举类类型。当然，对于上述两者CTS是都支持的。例如：<br /><br />enum native { fail, pass }; <br />enum class CLIEnum : char { fail, pass}; <br /><br />　　相似地，CTS支持它本身的数组类型，并且它再一次将其与本地数组在行为上区分开来。同时，微软再次为这两种类型提供了支持。<br /><br />int native[] = { 1,1,2,3,5,8 }; <br />array&lt;int&gt;^ managed = { 1,1,2,3,5,8 }; <br /><br />　　那种认为一种CLI语言比其他CLI语言在向底层的CTS映射中表现的更出色或更完美都是不确切的，相反，每种不同的CLI语言代表着对CTS底层对象模型的不同理解，在下一节你将更清楚地看到这一点。<br /><br />　　CLI的细节<br /><br />　　设计一个CLI语言时第二个必须要考虑的问题是将CLI的底层执行模式融入到语言的细节级别。这种语言用于解决什么问题？这种语言是否有必须的工具来解决这些问题？这种语言可能吸引什么样的程序开发人员？<br /><br />　　例如，值类型存在于托管堆上，在很多情况下值类型可以看到它们自身的存在。<br /><br />　　1、通过隐含的加箱操作，当一个值类型的实例被分配给一个对象或当一个虚拟的方法通过一个值类型来调用；<br /><br />　　2、当这个值类型被当作应用引用类类型的成员时；<br /><br />　　3、当这个值类型 被当作CLI数组成员时；<br /><br />　　需要指出的是，这种情况下开发人员是否被允许操作值类型的地址是CLI语言设计时必须应该予以考虑的问题。<br /><br />　　存在的问题<br /><br />　　在垃圾收集器扫描紧缩状态下，位于托管堆上的任何对象非常可能面对重新定位问题。指向对象的指针可以实时跟踪并修改。开发人员不能自己手动跟踪，所以，如果你获许取得一个可能位于托管堆上的值类型的地址时，除了本地指针外，还需要有一个跟踪形态的指针。 <br /><br />　　销售商考虑的是什么？那就是需要简单和安全，在语言中直接提供跟踪一个对象或集合的指针使语言复杂化，没有这种支持，将减少复杂程度，可资利用的、潜在的程序开发人群可能会增加，此外，准许程序开发人员操作生命短暂的值类型，增加了错误产生的可能性，程序开发人员可能有意无意地对内存进行错误操作，不支持跟踪指针，一个潜在的更安全地实时环境产生了。<br /><br />　　另一方面，效率和灵活性也是必须考虑的一个问题，每一次向同一个对象分配值类型时，一个全新的数值加箱操作发生了，准许存取加箱值类型允许在内存中进行更新，这可能在性能上产生了一个非常巨大的进步。没有跟踪形态的指针，你无法用指针算法重新声明一个CLI数组，这意味着CLI数组不能使用标准模板库进行重新声明，也不能使用一般的算法。准许操作加箱数值使设计具有更大地灵活性。<br /><br />　　微软在C++/CLI中选择地址集合模式来处理托管堆上的值类型。<br /><br />int ival = 1024;<br />int^ boxedi = ival; <br />array&lt;int&gt;^ ia = gcnew array&lt;int&gt;{1,1,2,3,5,8};<br />interior_ptr&lt;int&gt; begin = &amp;ia[0];<br /><br />value struct smallInt { int m_ival; ... } si;<br />pin_ptr&lt;int&gt; ppi = &amp;si.m_ival; <br /><br />　　典型地C++/CLI开发人员是一个复杂的系统程序员，承担着提供下层内部构造和有组织的应用程序的任务，而这些恰恰是未来商业发展的基础。C++/CLI开发人员必须兼顾可测量性和可执行性，所以必须在系统的高度级上来看待CLI下层结构。CLI细节水平反映了开发人员的脸色。<br /><br />　　复杂性本身并不代表对质量的否定，人类比单细胞细菌复杂的多，这当然不是一件坏事，然而，当表达一个简单的概念变的复杂化后，这常常被认为是一件坏事。在C++/CLI中，CLI开发团队已经试着提供一种精巧的方法来表达方式一个复杂的事情。<br /><br />　　额外增加的功能<br /><br />　　第三个设计方面是特定功能性的语言层，它远远超过CLI所提供的直接支持，虽然这可能需要在语言层支持和CLI底层执行模式间建立一个映射。但在某些情况下，这恰恰是不可能的，因为语言无法调节CLI的行为。这种情况的例子就是在基类的构造及析构函数中定义虚函数。根据ISO-C++在这种情况下的语言学，需要用每一个基类的构造和虚构函数重新设置虚拟表，而这是不可能的，因为虚拟表句柄是实时管理的，而不是某一个语言来管理。<br /><br />　　所以，这个设计方面是在完美性和可行性之间的妥协产物，C++/CLI提供的额外功能主要表现在三个方面：<br /><br />　　1、获取资源的一种形式是对于引用类型的初始化，此外，提供一种自动化工具，用于占用较少资源、所谓的可确定性自动消亡的垃圾收集类型对象。 <br /><br />　　2、一种深度拷贝形式的语法与C++拷贝构造函数和拷贝分配操作符相一致，但其并不适用与值类型。<br /><br />　　3、除了最初的一般性CLI机制外，还有对于CTS类型的C++模板直接支持。这些是我第一篇文章中讨论的主题。此外，还提供了针对CLI类型的可校验STL版本。<br /><br />　　让我们来看一个简单的例子，一个确定性消亡问题。在垃圾搜集器重新声明一块与对象相关联的内存之前，一个相关的消亡方法，如果存在的话，将被调用。你可以认为这种方法是超级析构函数，因为它与对象的程序生命期无关。这就叫做终结。终结函数是否调用以及什么时间调用都没有明确规定，这就是垃圾收集器的非确定性终结。 <br /><br />　　在动态内存管理的情况下，非确定性终结工作非常好，当可用内存变的越来越少时，垃圾收集器介入并开始着手解决问题。然而，非决定性终结也有工作不好的时候，当一个对象维护一个重要资源，例如一个数据库连接、锁定某些类别、或者可能是本地的堆内存。在这种情况下，只要是不需要，应立即释放资源。目前CLI所支持的解决问题的方法是，对于一个类通过执行IDisposable接口提供的Dispose方法释放资源。这里的问题是执行Dispose方法需要一个清晰的声明，所以它也就不可能存在调用。<br /><br />　　最基本的C++中的设计模式是上述的通过初始化来获取资源，这意味着类使用构造函数来获取资源，相反，类使用析构函数来释放资源。这些行为由类对象在生存期内自动管理。<br /><br />　　下面是引用类释放资源时所做的顺序动作：<br /><br />　　1、 首先使用析构函数来封装所有与释放类有关的资源时所必须的代码；<br /><br />　　2、 析构函数自动调用后，结束类对象的生命期。<br /><br />　　对于引用类型来说，CLI没有类析构函数的概念，所以析构函数不得不映射为在底层执行的其它代码。此时，在内部，编译器执行以下操作：<br /><br />　　1、 类让其基类列表继承自IDisposable接口；<br /><br />　　2、 析构函数转换成IDisposable的Dispose方法。<br /><br />　　以上实现了目标的一半，一种实现析构造函数自动调用的方法仍然需要，对于引用类型，一种特殊的基于栈的符号得到支持，也就是说，一个对象的生命期与它的声明范围有关。在内部，编译器将符号转换为在托管堆上分配引用对象。随着作用域的终结，编译器插入一个Dispose方法-用户定义的析构函数。与对象有关的内存的收回在垃圾收集器的控制下得到执行。<br /><br />　　C++/CLI并不是将C++拓展到一个托管的世界，更确切的说，它代表一个完全综合的范例，某种程度上就象当初将泛编程模式和多重继承综合进该语言一样。我认为C++/CLI开发小组做了一项非常卓有成效的工作。<br /><br />　　小结<br /><br />　　C++/CLI代表托管和本地编程的结合。在反复过程中，这种综合已经通过源级相对独立但又相互平等地组件和二进制元素得到了完成，包括混合模式（本地和CTS类型的源级混合，还有一个本地及CLI对象文件的二进制混合），纯模式（本地和CTS类型的源代码级混合，所有的都被编译为CLI对象文件），本地分类（可以通过一个特定的打包类来保持CTS类型），和CTS分类（可以保持本地类型为指针）。<br /><br />　　当然，C++/CLI开发人员也可以单独使用CLI类型来编程，并通过这种方式来提供伺服状态下的可校验代码，例如可以作为SQL Server2005的一个SQL存储过程。<br /><br />　　现在，还是回到这个问题上来，什么是C++/CLI？它是进行.NET编程模式的最佳切入点。对于C++/CLI，有一个来自C++的迁移路径，它不仅包含C++的底层基础，而且也需要C++编程经验，对于这些，我感到非常满意。<img src ="http://www.cppblog.com/sunraiing9/aggbug/18620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2007-02-10 19:13 <a href="http://www.cppblog.com/sunraiing9/archive/2007/02/10/18620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>