﻿<?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/andxie99/category/4403.html</link><description>上学时，因我年龄最小，个头也最小，上课时，就像大猩猩堆里的猴一般。如今，这猴偶尔也把最近的一些情况写在这里。</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 15:50:00 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 15:50:00 GMT</pubDate><ttl>60</ttl><item><title>被误解的C++</title><link>http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Fri, 15 Jun 2007 12:41:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/26396.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/26396.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/26396.html</trackback:ping><description><![CDATA[<p><br>&nbsp;&nbsp;&nbsp; 从CSDN上读到一篇文章，深有同感，原文如下：<br>&nbsp;&nbsp;&nbsp; 传统上认为，C++相对于目前一些新潮的语言，如Java、C#，优势在于程序的运行性能。这种观念并不完全。如果一个人深信这一点，那么说明他并没有充分了解和理解C++和那个某某语言。同时，持有这种观念的人，通常也是受到了某种误导（罪魁祸首当然就是那些财大气粗的公司）。对于这些公司而言，他们隐藏了C++同某某语言间的核心差别，而把现在多数程序员不太关心的差别，也就是性能，加以强化。因为随着cpu性能的快速提升，性能问题已不为人们所关心。这叫&#8220;李代桃僵&#8221;。很多涉世不深的程序员，也就相信了他们。于是，大公司们的阴谋也就得逞了。<br>&nbsp;&nbsp;&nbsp; 这个文章系列里，我将竭尽所能，利用一些现实的案例，来戳破这种谎言，还世道一个清白。但愿我的努力不会白费。</p>
<p><br>软件工程</p>
<p>&nbsp;&nbsp;&nbsp; 一般认为，使用Java或C#的开发成本比C++低。但是，如果你能够充分分析C++和这些语言的差别，会发现这句话的成立是有条件的。这个条件就是：软件规模和复杂度都比较小。如果不超过3万行有效代码（不包括生成器产生的代码），这句话基本上还能成立。否则，随着代码量和复杂度的增加，C++的优势将会越来越明显。<br>&nbsp;&nbsp;&nbsp; 造成这种差别的就是C++的软件工程性。在Java和C#大谈软件工程的时候，C++实际上已经悄悄地将软件工程性提升到一个前所未有的高度。这一点被多数人忽视，并且被大公司竭力掩盖。<br>&nbsp;&nbsp;&nbsp; 语言在软件工程上的好坏，依赖于语言的抽象能力。从面向过程到面向对象，语言的抽象能力有了一个质的飞跃。但在实践中，人们发现面向对象无法解决所有软件工程中的问题。于是，精英们逐步引入、并拓展泛型编程，解决更高层次的软件工程问题。（实际上，面向对象和泛型编程的起源都可以追溯到1967年，但由于泛型编程更抽象，所以应用远远落后于面向对象）。<br>&nbsp;&nbsp;&nbsp; 一个偶然的机会，我突发奇想，试图将货币强类型化，使得货币类型可以采用普通的算术表达式计算，而无需关心汇率换算的问题。具体的内容我已经写成文章，放在blog里：<a href="http://blog.csdn.net/longshanks/archive/2007/05/30/1631391.aspx">http://blog.csdn.net/longshanks/archive/2007/05/30/1631391.aspx</a>。（CSDN的论坛似乎对大文章有些消化不良）。下面我只是简单地描述一下问题，重点还在探讨语言能力间的差异。<br>&nbsp;&nbsp;&nbsp; 当时我面临的问题是：假设有四种货币：RMB、USD、UKP、JPD。我希望能够这样计算他们：<br>RMB rmb_(1000);<br>USD usd_;<br>UKP ukp_;<br>JPD jpd_(2000);</p>
<p>usd_=rmb_;//赋值操作，隐含了汇率转换。usd_实际值应该是1000/7.68=130.21<br>rmb_=rmb_*2.5;//单价乘上数量。<br>ukp_=usd_*3.7;//单价乘上数量，赋值给英镑。隐含汇率转换。<br>double n=jpd_/(usd_-ukp_);//利用差价计算数量。三种货币参与，隐含汇率转换。<br>而传统上，我们通常用一个double或者currency类型表示所有货币。于是，当不同币种参与运算时，必须进行显式的汇率转换：<br>double rmb_(100), usd_(0), ukp_(0), jpn_(2000);</p>
<p>usd_=rmb_*usd_rmb_rate;<br>ukp_=(usd_*usd_ukp_rate)*3.7;<br>double n=jpd_/((usd_*usd_jpd_rate)-(ukp_*ukp_jpd_rate))<br>很显然，强类型化后，代码简洁的多。并且可以利用重载或特化，直接给出与货币相关的辅助信息，如货币符号等（这点我没有做，但加上也不复杂）。<br>在C++中，我利用模板、操作符重载，以及操作符函数模板等技术，很快开发出这个货币体系：<br>template&lt;int CurrType&gt;<br>class Currency<br>{<br>public:<br>&nbsp;&nbsp; Currency&lt;CurrType&gt;&amp; operator=(count Currency&lt;ct2&gt;&amp; v) {<br>&#8230;<br>&nbsp;&nbsp; }<br>public:<br>&nbsp;&nbsp; double _val;<br>&#8230;<br>};<br>template&lt;int ty, int tp&gt;<br>inline bool operator==(currency&lt;ty&gt;&amp; c1, const currency&lt;tp&gt;&amp; c2) {<br>&#8230;<br>}<br>&nbsp;<br>template&lt;int ty, int tp&gt;<br>inline currency&lt;ty&gt;&amp; operator+=(currency&lt;ty&gt;&amp; c1, const currency&lt;tp&gt;&amp; c2) {<br>&#8230;<br>}<br>template&lt;int ty, int tp&gt;<br>inline currency&lt;ty&gt; operator+(currency&lt;ty&gt;&amp; c1, const currency&lt;tp&gt;&amp; c2) {<br>&#8230;<br>}<br>&#8230;<br>总共不超过200行代码。（当然，一个工业强度的货币体系，需要更多的辅助类、函数等等。但基本上不会超过500行代码）。如果我需要一种货币，就先为其指定一个int类型的常量值，然后typedef一下即可：<br>const int CT_RMB=0;//也可以用enum<br>typedef Currency&lt;CT_RMB&gt;RMB;<br>const int CT_USD=1;<br>typedef Currency&lt;CT_USD&gt;USD;<br>const int CT_UKP=2;<br>typedef Currency&lt;CT_USD&gt;USD;<br>const int CT_JPD=3;<br>typedef Currency&lt;CT_USD&gt;USD;<br>&#8230;<br>每新增一种货币，只需定义一个值，然后typedef即可。而对于核心的Currency&lt;&gt;和操作符重载，无需做丁点改动。<br>之后，我试图将这个货币体系的代码移植到C#中去。根据试验的结果，我也写了一篇文章（也放在blog里：<a href="http://blog.csdn.net/longshanks/archive/2007/05/30/1631476.aspx">http://blog.csdn.net/longshanks/archive/2007/05/30/1631476.aspx</a>）。我和一个同事（他是使用C#开发的，对其更熟悉），用了大半个上午，终于完成了这项工作。<br>令人丧气的事，上来就碰了个钉子：C#不支持=的重载。于是只能用asign&lt;&gt;()泛型函数代替。之后，由于C#的泛型不支持非类型泛型参数，即上面C++代码中的int CurrType模板参数的泛型对等物，以及C#不支持泛型操作符重载，整个货币系统从泛型编程模式退化成了面向对象模式。当然，在我们坚持不懈的努力下，最后终于实现了和C++中一样的代码效果（除了那个赋值操作）：<br>assign(rmb_, ukp_);<br>assign(usd_, rmb_*3.7);<br>&#8230;<br>我知道，有些人会说，既然OOP可以做到，何必用GP呢？GP太复杂了。这里，我已经为这些人准备了一组统计数据：在C#代码中，我实现了3个货币，结果定义了4个类（一个基类，三个货币类）；重载30个算术操作符（和C++一样，实现10个操作符，每个类都得把10个操作符重载一遍）；6个类型转换操作符（从两种货币类到第三货币类的转换操作符）。<br>这还不是最糟的。当我增加一个货币，货币数变成4个后，数据变成了：5个类；40个算术操作符重载；12个类型转换操作符重载。<br>当货币数增加到10个后：11个类；100个算术操作符重载；90个类型转换操作符重载。<br>反观C++的实现，3个货币时：1个类模板；1个赋值操作符重载模板；10个算术操作符重载模板；外加3个const int定义，3个typedef。<br>10个货币时：1个类模板；1个赋值操作符重载模板；10个算术操作符重载模板；const int定义和typedef分别增加到10个。<br>也就是说C++版本的代码随着货币的增加，仅线性增加。而且代码行增加的系数仅是2。请注意，是代码行！不是类、函数，也不是操作符的数量。而C#版本的代码量则会以几何级数增加。几何级数！！！<br>这些数字的含义，我就不用多说了吧。无论是代码的数量、可维护性、可扩展性C++都远远好于C#版本。更不用说可用性了（那个assign函数用起来有多难看）。<br>&nbsp;&nbsp;&nbsp; 我知道，有些人还会说：货币太特殊了，在实践中这种情况毕竟少见。没错，货币是比较特殊，但是并没有特殊到独此一家的程度。我曾经做了一个读取脚本中的图形信息，并绘图输出的简单案例，以展示OOP的一些基本概念，用于培训。但如果将其细化，可以开发出一个很不错的脚本绘图引擎。其中，我使用了组合递归、多态和动态链接，以及类工厂等技术。就是那个类工厂，由于我使用了模板，使得类工厂部分的代码减少了2/3，而且没有重复代码，更易维护。关于抽象类工厂的GP优化，Alexandrescu在其《Modren C++ design》中，有更多的案例。同样的技术，还可以推广到业务模型的类系统中，优化类工厂的代码。<br>如果还不满意，那么就去看看boost。boost的很多库实现了几乎不可想象的功能，比如lambda表达式、BGL的命名参数等等。它为我们很多优化软件代码新思路，很多技术和方法可以促进我们大幅优化代码，降低开发成本。<br>&nbsp;&nbsp;&nbsp; 最后，如果你认为C#的最大的优势在于.net平台，那我可以告诉你，这个世界上还有一种东西叫C++/CLI，完全可以满足.net的开发，而且更好，足以擦干净.net那肮脏的屁股。不过，这将会是另外一个故事了&#8230;<br></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/26396.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-06-15 20:41 <a href="http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于系统进程的一点很基础的知识</title><link>http://www.cppblog.com/andxie99/archive/2007/06/09/25900.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sat, 09 Jun 2007 07:36:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/06/09/25900.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/25900.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/06/09/25900.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/25900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/25900.html</trackback:ping><description><![CDATA[<br>&nbsp;&nbsp;&nbsp; 系统进程<br>&nbsp;&nbsp;&nbsp; Windows NT/2000操作系统拥有少量的系统进程来管理登录、服务、用户进程。你能通过任务管理器列出系统进程或者通过Platform SDK的任务列表工具（tlist）来找到他们。<br>&nbsp;&nbsp;&nbsp; 当Windows NT/2000操作系统运行时，可以将进程大致分成三个层次：<br>&nbsp;&nbsp;&nbsp; 第一层就包含一个系统进程——系统闲逛进程，该进程的ID为0；<br>&nbsp;&nbsp;&nbsp; 第二层包含所有其他系统进程，这些进程开始于一个称为system的进程，该进程是session manager process(smss.exe)的父进程，session manager process 是Win32 subsystem process(csrss.exe)和logon process(winlogon.exe)的父进程；<br>&nbsp;&nbsp;&nbsp; 第三层开始于一个程序管理进程（explorer.exe），它是所有用户进程的父进程。
<img src ="http://www.cppblog.com/andxie99/aggbug/25900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-06-09 15:36 <a href="http://www.cppblog.com/andxie99/archive/2007/06/09/25900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>存储过程开发模板</title><link>http://www.cppblog.com/andxie99/archive/2007/02/25/18966.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sun, 25 Feb 2007 06:58:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/02/25/18966.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/18966.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/02/25/18966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/18966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/18966.html</trackback:ping><description><![CDATA[总结的一个存储过程开发模板，主要是避免一些常见问题。<br>书写规范为：SQL关键字均使用小写。但是定义连接属性，如SET NOCOUNT ON可以用大写；变量采用Camel风格，单词首字符大写。<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_0_557_Open_Image onclick="this.style.display='none'; Codehighlighter1_0_557_Open_Text.style.display='none'; Codehighlighter1_0_557_Closed_Image.style.display='inline'; Codehighlighter1_0_557_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_0_557_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_557_Closed_Text.style.display='none'; Codehighlighter1_0_557_Open_Image.style.display='inline'; Codehighlighter1_0_557_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span id=Codehighlighter1_0_557_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">/**/</span><span id=Codehighlighter1_0_557_Open_Text><span style="COLOR: #008080">/*</span><span style="COLOR: #008080">*********************************************<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>作者：&nbsp;&nbsp;&nbsp;&nbsp;XXX<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>创建日期：YYYY-MM-DD<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>功能描述：（清楚、详尽。如：本存储过程主要用于生成主键ID，<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp; 为了适应分布式数据库的应用，采用SiteID（三位）+YYYYMMDD（八位）+顺序位（八位）组成BigInt类型编码。）<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>-----------------------------------------------<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>修改者：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>修改日期：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>修改描述：（如：本次修改加入了对存储过程的错误捕获。）<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>-----------------------------------------------<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>传入参数：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@X1<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据类型：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;描述：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@X2<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据类型：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;描述：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>传出参数：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@X1<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据类型：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;描述：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>返回值：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@XX<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据类型：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;描述：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>*********************************************</span><span style="COLOR: #008080">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;先检查存储过程是否存在，如果存在，先drop掉</span><span style="COLOR: #008080"><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;</span><span style="COLOR: #ff00ff">Object_Id</span><span style="COLOR: #000000">(N</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #ff0000">[dbo].[P_xxxx]</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #000000">,&nbsp;N</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #ff0000">P</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">is</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">not</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></span><span style="COLOR: #0000ff">begin</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">drop</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">procedure</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">dbo</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #000000">.</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">P_xxxx</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">go</span><span style="COLOR: #000000">&nbsp;<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></span><span style="COLOR: #0000ff">create</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">procedure</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">dbo</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #000000">.</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">P_xxxx</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">&nbsp;DataType,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">@xxx2</span><span style="COLOR: #000000">&nbsp;DataType&nbsp;output<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">begin</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;出于性能考虑，这是每个存储过程的第一条语句</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;当SET&nbsp;NOCOUNT为ON时，将不向客户端发送存储过程中每个语句的DONE_IN_PROC消息。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- 如果存储过程中包含的一些语句并不返回许多实际数据，则该设置由于大量减少了网络流量，因此可显著提高性能。</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">SET</span><span style="COLOR: #000000">&nbsp;NOCOUNT&nbsp;</span><span style="COLOR: #0000ff">ON</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;定义错误变量，为raiserror使用</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">declare</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@ErrorMessage</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #000000">nvarchar</span><span style="COLOR: #000000">(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">4000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">declare</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@ErrorSeverity</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #000000">int</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">declare</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@ErrorState</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #000000">int</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;注释：</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;1、为方便调试，在存储过程内部一律使用&#8220;--&#8221;代替&#8220;/*&nbsp;*/&#8221;</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;2、每个关键性操作请在前面注释</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;变量定义：</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;1、不要在循环中定义变量</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;2、如果变量是用于存储某个字段的值，请使变量类型（包括精度）和字段类型一致</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;3、最好显示的为变量初始化</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;变量赋值：</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;使用set&nbsp;@xxx&nbsp;=&nbsp;?，不要用早期版本的select&nbsp;@xxx&nbsp;=&nbsp;?方式</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;从SQL中为变量赋值采用</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">select</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;col1,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">@xxx2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;col2<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">from</span><span style="COLOR: #000000">&nbsp;tabelname<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;一次性清空表，请使用truncate代替delete</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">truncate</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">table</span><span style="COLOR: #000000">&nbsp;tablename<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;insert语句要把字段名写全</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">insert</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">into</span><span style="COLOR: #000000">&nbsp;tablename(col1,&nbsp;col2&#8230;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">values</span><span style="COLOR: #000000">(</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #008000">@xxx2</span><span style="COLOR: #000000">&#8230;);<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;批量插入</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">insert</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">into</span><span style="COLOR: #000000">&nbsp;tablename1(col1,&nbsp;col2&#8230;)&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">select</span><span style="COLOR: #000000">&nbsp;col1,&nbsp;col2&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">from</span><span style="COLOR: #000000">&nbsp;tablename2<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;判断语句</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;?&nbsp;</span><span style="COLOR: #808080">or</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@xxx2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;?)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</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; &#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</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; &#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">end</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;循环语句</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">&lt;&gt;</span><span style="COLOR: #000000">&nbsp;?)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</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; &#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">end</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;游标：</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;尽量避免使用游标</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;定义游标</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">declare</span><span style="COLOR: #000000">&nbsp;cursor_xxx&nbsp;</span><span style="COLOR: #0000ff">cursor</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">select</span><span style="COLOR: #000000">&nbsp;col1,&nbsp;col2&nbsp;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">from</span><span style="COLOR: #000000">&nbsp;tablename<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">where</span><span style="COLOR: #000000">&nbsp;col1&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@xxx</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;打开游标</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">open</span><span style="COLOR: #000000">&nbsp;cursor_xxx;<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;将游标中的值取到变量中</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">fetch</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">next</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">from</span><span style="COLOR: #000000">&nbsp;cursor_xxx<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">into</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #008000">@xxx2</span><span style="COLOR: #000000">&nbsp;&#8230;;<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;开始游标循环</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="FONT-WEIGHT: bold; COLOR: #008000">@@fetch_status</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</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; &#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">fetch</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">next</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">from</span><span style="COLOR: #000000">&nbsp;cursor_xxx<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">into</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@xxx1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #008000">@xxx2</span><span style="COLOR: #000000">&nbsp;&#8230;;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">end</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;结束游标</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">close</span><span style="COLOR: #000000">&nbsp;cursor_xxx;<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;销毁游标</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">deallocate</span><span style="COLOR: #000000">&nbsp;cursor_xxx;<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;事务</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;如果显式使用事务，请注意SQL&nbsp;Server默认的事务隔离级别是读提交（Read&nbsp;Committed）</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;如果使用更高级别的事务隔离级别，请详细阅读帮助文档，避免不必要的锁阻塞</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">tran</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">update</span><span style="COLOR: #000000">&nbsp;&#8230;&#8230;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">commit</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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;异常处理机制</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;1、在第一次使用异常处理机制之前声明异常变量</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;2、对容易发生错误的操作，用try<img src="http://www.cppblog.com/Images/dot.gif">catch进行异常捕获（声明变量不需要）</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;3、在清理资源后，将错误记录保存在ExecProcdure_ErrorLog表中</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;ExecProcdure_ErrorLog建表脚本如下：</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;create&nbsp;table&nbsp;dbo.ExecProcdure_ErrorLog(</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ID]&nbsp;[bigint]&nbsp;identity(1,&nbsp;1)&nbsp;not&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorNumber]&nbsp;[int]&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorSeverity]&nbsp;[int]&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorState]&nbsp;[int]&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorProcedure]&nbsp;[nvarchar](200)&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorLine]&nbsp;[nvarchar](50)&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorMessage]&nbsp;[nvarchar](4000)&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;[ErrorDateTime]&nbsp;[datetime]&nbsp;null,</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;constraint&nbsp;[PK_ExecProcdure_ErrorLog]&nbsp;primary&nbsp;key&nbsp;clustered</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;([ID]&nbsp;asc&nbsp;)&nbsp;</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;with&nbsp;(IGNORE_DUP_KEY&nbsp;=&nbsp;OFF)&nbsp;ON&nbsp;[primary]</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">----&nbsp;)&nbsp;ON&nbsp;(primary]</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;4、最后使用raiserror将错误返回给调用者</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;错误处理例子</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</span><span style="COLOR: #000000">&nbsp;try<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000">&nbsp;try<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;begin&nbsp;catch&nbsp;要紧跟着end&nbsp;try，中间不允许有其他语句</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">begin</span><span style="COLOR: #000000">&nbsp;catch<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;清理上面try中使用的资源，如删除临时表、销毁游标、回滚事务等</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;设置错误变量</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@ErrorMessage</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;ERROR_mESSAGE(),<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@ErrorSeverity</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;ERROR_SEVERITY(),<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">@ErrorState</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;ERROR_STATE();<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;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;返回错误信息</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">raiserror</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #008000">@ErrorMessage</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;</span><span style="COLOR: #008000">@ErrorSeverity</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;</span><span style="COLOR: #008000">@ErrorState</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">--&nbsp;保存错误信息</span><span style="COLOR: #008080"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">insert</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">into</span><span style="COLOR: #000000">&nbsp;ExecProcdure_ErrorLog<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ErrorNumber,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ErrorSeverity,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ErrorState,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ErrorProcedure,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ErrorLine,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ErrorMessage,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ErrorDateTime)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">select</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;ERROR_NUMBER()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorNumber,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ERROR_SEVERITY()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorSeverity,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ERROR_STATE()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorState,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ERROR_PROCEDURE()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorProcedure,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ERROR_LINE()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorLine,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ERROR_MESSAGE()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorMessage,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #ff00ff">getdate</span><span style="COLOR: #000000">()&nbsp;</span><span style="COLOR: #0000ff">as</span><span style="COLOR: #000000">&nbsp;ErrorDateTime;<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;&nbsp;</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000">&nbsp;catch<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;&nbsp;&#8230;&#8230;<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></span><span style="COLOR: #0000ff">end</span></div>
<img src ="http://www.cppblog.com/andxie99/aggbug/18966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-02-25 14:58 <a href="http://www.cppblog.com/andxie99/archive/2007/02/25/18966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用的DOS网络命令</title><link>http://www.cppblog.com/andxie99/archive/2007/01/07/17400.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sun, 07 Jan 2007 11:00:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/01/07/17400.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/17400.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/01/07/17400.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/17400.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/17400.html</trackback:ping><description><![CDATA[<p><strong>ping<br></strong>&nbsp;&nbsp;&nbsp; ping是个使用频率极高的实用程序，用于确定本地主机是否能与另一台主机交换（发送与接收）数据报。根据返回的信息，你就可以推断TCP/IP参数是否设置得正确以及运行是否正常。需要注意的是：成功地与另一台主机进行一次或两次数据报交换并不表示TCP/IP配置就是正确的，我们必须执行大量的本地主机与远程主机的数据报交换，才能确信TCP/IP的正确性。<br>简单的说，Ping就是一个测试程序，如果Ping运行正确，你大体上就可以排除网络访问层、网卡、MODEM的输入输出线路、电缆和路由器等存在的故障，从而减小了问题的范围。但由于可以自定义所发数据报的大小及无休止的高速发送，Ping也被某些别有用心的人作为DDOS（拒绝服务攻击）的工具，前段时间Yahoo就是被黑客利用数百台可以高速接入互联网的电脑连续发送大量Ping数据报而瘫痪的。 </p>
<p>按照缺省设置，Windows上运行的Ping命令发送4个ICMP（网间控制报文协议）回送请求，每个32字节数据，如果一切正常，你应能得到4个回送应答。 </p>
<p>Ping能够以毫秒为单位显示发送回送请求到返回回送应答之间的时间量。如果应答时间短，表示数据报不必通过太多的路由器或网络连接速度比较快。Ping还能显示TTL（Time To Live存在时间）值，你可以通过TTL值推算一下数据包已经通过了多少个路由器：源地点TTL起始值（就是比返回TTL略大的一个2的乘方数）-返回时TTL值。例如，返回TTL值为119，那么可以推算数据报离开源地址的TTL起始值为128，而源地点到目标地点要通过9个路由器网段（128-119）；如果返回TTL值为246，TTL起始值就是256，源地点到目标地点要通过9个路由器网段。 </p>
<p>通过Ping检测网络故障的典型次序 </p>
<p>正常情况下，当你使用Ping命令来查找问题所在或检验网络运行情况时，你需要使用许多Ping命令，如果所有都运行正确，你就可以相信基本的连通性和配置参数没有问题；如果某些Ping命令出现运行故障，它也可以指明到何处去查找问题。下面就给出一个典型的检测次序及对应的可能故障： </p>
<p>ping 127.0.0.1——这个Ping命令被送到本地计算机的IP软件，该命令永不退出该计算机。如果没有做到这一点，就表示TCP/IP的安装或运行存在某些最基本的问题。 </p>
<p>ping 本机IP——这个命令被送到你计算机所配置的IP地址，你的计算机始终都应该对该Ping命令作出应答，如果没有，则表示本地配置或安装存在问题。出现此问题时，局域网用户请断开网络电缆，然后重新发送该命令。如果网线断开后本命令正确，则表示另一台计算机可能配置了相同的IP地址。</p>
<p>ping 局域网内其他IP——这个命令应该离开你的计算机，经过网卡及网络电缆到达其他计算机，再返回。收到回送应答表明本地网络中的网卡和载体运行正确。但如果收到0个回送应答，那么表示子网掩码（进行子网分割时，将IP地址的网络部分与主机部分分开的代码）不正确或网卡配置错误或电缆系统有问题。 </p>
<p>ping 网关IP——这个命令如果应答正确，表示局域网中的网关路由器正在运行并能够作出应答。 </p>
<p>ping 远程IP——如果收到4个应答，表示成功的使用了缺省网关。对于拨号上网用户则表示能够成功的访问Internet（但不排除ISP的DNS会有问题）。 </p>
<p>ping localhost——localhost是个操作系统的网络保留名，它是127.0.0.1的别名，每台计算机都应该能够将该名字转换成该地址。如果没有做到这一带内，则表示主机文件（/Windows/host）中存在问题。</p>
<p>ping <a href="http://www.yahoo.com/">www.yahoo.com</a>——对这个域名执行Ping命令，你的计算机必须先将域名转换成IP地址，通常是通过DNS服务器。如果这里出现故障，则表示DNS服务器的IP地址配置不正确或DNS服务器有故障（对于拨号上网用户，某些ISP已经不需要设置DNS服务器了）。顺便说一句：你也可以利用该命令实现域名对IP地址的转换功能。 </p>
<p>如果上面所列出的所有Ping命令都能正常运行，那么你对你的计算机进行本地和远程通信的功能基本上就可以放心了。但是，这些命令的成功并不表示你所有的网络配置都没有问题，例如，某些子网掩码错误就可能无法用这些方法检测到。 </p>
<p>Ping命令的常用参数选项 </p>
<p><br>　　-t 表示将不间断向目标IP发送数据包，直到我们强迫其停止（Ctrl+C）。试想，如果你使用100M的宽带接入，而目标IP是56K的小猫，那么要不了多久，目标IP就因为承受不了这么多的数据而掉线，呵呵，一次攻击就这么简单的实现了。 　　 </p>
<p>　　-l 定义发送数据包的大小，默认为32字节，我们利用它可以最大定义到65500字节。结合上面介绍的-t参数一起使用，会有更好的效果。 　　 </p>
<p>　　-n 定义向目标IP发送数据包的次数，默认为3次。如果网络速度比较慢，3次对我们来说也浪费了不少时间，因为现在我们的目的仅仅是判断目标IP是否存在，那么就定义为一次吧。 　　 </p>
<p>　　说明一下，如果-t 参数和 -n参数一起使用，ping命令就以放在后面的参数为标准，比如&#8220;ping IP -t -n 3&#8221;，虽然使用了-t参数，但并不是一直ping下去，而是只ping 3次。另外，ping命令不一定非得ping IP，也可以直接ping主机域名，这样就可以得到主机的IP。 　　 </p>
<p>　　从TTL的返回值可以初步判断被ping主机的操作系统，之所以说&#8220;初步判断&#8221;是因为这个值是可以修改的。这里TTL=32表示操作系统可能是win98。 <br>　　（小知识：如果TTL=128，则表示目标主机可能是Win2000；如果TTL=250，则目标主机可能是Unix） </p>
<p><br><strong>Netstat</strong> </p>
<p>Netstat用于显示与IP、TCP、UDP和ICMP协议相关的统计数据，一般用于检验本机各端口的网络连接情况。 </p>
<p>&nbsp;&nbsp;&nbsp; 如果你的计算机有时候接受到的数据报会导致出错数据删除或故障，你不必感到奇怪，TCP/IP可以容许这些类型的错误，并能够自动重发数据报。但如果累计的出错情况数目占到所接收的IP数据报相当大的百分比，或者它的数目正迅速增加，那么你就应该使用Netstat查一查为什么会出现这些情况了。 </p>
<p>Netstat的一些常用选项： </p>
<p>&nbsp;&nbsp;&nbsp; 这是一个用来查看网络状态的命令，操作简便功能强大。 　　 </p>
<p>netstat -s——本选项能够按照各个协议分别显示其统计数据。如果你的应用程序（如Web浏览器）运行速度比较慢，或者不能显示Web页之类的数据，那么你就可以用本选项来查看一下所显示的信息。你需要仔细查看统计数据的各行，找到出错的关键字，进而确定问题所在。 </p>
<p>netstat -e——本选项用于显示关于以太网的统计数据。它列出的项目包括传送的数据报的总字节数、错误数、删除数、数据报的数量和广播的数量。这些统计数据既有发送的数据报数量，也有接收的数据报数量。这个选项可以用来统计一些基本的网络流量。 </p>
<p>netstat -r——本选项可以显示关于路由表的信息，类似于后面所讲使用route print命令时看到的信息。除了显示有效路由外，还显示当前有效的连接。告诉我们机器的网关、子网掩码等信息。</p>
<p>netstat -a——本选项显示一个所有的有效连接信息列表，即查看所有开放端口，包括已建立的连接（ESTABLISHED），也包括监听连接请求（LISTENING）的那些连接。可以有效发现和预防木马，可以知道机器所开的服务等信息。</p>
<p>netstat -n——显示所有已建立的有效连接。 </p>
<p>Netstat的妙用 </p>
<p>经常上网的人一般都使用ICQ的，不知道你有没有被一些讨厌的人骚扰得不敢上线，想投诉却又不知从何下手？其实，你只要知道对方的IP，就可以向他所属的ISP投诉了。但怎样才能通过ICQ知道对方的IP呢？如果对方在设置ICQ时选择了不显示IP地址，那你是无法在信息栏中看到的。其实，你只需要通过Netstat就可以很方便的做到这一点：当他通过ICQ或其他的工具与你相连时（例如你给他发一条ICQ信息或他给你发一条信息），你立刻在DOS Prompt下输入netstat -n或netstat -a就可以看到对方上网时所用的IP或ISP域名了。甚至连所用Port都完全暴露了，如果你想给他一些教训，这些信息已经足够&#8230;&#8230; </p>
<p><br><strong>IPConfig</strong> </p>
<p>IPConfig实用程序和它的等价图形用户界面——Windows 95/98中的WinIPCfg可用于显示当前的TCP/IP配置的设置值。这些信息一般用来检验人工配置的TCP/IP设置是否正确。但是，如果你的计算机和所在的局域网使用了动态主机配置协议（Dynamic Host Configuration Protocol，DHCP——Windows NT下的一种把较少的IP地址分配给较多主机使用的协议，类似于拨号上网的动态IP分配），这个程序所显示的信息也许更加实用。这时，IPConfig可以让你了解你的计算机是否成功的租用到一个IP地址，如果租用到则可以了解它目前分配到的是什么地址。了解计算机当前的IP地址、子网掩码和缺省网关实际上是进行测试和故障分析的必要项目。 </p>
<p>最常用的选项： </p>
<p>ipconfig——当使用IPConfig时不带任何参数选项，那么它为每个已经配置了的接口显示IP地址、子网掩码和缺省网关值。 </p>
<p>ipconfig /all——当使用all选项时，IPConfig能为DNS和WINS服务器显示它已配置且所要使用的附加信息（如IP地址等），并且显示内置于本地网卡中的物理地址（MAC）。如果IP地址是从DHCP服务器租用的，IPConfig将显示DHCP服务器的IP地址和租用地址预计失效的日期（有关DHCP服务器的相关内容请详见其他有关NT服务器的书籍或询问你的网管），其输出信息见图6的下半部分。 </p>
<p>ipconfig /release和ipconfig /renew——这是两个附加选项，只能在向DHCP服务器租用其IP地址的计算机上起作用。如果你输入ipconfig /release，那么所有接口的租用IP地址便重新交付给DHCP服务器（归还IP地址）。如果你输入ipconfig /renew，那么本地计算机便设法与DHCP服务器取得联系，并租用一个IP地址。请注意，大多数情况下网卡将被重新赋予和以前所赋予的相同的IP地址。 </p>
<p>如果你使用的是Windows 95/98，那么你应该更习惯使用winipcfg而不是ipconfig，因为它是一个图形用户界面，而且所显示的信息与ipconfig相同，并且也提供发布和更新动态IP地址的选项（见图7，全部详细资料见图8）。如果你购买了Windows NT Resource Kit（NT资源包），那么Windows NT也包含了一个图形替代界面，该实用程序的名字是wntipcfg，和Windows 95/98的winipcfg类似。 </p>
<p><strong>ARP（地址转换协议）</strong> </p>
<p>ARP是一个重要的TCP/IP协议，并且用于确定对应IP地址的网卡物理地址。实用arp命令，你能够查看本地计算机或另一台计算机的ARP高速缓存中的当前内容。此外，使用arp命令，也可以用人工方式输入静态的网卡物理/IP地址对，你可能会使用这种方式为缺省网关和本地服务器等常用主机进行这项操作，有助于减少网络上的信息量。 </p>
<p>按照缺省设置，ARP高速缓存中的项目是动态的，每当发送一个指定地点的数据报且高速缓存中不存在当前项目时，ARP便会自动添加该项目。一旦高速缓存的项目被输入，它们就已经开始走向失效状态。例如，在Windows NT网络中，如果输入项目后不进一步使用，物理/IP地址对就会在2至10分钟内失效。因此，如果ARP高速缓存中项目很少或根本没有时，请不要奇怪，通过另一台计算机或路由器的ping命令即可添加。所以，需要通过arp命令查看高速缓存中的内容时，请最好先ping 此台计算机（不能是本机发送ping命令）。 </p>
<p>常用命令选项： </p>
<p>arp -a或arp -g——用于查看高速缓存中的所有项目。-a和-g参数的结果是一样的，多年来-g一直是UNIX平台上用来显示ARP高速缓存中所有项目的选项，而Windows用的是arp -a（-a可被视为all，即全部的意思），但它也可以接受比较传统的-g选项。 </p>
<p>arp -a IP——如果你有多个网卡，那么使用arp -a加上接口的IP地址，就可以只显示与该接口相关的ARP缓存项目。 </p>
<p>arp -s IP 物理地址——你可以向ARP高速缓存中人工输入一个静态项目。该项目在计算机引导过程中将保持有效状态，或者在出现错误时，人工配置的物理地址将自动更新该项目。 </p>
<p>arp -d IP——使用本命令能够人工删除一个静态项目。 </p>
<p><strong>Tracert </strong></p>
<p>当数据报从你的计算机经过多个网关传送到目的地时，Tracert命令可以用来跟踪数据报使用的路由（路径）。该实用程序跟踪的路径是源计算机到目的地的一条路径，不能保证或认为数据报总遵循这个路径。如果你的配置使用DNS，那么你常常会从所产生的应答中得到城市、地址和常见通信公司的名字。Tracert是一个运行得比较慢的命令（如果你指定的目标地址比较远），每个路由器你大约需要给它15秒钟。 </p>
<p>Tracert的使用很简单，只需要在tracert后面跟一个IP地址或URL，Tracert会进行相应的域名转换的。Tracert一般用来检测故障的位置，你可以用tracert IP在哪个环节上出了问题，虽然还是没有确定是什么问题，但它已经告诉了我们问题所在的地方，你也就可以很有把握的告诉别人——某某出了问题。 </p>
<p><br><strong>Route</strong> </p>
<p>大多数主机一般都是驻留在只连接一台路由器的网段上。由于只有一台路由器，因此不存在使用哪一台路由器将数据报发表到远程计算机上去的问题，该路由器的IP地址可作为该网段上所有计算机的缺省网关来输入。 </p>
<p>但是，当网络上拥有两个或多个路由器时，你就不一定想只依赖缺省网关了。实际上你可能想让你的某些远程IP地址通过某个特定的路由器来传递，而其他的远程IP则通过另一个路由器来传递。 </p>
<p>在这种情况下，你需要相应的路由信息，这些信息储存在路由表中，每个主机和每个路由器都配有自己独一无二的路由表。大多数路由器使用专门的路由协议来交换和动态更新路由器之间的路由表。但在有些情况下，必须人工将项目添加到路由器和主机上的路由表中。Route就是用来显示、人工添加和修改路由表项目的。 </p>
<p>一般使用选项： </p>
<p>route print——本命令用于显示路由表中的当前项目，在单路由器网段上的输出结果如图12，由于用IP地址配置了网卡，因此所有的这些项目都是自动添加的。 </p>
<p>route add——使用本命令，可以将信路由项目添加给路由表。例如，如果要设定一个到目的网络209.98.32.33的路由，其间要经过5个路由器网段，首先要经过本地网络上的一个路由器，器IP为202.96.123.5，子网掩码为255.255.255.224，那么你应该输入以下命令： </p>
<p>route add 209.98.32.33 mask 255.255.255.224 202.96.123.5 metric 5 </p>
<p>route change——你可以使用本命令来修改数据的传输路由，不过，你不能使用本命令来改变数据的目的地。下面这个例子可以将数据的路由改到另一个路由器，它采用一条包含3个网段的更直的路径： </p>
<p>route add 209.98.32.33 mask 255.255.255.224 202.96.123.250 metric 3 </p>
<p>route delete——使用本命令可以从路由表中删除路由。例如：route delete 209.98.32.33 </p>
<p><br><strong>NBTStat</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 该命令使用TCP/IP上的NetBIOS显示协议统计和当前TCP/IP连接，使用这个命令你可以得到远程主机的NETBIOS信息，比如用户名、所属的工作组、网卡的MAC地址等。在此我们就有必要了解几个基本的参数。 　　 　 </p>
<p>　　当得到了对方的IP或者机器名的时候，就可以使用nbtstat命令来进一步得到对方的信息了，这又增加了我们入侵的保险系数。 </p>
<p>常用选项： </p>
<p>nbtstat -n——列出本地机器的NETBIOS信息（显示寄存在本地的名字和服务程序）。 </p>
<p>nbtstat -c——本命令用于显示NetBIOS名字高速缓存的内容。NetBIOS名字高速缓存用于寸放与本计算机最近进行通信的其他计算机的NetBIOS名字和IP地址对。 </p>
<p>nbtstat -r——本命令用于清除和重新加载NetBIOS名字高速缓存。 </p>
<p>nbtstat -a IP——通过IP显示另一台计算机的物理地址和名字列表，你所显示的内容就像对方计算机自己运行nbtstat -n一样。 </p>
<p>nbtstat -s IP——显示实用其IP地址的另一台计算机的NetBIOS连接表。 </p>
<p><br><strong>Net</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 这个命令是网络命令中最重要的一个，必须透彻掌握它的每一个子命令的用法，因为它的功能实在是太强大了，这简直就是微软为我们提供的最好的入侵工具。首先让我们来看一看它都有那些子命令，键入net /?回车。 </p>
<p>　　在这里，我们重点掌握几个入侵常用的子命令。 　　 </p>
<p>　　net view 　　 </p>
<p>　　使用此命令查看远程主机的所以共享资源。命令格式为net view <a href="file://IP/">\\IP</a>。</p>
<p>　　net use </p>
<p>　　把远程主机的某个共享资源影射为本地盘符，图形界面方便使用，呵呵。命令格式为net use x: <a href="file://IP/sharename">\\IP\sharename</a>。下面表示和192.168.0.7建立IPC$连接（net use <a href="file://IP/IPC$">\\IP\IPC$</a> "password" /user:"name"）， 　　 </p>
<p>　　建立了IPC$连接后，呵呵，就可以上传文件了：copy nc.exe <a href="file://192.168.0.7/admin$">\\192.168.0.7\admin$</a>，表示把本地目录下的nc.exe传到远程主机，结合后面要介绍到的其他DOS命令就可以实现入侵了。 　　 </p>
<p>　　net start </p>
<p>　　使用它来启动远程主机上的服务。当你和远程主机建立连接后，如果发现它的什么服务没有启动，而你又想利用此服务怎么办？就使用这个命令来启动吧。用法：net start servername，如启动telnet服务等。 　　 </p>
<p>　　net stop </p>
<p>　　入侵后发现远程主机的某个服务碍手碍脚，怎么办？利用这个命令停掉就ok了，用法和net start同。 　　 </p>
<p>　　net user </p>
<p>　　查看和帐户有关的情况，包括新建帐户、删除帐户、查看特定帐户、激活帐户、帐户禁用等。这对我们入侵是很有利的，最重要的，它为我们克隆帐户提供了前提。键入不带参数的net user，可以查看所有用户，包括已经禁用的。下面分别讲解。 </p>
<p>　　1，net user abcd 1234 /add，新建一个用户名为abcd，密码为1234的帐户，默认为user组成员。 </p>
<p>　　2，net user abcd /del，将用户名为abcd的用户删除。 </p>
<p>　　3，net user abcd /active:no，将用户名为abcd的用户禁用。 </p>
<p>　　4，net user abcd /active:yes，激活用户名为abcd的用户。 </p>
<p>　　5，net user abcd，查看用户名为abcd的用户的情况　　 </p>
<p>　　net localgroup </p>
<p>　　查看所有和用户组有关的信息和进行相关操作。键入不带参数的net localgroup即列出当前所有的用户组。在入侵过程中，我们一般利用它来把某个帐户提升为administrator组帐户，这样我们利用这个帐户就可以控制整个远程主机了。用法：net localgroup groupname username /add。</p>
<p>　　net time </p>
<p>　　这个命令可以查看远程主机当前的时间。如果你的目标只是进入到远程主机里面，那么也许就用不到这个命令了。但简单的入侵成功了，难道只是看看吗？我们需要进一步渗透。这就连远程主机当前的时间都需要知道，因为利用时间和其他手段可以实现某个命令和程序的定时启动，为我们进一步入侵打好基础。用法：net time <a href="file://IP/">\\IP</a>。 　　 </p>
<p><strong>at</strong> </p>
<p>　　这个命令的作用是安排在特定日期或时间执行某个特定的命令和程序（知道net time的重要了吧？）。当我们知道了远程主机的当前时间，就可以利用此命令让其在以后的某个时间（比如2分钟后）执行某个程序和命令。用法：at time command <a href="file://computer/">\\computer</a>。 　　 </p>
<p>ftp 　　 </p>
<p>　　大家对这个命令应该比较熟悉了吧？网络上开放的ftp的主机很多，其中很大一部分是匿名的，也就是说任何人都可以登陆上去。现在如果你扫到了一台开放ftp服务的主机（一般都是开了21端口的机器），如果你还不会使用ftp的命令怎么办？下面就给出基本的ftp命令使用方法。 </p>
<p>　　首先在命令行键入ftp回车，出现ftp的提示符，这时候可以键入&#8220;help&#8221;来查看帮助（任何DOS命令都可以使用此方法查看其帮助)。 　　 </p>
<p>　　大家可能看到了，这么多命令该怎么用？其实也用不到那么多，掌握几个基本的就够了。 　　 </p>
<p>　　首先是登陆过程，这就要用到open了，直接在ftp的提示符下输入&#8220;open 主机IP ftp端口&#8221;回车即可，一般端口默认都是21，可以不写。接着就是输入合法的用户名和密码进行登陆了，这里以匿名ftp为例介绍。 　　 </p>
<p>　　用户名和密码都是ftp，密码是不显示的。当提示**** logged in时，就说明登陆成功。这里因为是匿名登陆，所以用户显示为Anonymous。 　　 </p>
<p>　　接下来就要介绍具体命令的使用方法了。 　　 </p>
<p>　　dir 跟DOS命令一样，用于查看服务器的文件，直接敲上dir回车，就可以看到此ftp服务器上的文件。 </p>
<p>　　cd 进入某个文件夹。 </p>
<p>　　get 下载文件到本地机器。 </p>
<p>　　put 上传文件到远程服务器。这就要看远程ftp服务器是否给了你可写的权限了，如果可以，呵呵，该怎么 利用就不多说了，大家就自由发挥去吧。 </p>
<p>　　delete 删除远程ftp服务器上的文件。这也必须保证你有可写的权限。 </p>
<p>　　bye 退出当前连接。 </p>
<p>　　quit 同上。 <br>　　 </p>
<p><strong>telnet </strong></p>
<p>　　功能强大的远程登陆命令，几乎所有的入侵者都喜欢用它，屡试不爽。为什么？它操作简单，如同使用自己的机器一样，只要你熟悉DOS命令，在成功以administrator身份连接了远程机器后，就可以用它来做想干的一切了。下面介绍一下使用方法，首先键入telnet回车，再键入help查看其帮助信息。 　　 </p>
<p>　　然后在提示符下键入open IP回车，这时就出现了登陆窗口，让你输入合法的用户名和密码，这里输入任何密码都是不显示的。 　　 </p>
<p>　　当输入用户名和密码都正确后就成功建立了telnet连接，这时候你就在远程主机上具有了和此用户一样的权限，利用DOS命令就可以实现你想干的事情了。这里我使用的超级管理员权限登陆的。　　&nbsp; </p>
<p>　　另外大家应该清楚，任何人要想进入系统，必须得有一个合法的用户名和密码（输入法漏洞差不多绝迹了吧），哪怕你拿到帐户的只有一个很小的权限，你也可以利用它来达到最后的目的。所以坚决消灭空口令，给自己的帐户加上一个强壮的密码，是最好的防御弱口令入侵的方法</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/17400.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-01-07 19:00 <a href="http://www.cppblog.com/andxie99/archive/2007/01/07/17400.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>8086微处理器的结构</title><link>http://www.cppblog.com/andxie99/archive/2006/12/17/16540.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sun, 17 Dec 2006 04:27:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/12/17/16540.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/16540.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/12/17/16540.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/16540.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/16540.html</trackback:ping><description><![CDATA[<br><br><span class=pt9-black>　　计算机系统包括硬件和软件两部分。微计算机的硬件有包括中央处理器（CPU）的微处理器芯片、存储器（MEMORY）、输入/输出（I/O）接口三部分组成。软件是各种程序的总和，包括系统软件和应用软件。<br><br>　　</span> <span class=part>8086微处理器的基本组成<br></span><span class=pt9-black>
<div align=center><img height=589 alt=2_1.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/2_1.jpg" width=532 border=0> </div>
<br>
<div align=center>8086微处理器的结构</div>
<br>　<br>　　Intel 8086微处理器是一个16位结构，从图中可以看出，整个微处理器分成两大功能部件，即执行部件（Execution Unit，EU）与总线接口部件（Bus Interface Unit，BIU）。EU与BIU通过内部总线连接，它们既可协同工作，又可独立工作。当EU与BIU各自独立工作时，就体现出8086内部操作具有并行性的特征。<br><br><br>　　<strong>执行部件（EU）</strong><br>　　执行部件EU是执行程序的的核心部件，完成指令译码、运算及其它操作的执行。执行部件由ALU（算术逻辑运算部件）、通用寄存器组、状态标志寄存器以及控制电路组成。<br><br><br>　　<strong>总线接口部件（BIU）</strong><br>　　总线接口部件BIU负责与存储器、I/O接口电路连接，并形成20位的地址码和16位的数据，通过总线进行数据传送。BIU由一些专用寄存器、指令队列缓冲器、地址加法器等功能部件组成。　</span> 
<img src ="http://www.cppblog.com/andxie99/aggbug/16540.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-12-17 12:27 <a href="http://www.cppblog.com/andxie99/archive/2006/12/17/16540.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSI七层网络模型与TCP/IP四层网络模型</title><link>http://www.cppblog.com/andxie99/archive/2006/10/11/13559.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 11 Oct 2006 02:50:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/11/13559.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13559.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/11/13559.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13559.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13559.html</trackback:ping><description><![CDATA[<br>
<div class=Content-body id=logPanel>　　网络协议设计者不应当设计一个单一、巨大的协议来为所有形式的通信规定完整的细节，而应把通信问题划分成多个小问题，然后为每一个小问题设计一个单独的协议。这样做使得每个协议的设计、分析、时限和测试比较容易。协议划分的一个主要原则是确保目标系统有效且效率高。为了提高效率，每个协议只应该注意没有被其他协议处理过的那部分通信问题；为了主协议的实现更加有效，协议之间应该能够共享特定的数据结构；同时这些协议的组合应该能处理所有可能的硬件错误以及其它异常情况。为了保证这些协议工作的协同性，应当将协议设计和开发成完整的、协作的协议系列（即协议族），而不是孤立地开发每个协议。<br><br>　　在网络历史的早期，国际标准化组织（ISO）和国际电报电话咨询委员会（CCITT）共同出版了开放系统互联的七层参考模型。一台计算机操作系统中的网络过程包括从应用请求（在协议栈的顶部）到网络介质（底部） ，OSI参考模型把功能分成七个分立的层次。图1表示了OSI分层模型。<br><br>
<div align=center><img height=230 alt=osi.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/osi.jpg" width=155 border=0><br>图1　OSI七层参考模型</div>
<br><br>　　<strong>OSI模型的七层分别进行以下的操作：</strong><br><br>　　<strong>第一层　物理层</strong><br><br>　　第一层负责最后将信息编码成电流脉冲或其它信号用于网上传输。它由计算机和网络介质之间的实际界面组成，可定义电气信号、符号、线的状态和时钟要求、数据编码和数据传输用的连接器。如最常用的RS-232规范、10BASE-T的曼彻斯特编码以及RJ-45就属于第一层。所有比物理层高的层都通过事先定义好的接口而与它通话。如以太网的附属单元接口（AUI），一个DB-15连接器可被用来连接层一和层二。<br><br>　　<strong>第二层　数据链路层</strong><br><br>　　数据链路层通过物理网络链路提供可靠的数据传输。不同的数据链路层定义了不同的网络和协议特征，其中包括物理编址、网络拓扑结构、错误校验、帧序列以及流控。物理编址（相对应的是网络编址）定义了设备在数据链路层的编址方式；网络拓扑结构定义了设备的物理连接方式，如总线拓扑结构和环拓扑结构；错误校验向发生传输错误的上层协议告警；数据帧序列重新整理并传输除序列以外的帧；流控可能延缓数据的传输，以使接收设备不会因为在某一时刻接收到超过其处理能力的信息流而崩溃。数据链路层实际上由两个独立的部分组成，介质存取控制（Media Access Control,MAC）和逻辑链路控制层（Logical Link Control,LLC）。MAC描述在共享介质环境中如何进行站的调度、发生和接收数据。MAC确保信息跨链路的可靠传输，对数据传输进行同步，识别错误和控制数据的流向。一般地讲，MAC只在共享介质环境中才是重要的，只有在共享介质环境中多个节点才能连接到同一传输介质上。IEEE MAC规则定义了地址，以标识数据链路层中的多个设备。逻辑链路控制子层管理单一网络链路上的设备间的通信，IEEE 802.2标准定义了LLC。LLC支持无连接服务和面向连接的服务。在数据链路层的信息帧中定义了许多域。这些域使得多种高层协议可以共享一个物理数据链路。<br><br>　　<strong>第三层　网络层</strong><br><br>　　网络层负责在源和终点之间建立连接。它一般包括网络寻径，还可能包括流量控制、错误检查等。相同MAC标准的不同网段之间的数据传输一般只涉及到数据链路层，而不同的MAC标准之间的数据传输都涉及到网络层。例如IP路由器工作在网络层，因而可以实现多种网络间的互联。<br><br>　　<strong>第四层　传输层</strong><br><br>　　传输层向高层提供可靠的端到端的网络数据流服务。传输层的功能一般包括流控、多路传输、虚电路管理及差错校验和恢复。流控管理设备之间的数据传输，确保传输设备不发送比接收设备处理能力大的数据；多路传输使得多个应用程序的数据可以传输到一个物理链路上；虚电路由传输层建立、维护和终止；差错校验包括为检测传输错误而建立的各种不同结构；而差错恢复包括所采取的行动（如请求数据重发），以便解决发生的任何错误。传输控制协议（TCP）是提供可靠数据传输的TCP/IP协议族中的传输层协议。<br><br>　　<strong>第五层　会话层</strong><br><br>　　会话层建立、管理和终止表示层与实体之间的通信会话。通信会话包括发生在不同网络应用层之间的服务请求和服务应答，这些请求与应答通过会话层的协议实现。它还包括创建检查点，使通信发生中断的时候可以返回到以前的一个状态。<br><br>　　<strong>第六层　表示层</strong><br><br>　　表示层提供多种功能用于应用层数据编码和转化，以确保以一个系统应用层发送的信息可以被另一个系统应用层识别。表示层的编码和转化模式包括公用数据表示格式、性能转化表示格式、公用数据压缩模式和公用数据加密模式。<br><br>　　公用数据表示格式就是标准的图像、声音和视频格式。通过使用这些标准格式，不同类型的计算机系统可以相互交换数据；转化模式通过使用不同的文本和数据表示，在系统间交换信息，例如ASCII（American Standard Code for Information Interchange，美国标准信息交换码）；标准数据压缩模式确保原始设备上被压缩的数据可以在目标设备上正确的解压；加密模式确保原始设备上加密的数据可以在目标设备上正确地解密。<br><br>　　表示层协议一般不与特殊的协议栈关联，如QuickTime是Applet计算机的视频和音频的标准，MPEG是ISO的视频压缩与编码标准。常见的图形图像格式PCX、GIF、JPEG是不同的静态图像压缩和编码标准。<br><br>　　<strong>第七层　应用层</strong><br><br>　　应用层是最接近终端用户的OSI层，这就意味着OSI应用层与用户之间是通过应用软件直接相互作用的。注意，应用层并非由计算机上运行的实际应用软件组成，而是由向应用程序提供访问网络资源的API（Application Program Interface，应用程序接口）组成，这类应用软件程序超出了OSI模型的范畴。应用层的功能一般包括标识通信伙伴、定义资源的可用性和同步通信。因为可能丢失通信伙伴，应用层必须为传输数据的应用子程序定义通信伙伴的标识和可用性。定义资源可用性时，应用层为了请求通信而必须判定是否有足够的网络资源。在同步通信中，所有应用程序之间的通信都需要应用层的协同操作。<br><br>　　OSI的应用层协议包括文件的传输、访问及管理协议（FTAM） ，以及文件虚拟终端协议（VIP）和公用管理系统信息（CMIP）等。<br><br><br>　　<strong>TCP/IP分层模型</strong><br><br>　　TCP/IP分层模型（TCP/IP Layening Model）被称作因特网分层模型（Internet Layering Model）、因特网参考模型（Internet Reference Model）。图2表示了TCP/IP分层模型的四层。<br><br>
<div align=center><img height=287 alt=tcpip.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/tcpip.jpg" width=434 border=0><br>图2　TCP/IP四层参考模型</div>
<br><br>　　TCP/IP协议被组织成四个概念层，其中有三层对应于ISO参考模型中的相应层。ICP/IP协议族并不包含物理层和数据链路层，因此它不能独立完成整个计算机网络系统的功能，必须与许多其他的协议协同工作。<br><br>　　<strong>TCP/IP分层模型的四个协议层分别完成以下的功能：</strong><br><br>　　<strong>第一层　网络接口层</strong><br><br>　　网络接口层包括用于协作IP数据在已有网络介质上传输的协议。实际上TCP/IP标准并不定义与ISO数据链路层和物理层相对应的功能。相反，它定义像地址解析协议（Address Resolution Protocol,ARP）这样的协议，提供TCP/IP协议的数据结构和实际物理硬件之间的接口。<br><br>　　<strong>第二层　网间层</strong><br><br>　　网间层对应于OSI七层参考模型的网络层。本层包含IP协议、RIP协议（Routing Information Protocol，路由信息协议），负责数据的包装、寻址和路由。同时还包含网间控制报文协议（Internet Control Message Protocol,ICMP）用来提供网络诊断信息。<br><br>　　<strong>第三层　传输层</strong><br><br>　　传输层对应于OSI七层参考模型的传输层，它提供两种端到端的通信服务。其中TCP协议（Transmission Control Protocol）提供可靠的数据流运输服务，UDP协议（Use Datagram Protocol）提供不可靠的用户数据报服务。<br><br>　　<strong>第四层　应用层</strong><br><br>　　应用层对应于OSI七层参考模型的应用层和表达层。因特网的应用层协议包括Finger、Whois、FTP（文件传输协议）、Gopher、HTTP（超文本传输协议）、Telent（远程终端协议）、SMTP（简单邮件传送协议）、IRC（因特网中继会话）、NNTP（网络新闻传输协议）等。</div>
<img src ="http://www.cppblog.com/andxie99/aggbug/13559.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-11 10:50 <a href="http://www.cppblog.com/andxie99/archive/2006/10/11/13559.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Win32汇编基础教程</title><link>http://www.cppblog.com/andxie99/archive/2006/10/09/13481.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Mon, 09 Oct 2006 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/09/13481.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13481.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/09/13481.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13481.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13481.html</trackback:ping><description><![CDATA[<strong>Win32汇编教程之一<br></strong>Win32汇编的环境和基础<br><br>1.32位环境简介<br><br>&nbsp;&nbsp;在Dos下编汇编程序，我们可以管理系统的所有资源，我们可以改动系统中所有的内存，如自己改动内存控制块来分配内存，自己修改中断向量表来截获中断等，对其他操作也是如此，如我们对键盘端口直接操作就可以把键盘屏蔽掉，可以这样来描述Dos系统：系统只有一个特权级别，在编程上讲，任何程序和操作系统都是同级的，所以在Dos下，一个编得不好的程序会影响其他所有的程序，如一个程序把键盘口中断关掉了，所有程序就都不能从键盘获得键入的数据，直到任何一个程序重新打开键盘为止，一个程序陷入死循环，也没有其他程序可以把它终止掉。Dos下的编程思路是&#8220;单任务&#8221;的，你只要认为你的程序会按照你的流程一步步的执行下去，不必考虑先后问题（当然程序可能会被中断打断，但你可以认为它们会把环境恢复，如果中断程序没有把环境恢复，那是他们的错）。<br>&nbsp;&nbsp;在内存管理方式上，Dos汇编和Win32汇编也有很多的不同：Dos工作在实模式下，我们可以寻址1M的内存，寻址时通过段寄存器来制定段的初始地址，每个段的大小为64K，超过1M的部分，就只能把他作为XMS使用，也就是说，只能用作数据存放使用而无法在其中执行程序。<br>&nbsp;&nbsp;而Windows在保护模式下执行，这里所有的资源对应用程序来说都是被&#8220;保护&#8221;的：程序在执行中有级别之分，只有操作系统工作在最高级--0级中，所有应用程序都工作在3级中（Ring3)， 在Ring3中，你无法直接访问IO端口，无法访问其他程序运行的内存，连向程序自己的代码段写入数据都是非法的，会在Windows的屏幕上冒出一个熟悉的蓝屏幕来。只有对Ring0的程序来说，系统才是全开放的。<br>&nbsp;&nbsp;在内存方面，Windows使用了处理器的分页机制，使得对应用程序来说，所有的内存都是&#8220;平坦&#8221;的，你不必用一个段寄存器去指定段的地址，因为在保护模式下，段寄存器的含义是不同的（可以参见80386手册方面的书籍），你可以直接指定一个32位的地址来寻址4GB的内存。<br>&nbsp;&nbsp;在程序结构方面，Windows程序也有很大的不同，它是&#8220;基于消息&#8221;的，你可以想象这样一个常见的Windows窗口，上面有几个按钮，如果你用Dos编程的思路去考虑，你会发现实现它很困难：鼠标移动到窗口边缘时拖动会改变窗口大小，鼠标点击按钮时再做要做的事，你会发现，你的程序自开始执行后就在等待，你不知道鼠标先会点什么地方，实际上你是在等待所有可能的事情的发生。而在Dos下，你可以只顾自己先执行，需要用户输入时，再停下来，你不输入我就不再执行，而且，我让你输入数据A你就不能输入数据B。<br>&nbsp;&nbsp;好了，言归正传，因为以上是Win32编程的基础，无论对Win32汇编还是VC++，它们都是一样的，下面我们来看看有关Win32汇编的内容。<br><br>2.Win32A***编译器<br><br>&nbsp;&nbsp;Win32A***的编译器最常用的有两种：Borland公司的Tasm5.0和Microsoft的Masm6.11以上版本，两种编译器各有自己的优缺点，Tasm带了一个不大不小的Import库，而Masm没有带，但Masm在代码的优化上面好象比Tasm做得好，但它却不带Import库。看来使用哪一种编译器还是比较难选择的，但Steve Hutchesson给了我们一个答案，他为Masm建立了一个很全的Import库，基本上包括了Windows绝大部分的Api函数，这些库、include文件和其他工具还有Masm6.14版本一起做成了一个 Masm32编译器 -- Masm32V5。这样一来，我们用汇编编程就象用C一样方便。<br>&nbsp;&nbsp;因为有了Masm32V5，所以就我个人而言，我推荐使用Masm作为Win32A***的编译工具，但Masm和Tasm的宏语法有很多的不同，我的这个教程是以Masm格式写的。<br><br>3.Masm32的环境设置<br><br>&nbsp;&nbsp;在Win32编程中，由于Windows有很多的数据结构和定义，这些都放在include文件中，还有连接时要用到Import库（通俗的讲就是Windows提供的DLL文件中的函数列表，也就是告诉程序到哪里去调用API函数），这些都放在include 和lib目录中。我们在编译时要指定以下的系统环境：<br><br>set include=\Masm32v5\Include<br>set lib=\Masmv5\lib<br>set path=\Masmv5\Bin<br><br>这样编译器就会到正确的路径中去找 include 文件和 lib 文件。你可以自己在 autoexec.bat 文件中加上以上语句，为了产生Windows的PE格式的执行文件，在编译和连接中要指定相应的参数：<br><br>编译： Ml /c /coff 文件名.asm<br>连接： Link /SUBSYSTEM:WINDOWS OBJ文件名.obj 资源文件名.res<br><br>为了不在每次编译时都要打这么多的参数，我们可以用 nmake 文件来代为执行，nmake 是代码维护程序，他会检查 .asm .obj .exe .res 等文件的时间，如果你更新了源程序，他会自动执行编译程序或连接程序产生相应的文件。你可以在文件名为 makefile 的文件中指定使用的编译器和连接程序以及相应的参数，下面是一个 makefile 文件的例子：<br><br>NAME = Clock<br>OBJS = $(NAME).obj<br>RES = $(NAME).res<br>$(NAME).exe: $(OBJS) $(RES)<br>Link /DEBUG /SUBSYSTEM:WINDOWS $(OBJS) $(RES) <br>$(RES): $(NAME).rc <br>Rc $(NAME).rc <br>.asm.obj:<br>Ml /c /coff $(NAME).asm<br><br>文件告诉 nmake程序，程序名为 clock，产生 clock.exe 文件需要 clock.obj和 clock.res 文件，而产生 clock.res 文件需要 clock.rc 文件，产生 clock.obj 文件要用到 clock.asm 文件，至于是否需要执行 ml, link 和 rc，程序会根据文件的时间自动判断。<br><br><strong>Win32汇教程二<br></strong>Win32汇编程序的结构和语法<br><br>Win32A***程序的结构和语法<br><br>&nbsp;&nbsp;让我们先来看看一个最简单的Win32汇编程序：<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.386<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.model flat, stdcall<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;option casemap :none&nbsp;&nbsp; ; case sensitive<br><br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; windows.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kernel32.inc<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kernel32.lib<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.data<br><br>szCaption&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Win32汇编例子',0<br>szText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Win32汇编，Simple and powerful!',0<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.code<br><br>start:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;MessageBox,NULL,addr szText,addr szCaption,MB_OK<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;ExitProcess,NULL<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;&nbsp;&nbsp;&nbsp; start<br>这就是一个能执行的最简单的Win32汇编程序，下面我简单地介绍一下各部分的作用：<br><br>.386<br><br>这条语句和Dos下汇编是一样的，是告诉编译器我们要用到80386的指令集，因为32位汇编程序要用到32位的寄存器如eax,ebx等，所以这一句是必须的，当然，你也可以用.486,.586等，当用到特权指令时，还可以用 .386p,.486p等等。<br><br>.model flat,stdcall<br><br>.model告诉编译器程序的模式，编过Dos汇编的人可能知道在Dos程序的模式有tiny,small,...huge 等，它指定了程序内存寻址模式，在huge等模式下，内存寻址和子程序调用将用Far的格式，但在Win32汇编中，你只能使用一个模式即 flat 模式，因为对Win32程序来说，内存是连续的一个4GB的段，无所谓小或大的模式。而stdcall 告诉编译器参数的传递方式，在调用子程序时，参数是通过堆栈传递的，参数的传递方式有三种，stdcall,c 和 pascal，stdcall 指定了参数是从右到左压入堆栈的，比如说对一个Windows API 如 MessageBox，在手册中是如此定义的：<br><br>int MessageBox(<br><br>&nbsp;&nbsp;&nbsp;&nbsp;HWND hWnd,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// handle of owner window<br>&nbsp;&nbsp;&nbsp;&nbsp;LPCTSTR lpText,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // address of text in message box<br>&nbsp;&nbsp;&nbsp;&nbsp;LPCTSTR lpCaption,&nbsp;&nbsp;// address of title of message box&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;UINT uType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// style of message box<br>&nbsp;&nbsp; );<br>那么在汇编中我们就可以这样调用它：<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;uType<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;lpCaption<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;lpText<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;hWnd<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;MessageBox<br>大家要注意最右面的参数是最后一个进堆栈的，当然，我们不必这样麻烦的调用一个 API，因为Masm中的一个宏语句不但帮助我们完成了所有的压栈操作，还帮我们检查参数的个数是否正确，那就是 invoke 语句，我们可以把上面的语句换成 invoke MessageBox,hWnd,lpText,lpCaption,uType 就行了。如本程序中代入实际参数就成了 invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK。<br><br>include 语句<br><br>include 语句包含了一些系统的定义和API函说明，其中所有的Windows 数据结构定义和常量定义包含在 windows.inc 中，而其他 API函数的说明包含在 xxx.inc 中， 如查 Microsoft Win32 Programmer's Reference 知道 ExitProcess包含在kernel32.dll 中，那么我们就要在程序中包括 include kernel32.inc 和 includelib kernel32.lib语句，否则在编译时会出现 API 函数未定义的错误。而 MessageBox 在 user32.dll 中，那么我们就要在程序中包括 include user32.inc 和 includelib user32.lib语句<br><br>.data 或 .data?<br><br>指明了接下来是数据段，.data 定义了预定义的变量，.data?定义了未初始化的变量，两者的不同之处是 .data? 定义的变量并不占用 .exe 文件的大小，而是在程序执行时动态分配，所以开始是不指定初始值的数据可以放在 .data? 段中，如一个1K大小的缓冲区，放在 .data?中，程序将不会增加一个字节。<br><br>.code<br><br>指明了接下来是代码段，我们的所有代码都放在这里。最后的一句 start 语句指定了程序开始执行的语句。程序中的 ExitProcess 是一个标准的 Win32 API，对应 Dos汇编中的 int 20h 或 mov ah,4ch/int 21h，也就是程序退出。而 MessageBox 也是一个标准的 API，功能是在屏幕上显示一个消息框，具体的参数上面已经解释过了还有要注意的是 invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK 语句中， MB_OK 和 NULL 已经预定义在 Windows.inc 中。<br><br><strong>Win32汇编教程三<br></strong>一个简单的对话框 --- 兼谈资源文件的使用<br><br>Windows 的资源文件<br><br>&nbsp;&nbsp;&nbsp;&nbsp;不管在Dos下编程还是在Windows下编程，我们总是要用到除了可执行文件外的很多其他数据，如声音数据，图形数据，文本等等，在Dos下编程，我们可以自己定义这些文件的格式，但这样一来就造成了很多资源共享的问题，大家可能还记的Dos下的很多游戏，它们的图形都是按自己的格式存放的，你无法用标准的看图软件来看。也无法把它另存为其他格式。虽然在Win32编程中，我们仍然可以这样做，但Win32编程给了我们一个方案 ---- 就是格式统一的资源文件，把字符串、图形、对话框包括上面的按钮，文本等定义到一个资源文件中，就可以方便的在不同的文件中使用它，最重要的是，如果我们用自己的文件格式，使用时就要涉及到这些文件的读写操作，比较复杂，但使用资源文件时，Windows提供了一系列的API来装入资源。非常方便。现在，让我们来看一个很简单的资源文件的源文件，它的扩展名是 .rc，当它用资源编译器编译以后产生 .res 文件就可以在 link的时候连入.exe 文件中：<br><br><br>＃i nclude&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Resource.h&gt;<br>#define&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DLG_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1<br><br>DLG_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DIALOGEX 0, 0, 236, 185<br>STYLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DS_MODAL<em>FRame</em> | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SY***ENU<br>CAPTION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "对话框模板"<br>FONT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9, "宋体"<br>BEGIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFPUSHBUTTON&nbsp;&nbsp; "退出",IDOK,177,163,50,14<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONTROL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "",-1,"Static",SS_ETCHEDHORZ,7,155,222,1<br>END<br>现在我简单解释一下 .rc文件的语法：<br><br>＃i nclude &lt;resource.h&gt; -- resource.h文件包括资源文件的一些常量定义，如下面的 WS_POPUP,WS_VISIBLE 等窗口的风格等等<br><br>#define DLG_MAIN 1 -- 类似于 .asm 文件的 equ 语句，和汇编源程序一样，这些定义是为了程序的可读性。<br><br>DLG_MAIN DIALOGEX 0,0,236,185<br><br>Windows的.rc文件可以定义 BITMAP(位图),CURSOR(光标),ICON(图标),ACCELERATORS(加速键),DIALOG(对话框),MENU(菜单),STRINGTABLE(字符串表),RCDATA(自定义资源)等8种资源，详细的描述可以参考有关MFC的书籍，在Win32A***中的资源编译器的语法中，一般格式是这些资源的定义方法是：<br><br>位图定义： nameID BITMAP [load-mem] filename<br>光标定义： nameID CURSOR [load-mem] filename <br>图标定义： nameID ICON [load-mem] filename <br>加速键定义：<br>acctablename ACCELERATORS [optional-statements]<br>BEGIN event, idvalue, [type] [options]<br>. . .<br>END <br><br>等等，具体的定义和参数可以参考 Masm32v5 中的 Rc.hlp 帮助文件。我们可以用资源编辑器来所见即所得地编辑资源，也可以在文本编辑器中用上面这些语句自己定义资源。<br><br>在程序中使用资源<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在程序中，要使用资源之前必须先装如内存，Windows定义了一系列的API来装入资源，如 LoadMenu，LoadString，LoadBitmap 等等，如 LoadBitmap 的定义： <br>HBITMAP LoadBitmap( <br>HINSTANCE hInstance, // handle of application instance <br>LPCTSTR lpBitmapName // address of bitmap resource name <br>); <br>&nbsp;&nbsp;&nbsp;&nbsp;这些Load函数的返回值是一个句柄，调用参数中一般至少为两项： hInstance 和 ResouceName，这个 ResouceName(如BitmapName,MenuName)就是在资源文件中的 #define 指定的值，如果你用 #define MY_ICON 10/ MY_ICON ICON "Main.ico" 定义了一个图标，那么在程序中要使用 Main.ico 图标就可以用 LoadIcon(hInstance,10) 来装入已经定义为10号的图标文件。另一个参数 hInstance 是执行文件的句柄，它对应资源所在的文件名，你可以在程序开始执行时用 invoke GetModuleHandle,NULL 获得 hInstance。另外一些资源并不是显式地装入的，如对话框资源，它是在建立对话框的函数中由Windows自己装入的，如下面例子中的 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0 ，是在屏幕上显示一个资源文件中已经定义好了的对话框，就并不存在 LoadDialogBox 之类的API来先装入对话框。<br><br>Win32A*** - 显示一个对话框<br><br>介绍了这么多相关的东西，现在让我们来看看如何显示一个对话框，源程序如下： <br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.386<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.model flat, stdcall<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;option casemap :none&nbsp;&nbsp; ; case sensitive<br><br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; windows.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kernel32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; comctl32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; comdlg32.inc<br><br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kernel32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comctl32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comdlg32.lib<br><br>DLG_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equ&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.data?<br><br>hInstance&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?<br>szBuffer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;256 dup (?)<br><br>_ProcDlgMain&nbsp;&nbsp;&nbsp;&nbsp;PROTO&nbsp;&nbsp; :DWORD,:DWORD,:DWORD,:DWORD<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.data<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.code<br><br>;********************************************************************<br>_ProcDlgMain&nbsp;&nbsp;&nbsp;&nbsp;proc&nbsp;&nbsp;&nbsp;&nbsp;uses ebx edi esi, \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,wMsg<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.if&nbsp;&nbsp;&nbsp;&nbsp; eax == WM_CLOSE<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;invoke&nbsp;&nbsp;EndDialog,hWnd,NULL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.elseif eax == WM_INITDIALOG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.elseif eax == WM_COMMAND<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;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,wParam<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;.if&nbsp;&nbsp;&nbsp;&nbsp; eax == IDOK<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;invoke&nbsp;&nbsp;EndDialog,hWnd,NULL<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;.elseif eax == IDCANCEL<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;invoke&nbsp;&nbsp;EndDialog,hWnd,NULL<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;.endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.else<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;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,FALSE<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;ret<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.endif&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;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,TRUE<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>_ProcDlgMain&nbsp;&nbsp;&nbsp;&nbsp;endp<br>;********************************************************************<br>start:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;InitCommonControls<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;GetModuleHandle,NULL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; hInstance,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;ExitProcess,NULL<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;&nbsp;&nbsp;&nbsp; start<br><br>看了前面几篇文章以后，这儿的大部分语句应该是很熟悉了，我来讲解几句新的语句：<br><br>_ProcDlgMain PROTO :DWORD,:DWORD,:DWORD,:DWORD<br><br>PROTO 语句类似于C语言中的函数定义，在Win32汇编中，如果子程序的定义在引用以后，你就必须先定义，当然，这个定义是针对 invoke 语句和其他带参数的调用的，如果你的子程序没有参数，你就可以用 call 指令去调用它而不是用宏指令 invoke，这时候你就不必声明这个函数。<br><br>_ProcDlgMain proc uses ebx edi esi, \<br>hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD<br><br>这个定义 proc 的语句应该是不陌生的，要重复讲解一下的是 uses 和 下面的参数，uses 下的寄存器表示要编译器自动插入保存及恢复这些寄存器的指令，\ 是在 Masm32 中接下一行的符号，表示下一行是本行的继续内容，以避免一行中的内容过长。下面的 hWnd:DWORD 等语句定义了调用这个子程序的参数，如果有以下定义 MyProc proc dwPara1:DWORD,dwPara2:DWORD,dwPara3:DWORD，然后你用 invoke MyProc 1,2,3 来调用它，那么，1,2,3 将分别被赋值给 dwPara1,dwPara2,dwPara3，你可以在子程序中使用这些传递过来的参数。如果参数的类型是双字，那么:DWORD 可以省略。<br><br>.if/.else/.elseif/.endif<br><br>这些语句是宏指令，实际上不说你也知道它们的意思，有了这些宏指令，我们就可以把汇编编得象C一样结构清晰，而不必老是看到 jmp 指令了，当然，这只不过编译器帮你做了这些事情而已，如果你去反汇编一下，你开始会看到一大堆 jmp 指令，.if 的格式如下<br>.if eax == 1 如果eax等于1<br>.if eax != 1 如果eax不等于1<br>.if eax != 1 &amp;&amp; ebx != 2 如果eax不等于1且ebx不等于2<br>.if eax == 1 || ebx == 2 如果eax等于1或者ebx等于2<br>其他的宏指令还有 .while/.endw .break 等等，可以参考 Masm32V5 的帮助文件 Masm32.hlp<br><br>&nbsp;&nbsp;&nbsp;&nbsp;最后要讲到的就是 DialogBoxParam 这个API了，在Windows中，所有的窗口都要指定一个子程序，当Windows检测到鼠标、定时器等和这个窗口有关的动作时，它回调用这个子程序，这就是Windows基于消息的体系的最基本的概念，换句话说，在Dos下，我们通过INT指令调用系统，而在Windows 下，有很多时候是你指定子程序地址让Windows来调用你。 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0中的 offset _ProcDlgMain 就指定了如果有消息发生，Windows就来执行这个子程序，参数中的 DLG_MAIN 就是在资源文件中定义的对话框模板编号。 hInstance 是对话框所在的资源文件的句柄。<br>&nbsp;&nbsp;&nbsp;&nbsp;另外，在_ProcDlgMain 子程序中，Windows传给我们4个参数hWnd,wMsg,wParam,lParam，其中，hWnd是对话框的窗口句柄，wMsg表示现在发生的消息事件，如这个对话框初始化时Windows会以WM_INITDIALOG为消息调用，关闭时为WM_CLOSE，按下对话框上的按钮时为WM_COMMAND等，wParam和lParam是附加的参数，对应不同的消息对应不同定义，具体可以参考Win32 Programmer's reference。<br><br><strong>Win32汇编教程四<br></strong>编写一个简单的窗口<br><br>有关窗口的基本知识<br><br>&nbsp;&nbsp;&nbsp;&nbsp;窗口是屏幕上的矩形区域。一个窗口可以从键盘或者鼠标接受用户的输入，并在其内部显示图形输出。一个应用程序窗口通常包含程序的标题条、菜单、边框，滚动条。其中，对话框也是一种窗口。不同的是，对话框表面通常包含几个其它窗口，称之为&#8220;子窗口&#8221;。这些子窗口的形式有压入按钮、单选按钮、复选框、文本输入区域、列表框和滚动条等。 用户将这些窗口看成屏幕上的对象，可以通过按下一个按钮或者滚动一个滚动条与这些对象直接交互。<br>&nbsp;&nbsp;&nbsp;&nbsp;窗口以&#8220;消息&#8221;的形式接收窗口的输入，窗口也用消息与其它窗口通讯。比如在程序窗口的大小改变时，字处理器会重新格式化其中的文本。窗口大小改变的细节是由操作系统处理的，但程序能够响应这个系统功能。当用户改变窗口的大小时，Windows给程序发送一条消息指出新窗口的大小。然后，程序就可以调整窗口中的内容，以响应大小的变化。程序创建的每一个窗口都有相关的窗口过程。也就是给这个窗口指定一个子程序（窗口过程），Windows通过调用它来给窗口发送消息。窗口过程再根据此消息进行处理，然后将控制返回给Windows。<br>&nbsp;&nbsp;&nbsp;&nbsp;窗口在&#8220;窗口类&#8221;的基础上创建的。Windows定义了确省的窗口过程，如果你对所有的消息都让Windows自己处理，那么你就能得到一个标准的窗口，同样，你也可以选择处理自己感兴趣的消息，这样，相当于产生了不同的子类，也就形成了不同的应用程序。同样，子窗口也是基于同一个窗口类，并且使用同一个窗口过程。例如，所有Windows 程序中的所有按钮都基于同一窗口类。这个窗口类有一个处理所有按钮消息的窗口过程，但是，如果你按自己的设想设计一个按钮，如想把按钮的表面换成位图，你就可以自己处理按钮窗口的 WM_PAINT 消息，当 Windows 需要画按钮表面的时候，你就可以随自己的意思去画。<br>&nbsp;&nbsp;&nbsp;&nbsp;Windows程序开始执行后，Windows为该程序创建一个&#8220;消息队列&#8221;。这个消息队列用来存放该程序可能创建的各种不同窗口的消息。程序中有一段代码，叫做&#8220;消息循环&#8221;， 它用来从队列中取出消息，并且将它们发送给相应的窗口过程。在没有消息发生的时候，你的程序实际上就在消息循环中转圈子。<br>&nbsp;&nbsp;&nbsp;&nbsp;创建一个窗口的过程如下： <br><br>取得程序的实例句柄(hInstance) <br>注册窗口类，实际上就是为你的窗口指定处理消息的过程，定义光标，窗口风格，颜色等参数 <br>创建窗口 <br>显示窗口 <br>然后进入消息循环，也就是不停地检测有无消息，并把它发送给窗口进程去处理。 <br>创建一个窗口的代码在不同的程序中实际上是几乎一模一样的，所以你编一个新的程序时可以把这一段拷来拷去，稍微修改一下就行，程序的大部分代码实际上是用在窗口过程中，因为这才是不同程序的不同之处。窗口过程的编程要点如下： <br><br>从Windows传给窗口过程的参数 uMsg 得到消息类型，并转到不同的分枝去处理。 <br>对自己已经处理的消息，返回 Windows 时必须在eax 中返回0。 <br>自己不处理的消息，必须调用 DefWindowProc 处理，并把返回值传回Windows，否则，Windows会无法显示。 <br>uMsg 参数中指定的消息有280多种，实际上我们需要处理的只有重要的几种，如Windows在创建的时候会发送 WM_CREATE 消息，我们就可以在这时候初始化，分配内存等等，而退出时会发送 WM_CLOSE，我们就可以进行释放内存等清除工作，当Windows上的菜单或按钮被按下时发送 WM_COMMAND 消息等等，具体可以参考 Win32 Programmer's Reference。下面，我们来看一个创建窗口的简单程序。<br><br>一个创建窗口的程序<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.386<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.model flat, stdcall<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;option casemap :none&nbsp;&nbsp; ; case sensitive<br><br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; windows.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kernel32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; comctl32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; comdlg32.inc<br>include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gdi32.inc<br><br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kernel32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comctl32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comdlg32.lib<br>includelib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gdi32.lib<br><br>IDI_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equ&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;icon<br><br>IDM_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equ&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;menu<br>IDM_EXIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equ&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4001<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.data?<br><br>hInstance&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?<br>hWinMain&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?<br>hMenu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?<br>szBuffer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;256 dup (?)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.data<br><br>szClassName&nbsp;&nbsp;&nbsp;&nbsp; db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Windows Template",0<br>szCaptionMain&nbsp;&nbsp; db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'窗口模板',0<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.code<br><br>start:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;_WinMain<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;ExitProcess,NULL<br><br>_WinMain&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proc<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;&nbsp; @stWcMain:WNDCLASSEX<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;&nbsp; @stMsg:MSG<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;InitCommonControls<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;GetModuleHandle,NULL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; hInstance,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;LoadIcon,hInstance,IDI_MAIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; hIcon,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;LoadMenu,hInstance,IDM_MAIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; hMenu,eax<br>;*************** 注册窗口类 *****************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;LoadCursor,0,IDC_ARROW<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.hCursor,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.cbSize,sizeof WNDCLASSEX<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.hIconSm,0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.style,CS_HREDRAW or CS_VREDRAW<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.lpfnWndProc,offset WndMainProc<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.cbClsExtra,0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.cbWndExtra,0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,hInstance<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.hInstance,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.hIcon,0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.hbrBackground,COLOR_WINDOW + 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.lpszClassName,offset szClassName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; @stWcMain.lpszMenuName,0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;RegisterClassEx,addr @stWcMain<br>;*************** 建立输出窗口 ***************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;CreateWindowEx,WS_EX_CLIENTEDGE,\<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;offset szClassName,offset szCaptionMain,\<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;WS_OVERLAPPEDWINDOW OR WS_VSCROLL OR WS_HSCROLL,\<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;0,0,550,300,\<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;NULL,hMenu,hInstance,NULL<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;ShowWindow,hWinMain,SW_SHOWNORMAL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;UpdateWindow,hWinMain<br>;*************** 消息循环 *******************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.while&nbsp;&nbsp;TRUE<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;invoke&nbsp;&nbsp;GetMessage,addr @stMsg,NULL,0,0<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;.break&nbsp;&nbsp;.if eax == 0<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;invoke&nbsp;&nbsp;TranslateMessage,addr @stMsg<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;invoke&nbsp;&nbsp;DispatchMessage,addr @stMsg<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.endw<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret<br><br>_WinMain&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;endp<br>;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;<br>WndMainProc&nbsp;&nbsp;&nbsp;&nbsp; proc&nbsp;&nbsp;&nbsp;&nbsp;uses ebx edi esi, \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,uMsg<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.if&nbsp;&nbsp;&nbsp;&nbsp; eax ==&nbsp;&nbsp;WM_CREATE<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;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,hWnd<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;mov&nbsp;&nbsp;&nbsp;&nbsp; hWinMain,eax<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;call&nbsp;&nbsp;&nbsp;&nbsp;_Init<br>;********************************************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.elseif eax ==&nbsp;&nbsp;WM_COMMAND<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .if&nbsp;&nbsp;lParam == 0<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;mov&nbsp;&nbsp;&nbsp;&nbsp; eax,wParam<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;.if&nbsp;&nbsp;&nbsp;&nbsp; ax == IDM_EXIT<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;call&nbsp;&nbsp;&nbsp;&nbsp;_Quit<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;.endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .endif<br>;********************************************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.elseif eax ==&nbsp;&nbsp;WM_CLOSE<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;call&nbsp;&nbsp;&nbsp;&nbsp;_Quit<br>;********************************************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.else<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;invoke&nbsp;&nbsp;DefWindowProc,hWnd,uMsg,wParam,lParam<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;ret<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xor&nbsp;&nbsp;&nbsp;&nbsp; eax,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret<br><br>WndMainProc&nbsp;&nbsp;&nbsp;&nbsp; endp<br><br>_Init&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;SendMessage,hWinMain,WM_SETICON,ICON_***ALL,hIcon<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret<br><br>_Init&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; endp<br>;********************************************************************<br>_Quit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;DestroyWindow,hWinMain<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;PostQuitMessage,NULL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret<br><br>_Quit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; endp<br>;********************************************************************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;&nbsp;&nbsp;&nbsp; start<br>窗口程序的分析<br><br>&nbsp;&nbsp;&nbsp;&nbsp;让我们来简单分析一下这个程序，首先程序调用 _WinMain，在_WinMain 中定义了两个局部变量 @stMsg 和 @stWinMain，数据类型分别是 MSG 和 WNDCLASSEX结构，在参考手册中，可以看到WNDCLASSEX定义了一个窗口的所有参数，如使用的菜单、光标、颜色、窗口过程等，接下来的一大堆 mov 指令实际上就是在填写这个数据结构，填写完成后，最重要的两句是 mov @stWcMain.lpfnWndProc,offset WndMainProc 定义了处理消息的窗口过程， mov @stWcMain.lpszClassName,offset szClassName 定义了你要创建的类的名称，然后就是使用 RegisterClassEx 注册这个窗口类，注意，这时候窗口并没有创建，你只不过是定义好了一个子类，接下去你要用你定义的类去创建一个窗口。也就是使用 CreateWindowEx 函数去创建它。在手册中，CreateWindowEx 是这样定义的：<br><br>HWND CreateWindowEx( <br>DWORD dwExStyle, // extended window style <br>LPCTSTR lpClassName, // pointer to registered class name <br>LPCTSTR lpWindowName, // pointer to window name <br>DWORD dwStyle, // window style <br>int x, // horizontal position of window <br>int y, // vertical position of window <br>int nWidth, // window width <br>int nHeight, // window height <br>HWND hWndParent, // handle to parent or owner window <br>HMENU hMenu, // handle to menu, or child-window identifier <br>HINSTANCE hInstance, // handle to application instance <br>LPVOID lpParam // pointer to window-creation data ); <br><br>其中的参数 dwExStyle 是窗口的风格，lpClassName 就是我们自己定义的类的名字。如果大家要创建一个已经定义好的类，如 RichEdit 类等等，只要把 lpClassName 指向 "RichEdit32" 字符串就行了，当然这时就不用 RegisterClass 以及编写自己的窗口过程了。执行 CreateWindowEx 后，得到一个返回值就是窗口句柄，这个值在以后是要经常用到了，所以要先保存下来。这时窗口并没有在屏幕上显示出来，而是处于隐藏状态，我们要用 ShowWindow 来显示出窗口并用UpdateWindow 来绘窗口的内容。<br>&nbsp;&nbsp;&nbsp;&nbsp;窗口显示出来后，程序就进入一个循环----消息循环，前面我已经说过，作用是不停地接收 Windows 消息并发送给窗口过程去处理。GetMessage 从消息队列中取出一条消息，如果取得的消息不是 WM_QUIT，那么 GetMessage 返回一个非零值，否则返回零，这时候循环结束，程序执行 ExitProcess退回操作系统。TranslateMessage 将消息进行一些键盘转换，用于处理一些快捷键，DispatchMessage 将处理后的消息发回 Windows，由Windows调用窗口进程进行处理，当窗口进程处理完返回后，程序才从 DispatchMessage 返回，从而开始下一个 GetMessage 调用。这些函的参数可以参考手册。<br><br>窗口过程的分析<br><br>&nbsp;&nbsp;&nbsp;&nbsp;窗口过程有四个参数，hWnd 是本窗口的句柄，和创建窗口时返回的值相同，uMsg 是本次调用的消息类型，wParam 和lParam是消息的参数，其含义和数值根据消息的不同而不同。在本程序中，我们处理 WM_CREATE,WM_COMMAND 和 WM_QUIT 消息，然后返回0，对不处理的消息，使用 invoke DefWindowProc,hWnd,uMsg,wParam,lParam 来处理并直接用 ret 将返回值传回 Windows。在响应 WM_CLOSE 消息时，我们用 DestroyWindow 清除窗口并用PostQuitMessage 产生一条 WM_QUIT 消息，从而使程序在 消息循环调用GetMessage 时返回0，以结束消息循环并结束程序。 
<img src ="http://www.cppblog.com/andxie99/aggbug/13481.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-09 11:17 <a href="http://www.cppblog.com/andxie99/archive/2006/10/09/13481.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件工程知识体系全景图</title><link>http://www.cppblog.com/andxie99/archive/2006/09/28/13072.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 28 Sep 2006 00:37:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/09/28/13072.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13072.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/09/28/13072.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13072.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13072.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 来源：http://blog.csdn.net/kongdong/参考：《中国软件工程学科教程》（清华大学出版社）ISBN 7-302-0980206/TP.6763 ...&nbsp;&nbsp;<a href='http://www.cppblog.com/andxie99/archive/2006/09/28/13072.html'>阅读全文</a><img src ="http://www.cppblog.com/andxie99/aggbug/13072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-09-28 08:37 <a href="http://www.cppblog.com/andxie99/archive/2006/09/28/13072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[SQL Server]管理常用SQL语句</title><link>http://www.cppblog.com/andxie99/archive/2006/08/14/11213.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Mon, 14 Aug 2006 05:14:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/08/14/11213.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/11213.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/08/14/11213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/11213.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/11213.html</trackback:ping><description><![CDATA[<p><br><strong>1. 查看数据库的版本</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　 select @@version </p>
<p><strong>2. 查看数据库所在机器操作系统参数</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　exec master..xp_msver </p>
<p><br><strong>3. 查看数据库启动的参数</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　sp_configure </p>
<p><br><strong>4. 查看数据库启动时间</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　select convert(varchar(30),login_time,120) from master..sysprocesses where spid=1 </p>
<p>　　查看数据库服务器名和实例名 </p>
<p>　　print 'Server Name...............：' + convert(varchar(30),@@SERVERNAME)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　print 'Instance..................：' + convert(varchar(30),@@SERVICENAME)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><strong>5. 查看所有数据库名称及大小&nbsp;</strong>&nbsp;&nbsp;&nbsp; </p>
<p>　　sp_helpdb </p>
<p>　　重命名数据库用的SQL </p>
<p>　　sp_renamedb 'old_dbname', 'new_dbname' </p>
<p><br><strong>6. 查看所有数据库用户登录信息</strong>&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　sp_helplogins </p>
<p>　　查看所有数据库用户所属的角色信息&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　sp_helpsrvrolemember </p>
<p>　　修复迁移服务器时孤立用户时,可以用的fix_orphan_user脚本或者LoneUser过程 </p>
<p>　　更改某个数据对象的用户属主 <br>　　<br>　　sp_changeobjectowner [@objectname =] 'object', [@newowner =] 'owner' </p>
<p>　　注意：更改对象名的任一部分都可能破坏脚本和存储过程。 </p>
<p>　　把一台服务器上的数据库用户登录信息备份出来可以用add_login_to_aserver脚本 </p>
<p>　　查看某数据库下,对象级用户权限 </p>
<p>　　sp_helprotect </p>
<p><br><strong>7. 查看链接服务器</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>　　<br>　　sp_helplinkedsrvlogin </p>
<p>　　查看远端数据库用户登录信息<br>　　<br>　　sp_helpremotelogin </p>
<p><br><strong>8.查看某数据库下某个数据对象的大小</strong> </p>
<p>　　sp_spaceused @objname </p>
<p>　　还可以用sp_toptables过程看最大的N(默认为50)个表 </p>
<p>　　查看某数据库下某个数据对象的索引信息 </p>
<p>　　sp_helpindex @objname </p>
<p>　　还可以用SP_NChelpindex过程查看更详细的索引情况 </p>
<p>　　SP_NChelpindex @objname </p>
<p>　　clustered索引是把记录按物理顺序排列的，索引占的空间比较少。&nbsp; </p>
<p>　　对键值DML操作十分频繁的表我建议用非clustered索引和约束，fillfactor参数都用默认值。 </p>
<p>　　查看某数据库下某个数据对象的的约束信息 </p>
<p>　　sp_helpconstraint @objname</p>
<p><strong>9.查看数据库里所有的存储过程和函数</strong> </p>
<p><br>　　use @database_name </p>
<p><br>　　sp_stored_procedures </p>
<p><br>　　查看存储过程和函数的源代码 </p>
<p><br>　　sp_helptext <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#39;&#64;&#112;&#114;&#111;&#99;&#101;&#100;&#117;&#114;&#101;&#95;&#110;&#97;&#109;&#101;&#39;">'@procedure_name'</a></p>
<p><br>　　查看包含某个字符串@str的数据对象名称 </p>
<p><br>　　select distinct object_name(id) from syscomments where text like <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#39;&#37;&#64;&#115;&#116;&#114;&#37;&#39;">'%@str%'</a></p>
<p><br>　　创建加密的存储过程或函数在AS前面加WITH ENCRYPTION参数 </p>
<p><br>　　解密加密过的存储过程和函数可以用sp_decrypt过程 </p>
<p>&nbsp;</p>
<p><strong>10.查看数据库里用户和进程的信息</strong> </p>
<p>　　sp_who </p>
<p>　　查看SQL Server数据库里的活动用户和进程的信息 </p>
<p>　　sp_who 'active' </p>
<p>　　查看SQL Server数据库里的锁的情况 </p>
<p>　　sp_lock </p>
<p>　　进程号1--50是SQL Server系统内部用的,进程号大于50的才是用户的连接进程. <br>　　<br>　　spid是进程编号,dbid是数据库编号,objid是数据对象编号 </p>
<p>　　查看进程正在执行的SQL语句 </p>
<p>　　dbcc inputbuffer () </p>
<p>　　推荐大家用经过改进后的sp_who3过程可以直接看到进程运行的SQL语句 </p>
<p>　　sp_who3 </p>
<p>　　检查死锁用sp_who_lock过程 </p>
<p>　　sp_who_lock&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><strong>11.查看和收缩数据库日志文件的方法</strong></p>
<p>　　查看所有数据库日志文件大小&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>　　dbcc sqlperf(logspace) </p>
<p>　　如果某些日志文件较大，收缩简单恢复模式数据库日志，收缩后@database_name_log的大小单位为M </p>
<p>　　backup log @database_name with no_log </p>
<p>　　dbcc shrinkfile (@database_name_log, 5) </p>
<p><br><strong>12.分析SQL Server SQL 语句的方法：</strong> </p>
<p>　　set statistics time {on | off} </p>
<p>　　set statistics io {on | off} </p>
<p>　　图形方式显示查询执行计划 </p>
<p>　　在查询分析器-&gt;查询-&gt;显示估计的评估计划(D)-Ctrl-L&nbsp;&nbsp;&nbsp; 或者点击工具栏里的图形 </p>
<p>　　文本方式显示查询执行计划 </p>
<p>　　set showplan_all {on | off} </p>
<p>　　set showplan_text { on | off } </p>
<p>　　set statistics profile { on | off } </p>
<p><br><strong>13.出现不一致错误时，NT事件查看器里出3624号错误，修复数据库的方法</strong> <br>　　先注释掉应用程序里引用的出现不一致性错误的表，然后在备份或其它机器上先恢复然后做修复操作 </p>
<p>　　alter database [@error_database_name] set single_user </p>
<p>　　修复出现不一致错误的表 </p>
<p>　　dbcc checktable(<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#39;&#64;&#101;&#114;&#114;&#111;&#114;&#95;&#116;&#97;&#98;&#108;&#101;&#95;&#110;&#97;&#109;&#101;&#39;&#44;&#114;&#101;&#112;&#97;&#105;&#114;&#95;&#97;&#108;&#108;&#111;&#119;&#95;&#100;&#97;&#116;&#97;&#95;&#108;&#111;&#115;&#115;">'@error_table_name',repair_allow_data_loss</a>) </p>
<p>　　或者可惜选择修复出现不一致错误的小型数据库名 </p>
<p>　　dbcc checkdb(<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#39;&#64;&#101;&#114;&#114;&#111;&#114;&#95;&#100;&#97;&#116;&#97;&#98;&#97;&#115;&#101;&#95;&#110;&#97;&#109;&#101;&#39;&#44;&#114;&#101;&#112;&#97;&#105;&#114;&#95;&#97;&#108;&#108;&#111;&#119;&#95;&#100;&#97;&#116;&#97;&#95;&#108;&#111;&#115;&#115;">'@error_database_name',repair_allow_data_loss</a>) </p>
<p>　　alter database [@error_database_name] set multi_user </p>
<p>　　CHECKDB 有3个参数：</p>
<p>　　repair_allow_data_loss 包括对行和页进行分配和取消分配以改正分配错误、结构行或页的错误，以及删除已损坏的文本对象，这些修复可能会导致一些数据丢失。 </p>
<p>　　修复操作可以在用户事务下完成以允许用户回滚所做的更改。 </p>
<p>　　如果回滚修复，则数据库仍会含有错误，应该从备份进行恢复。 </p>
<p>　　如果由于所提供修复等级的缘故遗漏某个错误的修复，则将遗漏任何取决于该修复的修复。 </p>
<p>　　修复完成后，请备份数据库。&nbsp; </p>
<p>　　repai*_**st 进行小的、不耗时的修复操作，如修复非聚集索引中的附加键。 </p>
<p>　　这些修复可以很快完成，并且不会有丢失数据的危险。&nbsp; </p>
<p>　　repair_rebuild 执行由 repai*_**st 完成的所有修复，包括需要较长时间的修复（如重建索引）。 </p>
<p>　　执行这些修复时不会有丢失数据的危险。<br></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/11213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-08-14 13:14 <a href="http://www.cppblog.com/andxie99/archive/2006/08/14/11213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>电脑容量单位</title><link>http://www.cppblog.com/andxie99/archive/2006/08/08/10994.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 08 Aug 2006 06:33:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/08/08/10994.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/10994.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/08/08/10994.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/10994.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/10994.html</trackback:ping><description><![CDATA[<div class=textbox-title>
<h4>&nbsp;</h4>
</div>
<div class=textbox-content>计算机容量分为YB、ZB、EB、PB、TB、GB、MB、KB、Byte。<br><br>既然有YB这个名词出现了，应该是说有人至少具有或共有1YB的容量吧。<br><br>世界上有没有人使用1YB的硬盘，还是那只是空虚的名词。<br><br>备注:计算机容量分配一览表<br>YB (Yota-byte) &gt; ZB (Zeta-byte) &gt; EB (Exa-byte) &gt; PB (Peta-byte) &gt; TB (Tera-byte) &gt; GB (Giga-byte) &gt; MB (Mega-byte) &gt; KB (Kilo-byte) &gt; Byte &gt; Bit<br><br>1Byte = 8 Bit<br>1 KB = 1,024 Bytes<br>1 MB = 1,024 KB = 1,048,576 Bytes<br>1 GB = 1,024 MB = 1,048,576 KB = 1,073,741,824 Bytes<br>1 TB = 1,024 GB = 1,048,576 MB = 1,073,741,824 KB = 1,099,511,627,776 Bytes<br>1 PB = 1,024 TB = 1,048,576 GB = ... = 1,125,899,906,842,624 Bytes<br>1 EB = 1,024 PB = 1,048,576 TB = ... = 1,152,921,504,606,846,976 Bytes <br>1 ZB = 1,024 EB = ... = 1,180,591,620,717,411,303,424 Bytes<br>1 YB = 1,024 ZB = ... = 1,208,925,819,614,629,174,706,176 Bytes<br><br>目前 YB是计算机界已知最大的储存空间单位。以一个250GB的硬盘而言， 1YB就需要约4兆5千亿个这样的硬盘。再大的单位恐怕在短期间内是还用不到的。</div>
<img src ="http://www.cppblog.com/andxie99/aggbug/10994.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-08-08 14:33 <a href="http://www.cppblog.com/andxie99/archive/2006/08/08/10994.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开拓思维   摘自《编程高手箴言》作者：梁肇新 </title><link>http://www.cppblog.com/andxie99/archive/2006/07/27/10585.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 27 Jul 2006 07:34:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/07/27/10585.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/10585.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/07/27/10585.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/10585.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/10585.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'"><font size=3>因为计算机技术没有任何时候是突变的。它的今年和去年相差不会很大，但是回过头来看三年以前的情况，和现在的距离就很大。所以说，如果你每年都跟着技术进步的话，你的压力就很小，因为你时刻都能掌握最新的技术。但是，如果你落下来，别说十年，就是三年，你就赶不上了。</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'"><font size=3>如果你一旦赶不上，就会觉得非常吃力；如果你赶不上，你就会迷失方向；如果你迷失了方向，你就觉得计算机没有味道，越做越没劲。当你还只是有个思路的时候，别人的产品都做出来了，因为你的水平跟别人相差太远，人家早就想到的问题，你现在才开始认识。水平越高，他就看得越远，那么他的思维就越开阔；水平越低，想的问题就越窄。</font></span></p>
<div style="BORDER-RIGHT: windowtext 1.5pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1.5pt solid; PADDING-LEFT: 4pt; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 10.5pt; BORDER-LEFT: windowtext 1.5pt solid; MARGIN-RIGHT: 10.5pt; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1.5pt solid; mso-border-shadow: yes; mso-element: para-border-div">
<p class=a style="MARGIN: 12pt 0cm 0pt; TEXT-INDENT: 57.7pt; LINE-HEIGHT: 18pt; mso-para-margin-bottom: .0001pt; mso-para-margin-top: 1.0gd; mso-char-indent-count: 5.77; mso-line-height-rule: exactly; mso-para-margin-left: 0cm; mso-para-margin-right: 0cm"><v:shapetype id=_x0000_t75 o:preferrelative="t" filled="f" stroked="f" coordsize="21600,21600" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype><v:shape id=_x0000_s1026 style="MARGIN-TOP: 7.9pt; Z-INDEX: 1; LEFT: 0px; MARGIN-LEFT: 14.2pt; WIDTH: 53.5pt; POSITION: absolute; HEIGHT: 28pt; TEXT-ALIGN: left" filled="t" type="#_x0000_t75"><font size=3><v:imagedata src="file:///D:\DOCUME~1\刘伟\LOCALS~1\Temp\msohtml1\01\clip_image001.png" o:title="cq"></v:imagedata><o:lock v:ext="edit" aspectratio="f"></o:lock></font></v:shape><font size=3><span lang=EN-US>64</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位</span><span lang=EN-US>CPU</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">是这个十年和下个十年最重要的技术之一，谁抓住这个机会，谁就能抓住未来赚钱的商机。</span><span lang=EN-US>CPU</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">是英特尔设计的，对这一点他肯定清楚。举例来说，如果从</span><span lang=EN-US>64</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位的角度来看现在的</span><span lang=EN-US>32</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位，就像从现在的角度去看</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">。你说</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">很复杂吗？当你在</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">年代的时候，你会觉得</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">很复杂。你说现在的</span><span lang=EN-US>Windows</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">不够复杂吗？</span><span lang=EN-US>Windows</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">太复杂了，但是你到了</span><span lang=EN-US>64</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位的时候再去看</span><span lang=EN-US>Windows</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">，就如同现在看</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">一样。</span></font></p>
<p class=a style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">整个</span><span lang=EN-US>64</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位系统的平台和思维方式、思路都比现在更开阔，打个比方说，现在的</span><span lang=EN-US>Windows</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">里面能开</span><em><span lang=EN-US>n</span></em><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">个</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">窗口，每个</span><span lang=EN-US>DOS</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">窗都能运行一个程序。到达</span><span lang=EN-US>64</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位的时候，操作系统事实上能做到开</span><em><span lang=EN-US>n</span></em><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">个</span><span lang=EN-US>X86</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">，开</span><em><span lang=EN-US>n</span></em><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">个</span><span lang=EN-US>Windows 98</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">，然后再开</span><em><span lang=EN-US>n</span></em><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">个</span><span lang=EN-US>Windows 95</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">都没有问题，系统能做到这一步，甚至你的系统内开</span><em><span lang=EN-US>n</span></em><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">个</span><span lang=EN-US>Windows NT</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">都没有关系。这就是</span><span lang=EN-US>64</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位和</span><span lang=EN-US>32</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">位的差别。所以，微软的那些&#8220;老头&#8221;，四、五十岁的那几个做核心的人，现在正在玩这些东西。你说微软的技术它能不先进吗？是</span><span lang=EN-US>Linux</span><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">那几个玩家能搞定的吗？</span></font></p>
<p class=a style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span style="FONT-FAMILY: 楷体_GB2312; mso-ascii-font-family: 'Times New Roman'">微软的技术非常雄厚，世界计算机的最新技术绝对集中在这几个人手里。而且这几个人的思维模式非常开阔，谁都没有意识到的东西他早就<span style="LETTER-SPACING: -0.1pt">开始做了。现在</span></span><span lang=EN-US style="LETTER-SPACING: -0.1pt">64</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: -0.1pt; mso-ascii-font-family: 'Times New Roman'">位的</span><span lang=EN-US style="LETTER-SPACING: -0.1pt">CPU</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: -0.1pt; mso-ascii-font-family: 'Times New Roman'">都出来一二年了，你说有什么人去做这些应用吗？没有，有的就是那几个</span><span lang=EN-US style="LETTER-SPACING: -0.1pt">UNIX</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: -0.1pt; mso-ascii-font-family: 'Times New Roman'">厂商做好后给自己用的。</span></font></p>
</div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span lang=EN-US><o:p><font size=3>&nbsp;</font></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'"><font size=3>所以，追求技术的最高境界的时候，实际上是没有年龄限制的。对我来说，现在都三十三了，我从来没有想过退出这行，我觉得我就能玩下去，一直玩到退休都没有问题。我要时刻保持技术的最前端，这样的话对我来说是不困难的，没有任何累的感觉。</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'"><font size=3>很多人说做程序不是人干的事情，是非人的待遇。这样，他们一旦成立一个公司，做出一点成绩，在辉煌的时候马上就考虑退出。因为他们太苦了，每天晚上熬夜，每天晚上烧了两包烟还不够，屋子里面简直就缺氧了，好像还没有解决问题。</font></span></p>
<p class=MsoBodyTextIndent2 style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span>白天睡觉，晚上干活，那当然累死了，这是自己折腾自己。所以，做程序员一定要有一种正常的心态，就是说，你做程序的时候，不要把自己的生活搞得颠三倒四的。如果非得搞得晚上烧好多<span style="COLOR: black">烟</span>才行，这样你肯定折腾不到三十岁，三十岁以后身体就差了。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">事实上，我基本上就没有因为做程序而熬夜的。我只经历过三次熬夜，一次是在学校的时候，</span><span lang=EN-US>1986</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">年刚接触计算机时，一天晚上跟一个同桌在计算机室内玩游戏，研究了半天，搞着搞着就到了天亮，这是第一次。然后在毕业之前，在</span><span lang=EN-US>286</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">上做一个程序。还有一次就是超级解霸上市前，那时公司已吹得很大了，那天晚上没法睡觉。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'"><font size=3>一般来说，我也是十二点钟睡觉，第二天七点就起了。所以说，只有具有正常的生活、正常的节奏，才有正常的心态来做程序员，这样，你的思路才是正常的，只有正常的东西才能长久。搞疲劳战或者是黑白颠倒，时间长久后就玩不转了，玩着玩着就不想玩了。</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'"><font size=3>只要你不想玩，不了解新技术，你就会落后，一旦落后，你再想追，就很难了。</font></span></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/10585.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-07-27 15:34 <a href="http://www.cppblog.com/andxie99/archive/2006/07/27/10585.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>理解矩阵（二）</title><link>http://www.cppblog.com/andxie99/archive/2006/07/05/9435.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 05 Jul 2006 06:27:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/07/05/9435.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9435.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/07/05/9435.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9435.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9435.html</trackback:ping><description><![CDATA[<p>原文地址：<a href="http://blog.csdn.net/myan/archive/2006/04/03/649018.aspx">http://blog.csdn.net/myan/archive/2006/04/03/649018.aspx</a><br><br>接着理解矩阵。</p>
<p>上一篇里说&#8220;矩阵是运动的描述&#8221;，到现在为止，好像大家都还没什么意见。但是我相信早晚会有数学系出身的网友来拍板转。因为运动这个概念，在数学和物理里是跟微积分联系在一起的。我们学习微积分的时候，总会有人照本宣科地告诉你，初等数学是研究常量的数学，是研究静态的数学，高等数学是变量的数学，是研究运动的数学。大家口口相传，差不多人人都知道这句话。但是真知道这句话说的是什么意思的人，好像也不多。简而言之，在我们人类的经验里，运动是一个连续过程，从A点到B点，就算走得最快的光，也是需要一个时间来<strong><u>逐点</u></strong>地经过AB之间的路径，这就带来了连续性的概念。而连续这个事情，如果不定义极限的概念，根本就解释不了。古希腊人的数学非常强，但就是缺乏极限观念，所以解释不了运动，被芝诺的那些著名悖论（飞箭不动、飞毛腿阿喀琉斯跑不过乌龟等四个悖论）搞得死去活来。因为这篇文章不是讲微积分的，所以我就不多说了。有兴趣的读者可以去看看齐民友教授写的《重温微积分》。我就是读了这本书开头的部分，才明白&#8220;高等数学是研究运动的数学&#8221;这句话的道理。</p>
<p>不过在我这个《理解矩阵》的文章里，&#8220;运动&#8221;的概念不是微积分中的连续性的运动，而是瞬间发生的变化。比如这个时刻在A点，经过一个&#8220;运动&#8221;，一下子就&#8220;<strong><u>跃迁</u></strong>&#8221;到了B点，其中不需要经过A点与B点之间的任何一个点。这样的&#8220;运动&#8221;，或者说&#8220;跃迁&#8221;，是违反我们日常的经验的。不过了解一点量子物理常识的人，就会立刻指出，量子（例如电子）在不同的能量级轨道上跳跃，就是瞬间发生的，具有这样一种跃迁行为。所以说，自然界中并不是没有这种运动现象，只不过宏观上我们观察不到。但是不管怎么说，&#8220;运动&#8221;这个词用在这里，还是容易产生歧义的，说得更确切些，应该是&#8220;跃迁&#8221;。因此这句话可以改成：</p>
<p>&#8220;矩阵是线性空间里跃迁的描述&#8221;。</p>
<p>可是这样说又太物理，也就是说太具体，而不够数学，也就是说不够抽象。因此我们最后换用一个正牌的数学术语——<strong><u>变换</u></strong>，来描述这个事情。这样一说，大家就应该明白了，<font color=#ff0000><strong>所谓变换，其实就是空间里从一个点（元素/对象）到另一个点（元素/对象）的跃迁</strong></font>。比如说，拓扑变换，就是在拓扑空间里从一个点到另一个点的跃迁。再比如说，仿射变换，就是在仿射空间里从一个点到另一个点的跃迁。附带说一下，这个仿射空间跟向量空间是亲兄弟。做计算机图形学的朋友都知道，尽管描述一个三维对象只需要三维向量，但所有的计算机图形学变换矩阵都是4 x 4的。说其原因，很多书上都写着&#8220;为了使用中方便&#8221;，这在我看来简直就是企图蒙混过关。真正的原因，是因为在计算机图形学里应用的图形变换，实际上是在仿射空间而不是向量空间中进行的。想想看，在向量空间里相一个向量平行移动以后仍是相同的那个向量，而现实世界等长的两个平行线段当然不能被认为同一个东西，所以计算机图形学的生存空间实际上是仿射空间。而仿射变换的矩阵表示根本就是4 x 4的。又扯远了，有兴趣的读者可以去看《计算机图形学——几何工具算法详解》。</p>
<p>一旦我们理解了&#8220;变换&#8221;这个概念，矩阵的定义就变成：</p>
<p><font color=#ff0000><strong>&#8220;矩阵是线性空间里的变换的描述。&#8221;</strong> </font></p>
<p>到这里为止，我们终于得到了一个看上去比较数学的定义。不过还要多说几句。教材上一般是这么说的，在一个线性空间V里的一个线性变换T，当选定一组基之后，就可以表示为矩阵。因此我们还要说清楚到底什么是线性变换，什么是基，什么叫选定一组基。线性变换的定义是很简单的，设有一种变换T，使得对于线性空间V中间任何两个不相同的对象x和y，以及任意实数a和b，有：<br>T(ax + by) = aT(x) + bT(y)，<br>那么就称T为线性变换。</p>
<p>定义都是这么写的，但是光看定义还得不到直觉的理解。线性变换究竟是一种什么样的变换？我们刚才说了，变换是从空间的一个点跃迁到另一个点，而线性变换，就是从一个线性空间V的某一个点跃迁到另一个线性空间W的另一个点的运动。这句话里蕴含着一层意思，就是说一个点不仅可以变换到同一个线性空间中的另一个点，而且可以变换到另一个线性空间中的另一个点去。不管你怎么变，只要变换前后都是线性空间中的对象，这个变换就一定是线性变换，也就一定可以用一个非奇异矩阵来描述。而你用一个非奇异矩阵去描述的一个变换，一定是一个线性变换。有的人可能要问，这里为什么要强调非奇异矩阵？所谓非奇异，只对方阵有意义，那么非方阵的情况怎么样？这个说起来就会比较冗长了，最后要把线性变换作为一种映射，并且讨论其映射性质，以及线性变换的核与像等概念才能彻底讲清楚。我觉得这个不算是重点，如果确实有时间的话，以后写一点。<strong>以下我们只探讨最常用、最有用的一种变换，就是在同一个线性空间之内的线性变换。也就是说，下面所说的矩阵，不作说明的话，就是方阵，而且是非奇异方阵。学习一门学问，最重要的是把握主干内容，迅速建立对于这门学问的整体概念，不必一开始就考虑所有的细枝末节和特殊情况，自乱阵脚。</strong></p>
<p>接着往下说，什么是基呢？这个问题在后面还要大讲一番，这里只要<strong><font color=#ff0000>把基看成是线性空间里的坐标系就可以了。</font></strong>注意是坐标系，不是坐标值，这两者可是一个&#8220;对立矛盾统一体&#8221;。这样一来，&#8220;选定一组基&#8221;就是说在线性空间里选定一个坐标系。就这意思。</p>
<p>好，最后我们把矩阵的定义完善如下：</p>
<p><font color=#ff0000><strong>&#8220;矩阵是线性空间中的线性变换的一个描述。在一个线性空间中，只要我们选定一组基，那么对于任何一个线性变换，都能够用一个确定的矩阵来加以描述。&#8221;</strong> </font></p>
<p><strong>理解这句话的关键，在于把&#8220;线性变换&#8221;与&#8220;线性变换的一个描述&#8221;区别开。</strong>一个是那个对象，一个是对那个对象的表述。就好像我们熟悉的面向对象编程中，一个对象可以有多个引用，每个引用可以叫不同的名字，但都是指的同一个对象。如果还不形象，那就干脆来个很俗的类比。</p>
<p>比如有一头猪，你打算给它拍照片，只要你给照相机选定了一个镜头位置，那么就可以给这头猪拍一张照片。这个照片可以看成是这头猪的一个描述，但只是一个片面的的描述，因为换一个镜头位置给这头猪拍照，能得到一张不同的照片，也是这头猪的另一个片面的描述。所有这样照出来的照片都是这同一头猪的描述，但是又都不是这头猪本身。</p>
<p><font color=#ff0000><strong>同样的，对于一个线性变换，只要你选定一组基，那么就可以找到一个矩阵来描述这个线性变换。换一组基，就得到一个不同的矩阵。所有这些矩阵都是这同一个线性变换的描述，但又都不是线性变换本身。</strong> </font></p>
<p>但是这样的话，问题就来了如果你给我两张猪的照片，我怎么知道这两张照片上的是同一头猪呢？同样的，你给我两个矩阵，我怎么知道这两个矩阵是描述的同一个线性变换呢？如果是同一个线性变换的不同的矩阵描述，那就是本家兄弟了，见面不认识，岂不成了笑话。</p>
<p>好在，我们可以找到同一个线性变换的矩阵兄弟们的一个性质，那就是：</p>
<p>若矩阵A与B是同一个线性变换的两个不同的描述（之所以会不同，是因为选定了不同的基，也就是选定了不同的坐标系），则一定能找到一个非奇异矩阵P，使得A、B之间满足这样的关系：</p>
<p>A = P<sup>-1</sup>BP</p>
<p>线性代数稍微熟一点的读者一下就看出来，这就是相似矩阵的定义。没错，<strong><font color=#ff0000>所谓相似矩阵，就是同一个线性变换的不同的描述矩阵。</font></strong>按照这个定义，同一头猪的不同角度的照片也可以成为相似照片。俗了一点，不过能让人明白。</p>
<p>而在上面式子里那个矩阵P，其实就是A矩阵所基于的基与B矩阵所基于的基这两组基之间的一个变换关系。关于这个结论，可以用一种非常直觉的方法来证明（而不是一般教科书上那种形式上的证明），如果有时间的话，我以后在blog里补充这个证明。</p>
<p>这个发现太重要了。<strong><font color=#ff0000>原来一族相似矩阵都是同一个线性变换的描述啊！</font></strong>难怪这么重要！工科研究生课程中有矩阵论、矩阵分析等课程，其中讲了各种各样的相似变换，比如什么相似标准型，对角化之类的内容，都要求变换以后得到的那个矩阵与先前的那个矩阵式相似的，为什么这么要求？因为只有这样要求，才能保证变换前后的两个矩阵是描述同一个线性变换的。当然，同一个线性变换的不同矩阵描述，从实际运算性质来看并不是不分好环的。有些描述矩阵就比其他的矩阵性质好得多。这很容易理解，同一头猪的照片也有美丑之分嘛。所以矩阵的相似变换可以把一个比较丑的矩阵变成一个比较美的矩阵，而保证这两个矩阵都是描述了同一个线性变换。</p>
<p>这样一来，矩阵作为线性变换描述的一面，基本上说清楚了。但是，事情没有那么简单，或者说，线性代数还有比这更奇妙的性质，那就是，<strong><font color=#ff0000>矩阵不仅可以作为线性变换的描述，而且可以作为一组基的描述。</font><font color=#ff0000>而作为变换的矩阵，不但可以把线性空间中的一个点给变换到另一个点去，而且也能够把线性空间中的一个坐标系（基）表换到另一个坐标系（基）去。而且，变换点与变换坐标系，具有异曲同工的效果。线性代数里最有趣的奥妙，就蕴含在其中。理解了这些内容，线性代数里很多定理和规则会变得更加清晰、直觉。</font></strong></p>
<p>这个留在下一篇再写吧。</p>
<p>因为有别的事情要做，下一篇可能要过几天再写了。</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/9435.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-07-05 14:27 <a href="http://www.cppblog.com/andxie99/archive/2006/07/05/9435.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>抄两篇孟岩老师的作品——理解矩阵（一）</title><link>http://www.cppblog.com/andxie99/archive/2006/07/05/9434.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 05 Jul 2006 06:25:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/07/05/9434.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9434.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/07/05/9434.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9434.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9434.html</trackback:ping><description><![CDATA[一字不改的抄在下面，原文地址：<a href="http://blog.csdn.net/myan/archive/2006/04/02/647511.aspx">http://blog.csdn.net/myan/archive/2006/04/02/647511.aspx</a><br><br>
<p>前不久chensh出于不可告人的目的，要充当老师，教别人线性代数。于是我被揪住就线性代数中一些务虚性的问题与他讨论了几次。很明显，chensh觉得，要让自己在讲线性代数的时候不被那位强势的学生认为是神经病，还是比较难的事情。</p>
<p>可怜的chensh，谁让你趟这个地雷阵？！色令智昏啊！</p>
<p>线性代数课程，无论你从行列式入手还是直接从矩阵入手，从一开始就充斥着莫名其妙。比如说，在全国一般工科院系教学中应用最广泛的同济线性代数教材（现在到了第四版），一上来就介绍逆序数这个&#8220;前无古人，后无来者&#8221;的古怪概念，然后用逆序数给出行列式的一个极不直观的定义，接着是一些简直犯傻的行列式性质和习题——把这行乘一个系数加到另一行上，再把那一列减过来，折腾得那叫一个热闹，可就是压根看不出这个东西有嘛用。大多数像我一样资质平庸的学生到这里就有点犯晕：连这是个什么东西都模模糊糊的，就开始钻火圈表演了，这未免太&#8220;无厘头&#8221;了吧！于是开始有人逃课，更多的人开始抄作业。这下就中招了，因为其后的发展可以用一句峰回路转来形容，紧跟着这个无厘头的行列式的，是一个同样无厘头但是伟大的无以复加的家伙的出场——矩阵来了！多年之后，我才明白，当老师犯傻似地用中括号把一堆傻了吧叽的数括起来，并且不紧不慢地说：&#8220;这个东西叫做矩阵&#8221;的时候，我的数学生涯掀开了何等悲壮辛酸、惨绝人寰的一幕！自那以后，在几乎所有跟&#8220;学问&#8221;二字稍微沾点边的东西里，矩阵这个家伙从不缺席。对于我这个没能一次搞定线性代数的笨蛋来说，矩阵老大的不请自来每每搞得我灰头土脸，头破血流。长期以来，我在阅读中一见矩阵，就如同阿Q见到了假洋鬼子，揉揉额角就绕道走。</p>
<p>事实上，我并不是特例。一般工科学生初学线性代数，通常都会感到困难。这种情形在国内外皆然。瑞典数学家Lars Garding在其名著Encounter with Mathematics中说：&#8220;<font color=#ff0000><strong>如果不熟悉线性代数的概念，要去学习自然科学，现在看来就和文盲差不多。</strong></font>&#8221;，然而<strong><font color=#ff0000>&#8220;按照现行的国际标准，线性代数是通过公理化来表述的，它是第二代数学模型，...，这就带来了教学上的困难。&#8221;</font></strong>事实上，当我们开始学习线性代数的时候，不知不觉就进入了&#8220;第二代数学模型&#8221;的范畴当中，这意味着数学的表述方式和抽象性有了一次全面的进化，对于从小一直在&#8220;第一代数学模型&#8221;，即以实用为导向的、具体的数学模型中学习的我们来说，在没有并明确告知的情况下进行如此剧烈的paradigm shift，不感到困难才是奇怪的。</p>
<p>大部分工科学生，往往是在学习了一些后继课程，如数值分析、数学规划、矩阵论之后，才逐渐能够理解和熟练运用线性代数。即便如此，不少人即使能够很熟练地以线性代数为工具进行科研和应用工作，但对于很多这门课程的初学者提出的、看上去是很基础的问题却并不清楚。比如说：</p>
<p><font color=#0000ff><strong>* 矩阵究竟是什么东西？向量可以被认为是具有n个相互独立的性质（维度）的对象的表示，矩阵又是什么呢？我们如果认为矩阵是一组列（行）向量组成的新的复合向量的展开式，那么为什么这种展开式具有如此广泛的应用？特别是，为什么偏偏二维的展开式如此有用？如果矩阵中每一个元素又是一个向量，那么我们再展开一次，变成三维的立方阵，是不是更有用？</strong></font></p>
<p><font color=#0000ff><strong>* 矩阵的乘法规则究竟为什么这样规定？为什么这样一种怪异的乘法规则却能够在实践中发挥如此巨大的功效？很多看上去似乎是完全不相关的问题，最后竟然都归结到矩阵的乘法，这难道不是很奇妙的事情？难道在矩阵乘法那看上去莫名其妙的规则下面，包含着世界的某些本质规律？如果是的话，这些本质规律是什么？</strong></font></p>
<p><font color=#0000ff><strong>* 行列式究竟是一个什么东西？为什么会有如此怪异的计算规则？行列式与其对应方阵本质上是什么关系？为什么只有方阵才有对应的行列式，而一般矩阵就没有（不要觉得这个问题很蠢，如果必要，针对m x n矩阵定义行列式不是做不到的，之所以不做，是因为没有这个必要，但是为什么没有这个必要）？而且，行列式的计算规则，看上去跟矩阵的任何计算规则都没有直观的联系，为什么又在很多方面决定了矩阵的性质？难道这一切仅是巧合？</strong></font></p>
<p><font color=#0000ff><strong>* 矩阵为什么可以分块计算？分块计算这件事情看上去是那么随意，为什么竟是可行的？</strong></font></p>
<p><font color=#0000ff><strong>* 对于矩阵转置运算A<sup>T</sup>，有(AB)<sup>T</sup> = B<sup>T</sup>A<sup>T</sup>，对于矩阵求逆运算A<sup>-1</sup>，有(AB)<sup>-1</sup> = B<sup>-1</sup>A<sup>-1</sup>。两个看上去完全没有什么关系的运算，为什么有着类似的性质？这仅仅是巧合吗？</strong></font></p>
<p><font color=#0000ff><strong>* 为什么说P<sup>-1</sup>AP得到的矩阵与A矩阵&#8220;相似&#8221;？这里的&#8220;相似&#8221;是什么意思？</strong></font></p>
<p><font color=#0000ff><strong>* 特征值和特征向量的本质是什么？它们定义就让人很惊讶，因为Ax =&#955;x，一个诺大的矩阵的效应，竟然不过相当于一个小小的数&#955;，确实有点奇妙。但何至于用&#8220;特征&#8221;甚至&#8220;本征&#8221;来界定？它们刻划的究竟是什么？</strong></font></p>
<p>这样的一类问题，经常让使用线性代数已经很多年的人都感到为难。就好像大人面对小孩子的刨根问底，最后总会迫不得已地说&#8220;就这样吧，到此为止&#8221;一样，面对这样的问题，很多老手们最后也只能用：&#8220;就是这么规定的，你接受并且记住就好&#8221;来搪塞。然而，这样的问题如果不能获得回答，线性代数对于我们来说就是一个粗暴的、不讲道理的、莫名其妙的规则集合，我们会感到，自己并不是在学习一门学问，而是被不由分说地&#8220;抛到&#8221;一个强制的世界中，只是在考试的皮鞭挥舞之下被迫赶路，全然无法领略其中的美妙、和谐与统一。直到多年以后，我们已经发觉这门学问如此的有用，却仍然会非常迷惑：怎么这么凑巧？</p>
<p>我认为，这是我们的线性代数教学中直觉性丧失的后果。上述这些涉及到&#8220;如何能&#8221;、&#8220;怎么会&#8221;的问题，仅仅通过纯粹的数学证明来回答，是不能令提问者满意的。比如，如果你通过一般的证明方法论证了矩阵分块运算确实可行，那么这并不能够让提问者的疑惑得到解决。他们真正的困惑是：矩阵分块运算为什么竟然是可行的？究竟只是凑巧，还是说这是由矩阵这种对象的某种本质所必然决定的？如果是后者，那么矩阵的这些本质是什么？只要对上述那些问题稍加考虑，我们就会发现，所有这些问题都不是单纯依靠数学证明所能够解决的。像我们的教科书那样，凡事用数学证明，最后培养出来的学生，只能熟练地使用工具，却欠缺真正意义上的理解。</p>
<p>自从1930年代法国布尔巴基学派兴起以来，数学的公理化、系统性描述已经获得巨大的成功，这使得我们接受的数学教育在严谨性上大大提高。然而数学公理化的一个备受争议的副作用，就是一般数学教育中直觉性的丧失。数学家们似乎认为直觉性与抽象性是矛盾的，因此毫不犹豫地牺牲掉前者。然而包括我本人在内的很多人都对此表示怀疑，我们不认为直觉性与抽象性一定相互矛盾，特别是在数学教育中和数学教材中，帮助学生建立直觉，有助于它们理解那些抽象的概念，进而理解数学的本质。反之，如果一味注重形式上的严格性，学生就好像被迫进行钻火圈表演的小白鼠一样，变成枯燥的规则的奴隶。</p>
<p>对于线性代数的类似上述所提到的一些直觉性的问题，两年多来我断断续续地反复思考了四、五次，为此阅读了好几本国内外线性代数、数值分析、代数和数学通论性书籍，其中像前苏联的名著《数学：它的内容、方法和意义》、龚昇教授的《线性代数五讲》、前面提到的Encounter with Mathematics（《数学概观》）以及Thomas A. Garrity的《数学拾遗》都给我很大的启发。不过即使如此，我对这个主题的认识也经历了好几次自我否定。比如以前思考的一些结论曾经写在自己的blog里，但是现在看来，这些结论基本上都是错误的。因此打算把自己现在的有关理解比较完整地记录下来，一方面是因为我觉得现在的理解比较成熟了，可以拿出来与别人探讨，向别人请教。另一方面，如果以后再有进一步的认识，把现在的理解给推翻了，那现在写的这个snapshot也是很有意义的。</p>
<p>因为打算写得比较多，所以会分几次慢慢写。也不知道是不是有时间慢慢写完整，会不会中断，写着看吧。</p>
<p>--------------------------------------------------------------------------</p>
<p>今天先谈谈对线形空间和矩阵的几个核心概念的理解。这些东西大部分是凭着自己的理解写出来的，基本上不抄书，可能有错误的地方，希望能够被指出。但我希望做到直觉，也就是说能把数学背后说的实质问题说出来。</p>
<p>首先说说空间(space)，这个概念是现代数学的命根子之一，从拓扑空间开始，一步步往上加定义，可以形成很多空间。线形空间其实还是比较初级的，如果在里面定义了范数，就成了赋范线性空间。赋范线性空间满足完备性，就成了巴那赫空间；赋范线性空间中定义角度，就有了内积空间，内积空间再满足完备性，就得到希尔伯特空间。</p>
<p>总之，空间有很多种。你要是去看某种空间的数学定义，大致都是&#8220;存在一个集合，在这个集合上定义某某概念，然后满足某些性质&#8221;，就可以被称为空间。这未免有点奇怪，为什么要用&#8220;空间&#8221;来称呼一些这样的集合呢？大家将会看到，其实这是很有道理的。</p>
<p>我们一般人最熟悉的空间，毫无疑问就是我们生活在其中的（按照牛顿的绝对时空观）的三维空间，从数学上说，这是一个三维的欧几里德空间，我们先不管那么多，先看看我们熟悉的这样一个空间有些什么最基本的特点。仔细想想我们就会知道，这个三维的空间：1. 由很多（实际上是无穷多个）位置点组成；2. 这些点之间存在相对的关系；3. 可以在空间中定义长度、角度；4. <strong><font color=#ff0000>这个空间可以容纳运动，这里我们所说的运动是从一个点到另一个点的移动（变换），而不是微积分意义上的&#8220;连续&#8221;性的运动，</font></strong></p>
<p>上面的这些性质中，最最关键的是第4条。第1、2条只能说是空间的基础，不算是空间特有的性质，凡是讨论数学问题，都得有一个集合，大多数还得在这个集合上定义一些结构（关系），并不是说有了这些就算是空间。而第3条太特殊，其他的空间不需要具备，更不是关键的性质。只有第4条是空间的本质，也就是说，<strong><font color=#ff0000>容纳运动是空间的本质特征。</font></strong></p>
<p>认识到了这些，我们就可以把我们关于三维空间的认识扩展到其他的空间。<strong><font color=#ff0000>事实上，不管是什么空间，都必须容纳和支持在其中发生的符合规则的运动（变换）。你会发现，在某种空间中往往会存在一种相对应的变换，比如拓扑空间中有拓扑变换，线性空间中有线性变换，仿射空间中有仿射变换，其实这些变换都只不过是对应空间中允许的运动形式而已。</font></strong></p>
<p>因此只要知道<strong><font color=#ff0000>，&#8220;空间&#8221;是容纳运动的一个对象集合，而变换则规定了对应空间的运动。</font></strong></p>
<p>下面我们来看看线性空间。线性空间的定义任何一本书上都有，但是既然我们承认线性空间是个空间，那么有两个最基本的问题必须首先得到解决，那就是：</p>
<p>1. 空间是一个对象集合，线性空间也是空间，所以也是一个对象集合。那么线性空间是什么样的对象的集合？或者说，线性空间中的对象有什么共同点吗？</p>
<p>2. 线性空间中的运动如何表述的？也就是，线性变换是如何表示的？</p>
<p>我们先来回答第一个问题，回答这个问题的时候其实是不用拐弯抹角的，可以直截了当的给出答案。<strong><font color=#ff0000>线性空间中的任何一个对象，通过选取基和坐标的办法，都可以表达为向量的形式。</font></strong>通常的向量空间我就不说了，举两个不那么平凡的例子：</p>
<p>L1. 最高次项不大于n次的多项式的全体构成一个线性空间，也就是说，这个线性空间中的每一个对象是一个多项式。如果我们以x<sup>0</sup>, x<sup>1</sup>, ..., x<sup>n</sup>为基，那么任何一个这样的多项式都可以表达为一组n+1维向量，其中的每一个分量a<sub>i</sub>其实就是多项式中x<sup>(i-1)</sup>项的系数。值得说明的是，基的选取有多种办法，只要所选取的那一组基线性无关就可以。这要用到后面提到的概念了，所以这里先不说，提一下而已。</p>
<p>L2. 闭区间[a, b]上的n阶连续可微函数的全体，构成一个线性空间。也就是说，这个线性空间的每一个对象是一个连续函数。对于其中任何一个连续函数，根据魏尔斯特拉斯定理，一定可以找到最高次项不大于n的多项式函数，使之与该连续函数的差为0，也就是说，完全相等。这样就把问题归结为L1了。后面就不用再重复了。</p>
<p>所以说，向量是很厉害的，只要你找到合适的基，用向量可以表示线性空间里任何一个对象。这里头大有文章，因为向量表面上只是一列数，但是其实由于它的有序性，所以除了这些数本身携带的信息之外，还可以在每个数的对应位置上携带信息。为什么在程序设计中数组最简单，却又威力无穷呢？根本原因就在于此。这是另一个问题了，这里就不说了。</p>
<p>下面来回答第二个问题，这个问题的回答会涉及到线性代数的一个最根本的问题。</p>
<p>线性空间中的运动，被称为线性变换。也就是说，你从线性空间中的一个点运动到任意的另外一个点，都可以通过一个线性变化来完成。那么，线性变换如何表示呢？<strong><font color=#ff0000>很有意思，在线性空间中，当你选定一组基之后，不仅可以用一个向量来描述空间中的任何一个对象，而且可以用矩阵来描述该空间中的任何一个运动（变换）。而使某个对象发生对应运动的方法，就是用代表那个运动的矩阵，乘以代表那个对象的向量。</font></strong></p>
<p>简而言之，<strong><font color=#ff0000>在线性空间中选定基之后，向量刻画对象，矩阵刻画对象的运动，用矩阵与向量的乘法施加运动。</font></strong></p>
<p>是的，矩阵的本质是运动的描述。如果以后有人问你矩阵是什么，那么你就可以响亮地告诉他，<u><strong><font color=#ff0000>矩阵的本质是运动的描述</font></strong></u>。（chensh，说你呢！）</p>
<p>可是多么有意思啊，向量本身不是也可以看成是n x 1矩阵吗？这实在是很奇妙，<strong><font color=#ff0000>一个空间中的对象和运动竟然可以用相类同的方式表示。</font></strong>能说这是巧合吗？如果是巧合的话，那可真是幸运的巧合！可以说，线性代数中大多数奇妙的性质，均与这个巧合有直接的关系。</p>
<p>（待续）</p>
<br>
<img src ="http://www.cppblog.com/andxie99/aggbug/9434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-07-05 14:25 <a href="http://www.cppblog.com/andxie99/archive/2006/07/05/9434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaScript 的对象层次结构</title><link>http://www.cppblog.com/andxie99/archive/2006/06/30/9239.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Fri, 30 Jun 2006 08:19:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/30/9239.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9239.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/30/9239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9239.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9239.html</trackback:ping><description><![CDATA[<h3><a name=文档对象>文档对象</a> </h3>
<p>现在我们将开始讨论更&#8220;实际&#8221;的话题——文档对象(DOM)。文档对象是指在网页文档里划分出来的对象。在 JavaScript 能够涉及的范围内有如下几个&#8220;大&#8221;对象：window, document, location, navigator, screen, history 等。下面是一个文档对象树，你可以看到对象下包含对象的&#8220;壮观&#8221;情景。要引用某个对象，就要把父级的对象都列出来。例如，要引用某表单&#8220;applicationForm&#8221;的某文字框&#8220;customerName&#8221;，就要用&#8220;document.applicationForm.customerName&#8221;。</p>
<p>下表中有些对象是全小写的，有些是以大写字母开头的。以大写字母开头的对象表示，引用该对象不使用下表列出的名字，而直接用对象的&#8220;名字&#8221;（Id 或 Name，下面有讲解），或用它所属的对象数组指定。</p>
<p>这里我们不准备讲解对象的&#8220;事件&#8221;，虽然我们也会列出对象所能响应的事件。</p>
<div align=center>
<center>
<table cellSpacing=0 cellPadding=0 width=1 border=0>
    <tbody>
        <tr>
            <td vAlign=top noWrap>
            <ul>
                <li><a href="#navigator 浏览器对象">navigator</a>
                <li><a href="#screen 屏幕对象">screen</a>
                <li><a href="#window 窗口对象">window</a>
                <ul>
                    <li><a href="#history 历史对象">history</a>
                    <li><a href="#location 地址对象">location</a>
                    <li><a href="#frames[]; Frame 框架对象">frames[]; Frame</a>
                    <li><a href="#document 文档对象">document</a>
                    <ul>
                        <li><a href="#anchors[]; links[]; Link 连接对象">anchors[]; links[]; Link</a>
                        <li><a href="#applets[] Java小程序对象">applets[]</a>
                        <li><a href="#embeds[] 插件对象">embeds[]</a>
                        <li><a href="#forms[]; Form 表单对象">forms[]; Form</a>
                        <ul>
                            <li><a href="#Button 按钮对象">Button</a>
                            <li><a href="#Checkbox 复选框对象">Checkbox</a>
                            <li><a href="#elements[]; Element 表单元素对象">elements[]; Element</a>
                            <li><a href="#Hidden 隐藏对象">Hidden</a>
                            <li><a href="#Password 密码输入区对象">Password</a>
                            <li><a href="#Radio 单选域对象">Radio</a>
                            <li><a href="#Reset 重置按钮对象">Reset</a>
                            <li><a href="#Select 选择区（下拉菜单、列表）对象">Select</a>
                            <ul>
                                <li><a href="#options[]; Option 选择项对象">options[]; Option</a> </li>
                            </ul>
                            <li><a href="#Submit 提交按钮对象">Submit</a>
                            <li><a href="#Text 文本框对象">Text</a>
                            <li><a href="#Textarea 多行文本输入区对象">Textarea</a> </li>
                        </ul>
                        <li><a href="#images[]; Image 图片对象">images[]; Image</a> </li>
                    </ul>
                    </li>
                </ul>
                </li>
            </ul>
            </td>
            <td vAlign=top noWrap><a href="#navigator 浏览器对象">浏览器对象</a> <br><a href="#screen 屏幕对象">屏幕对象</a> <br><a href="#window 窗口对象">窗口对象</a> <br>　<a href="#history 历史对象">历史对象</a><br>　<a href="#location 地址对象">地址对象</a><br>　<a href="#frames[]; Frame 框架对象">框架对象<br></a>　<a href="#document 文档对象">文档对象</a><br>　　<a href="#anchors[]; links[]; Link 连接对象">连接对象</a><br>　　<a href="#applets[] Java小程序对象">Java小程序对象</a><br>　　<a href="#embeds[] 插件对象">插件对象</a><br>　　<a href="#forms[]; Form 表单对象">表单对象</a><br>　　　<a href="#Button 按钮对象">按钮对象</a><br>　　　<a href="#Checkbox 复选框对象">复选框对象</a><br>　　　<a href="#elements[]; Element 表单元素对象">表单元素对象</a><br>　　　<a href="#Hidden 隐藏对象">隐藏对象</a><br>　　　<a href="#Password 密码输入区对象">密码输入区对象</a><br>　　　<a href="#Radio 单选域对象">单选域对象</a><br>　　　<a href="#Reset 重置按钮对象">重置按钮对象</a><br>　　　<a href="#Select 选择区（下拉菜单、列表）对象">选择区（下拉菜单、列表）对象</a><br>　　　　<a href="#options[]; Option 选择项对象">选择项对象</a><br>　　　<a href="#Submit 提交按钮对象">提交按钮对象</a><br>　　　<a href="#Text 文本框对象">文本框对象</a><br>　　　<a href="#Textarea 多行文本输入区对象">多行文本输入区对象</a><br>　　<a href="#images[]; Image 图片对象">图片对象</a></td>
        </tr>
    </tbody>
</table>
</center></div>
<p><strong><a name="navigator 浏览器对象">navigator 浏览器对象</a> </strong>反映了当前使用的浏览器的资料。</p>
<p><strong>属性</strong> </p>
<p><strong>appCodeName</strong> 返回浏览器的&#8220;码名&#8221;(?)，流行的 IE 和 NN 都返回 'Mozilla'。<strong><br>appName</strong> 返回浏览器名。IE 返回 'Microsoft Internet Explorer'，NN 返回 'Netscape'。<strong><br>appVersion</strong> 返回浏览器版本，包括了大版本号、小版本号、语言、操作平台等信息。<strong><br>platform</strong> 返回浏览器的操作平台，对于 Windows 9x 上的浏览器，返回 'Win32'（大小写可能有差异）。<strong><br>userAgent</strong> 返回以上全部信息。例如，IE5.01 返回 'Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)'。<br><strong>javaEnabled()</strong> 返回一个布尔值，代表当前浏览器允许不允许 Java。</p>
<p><strong><a name="screen 屏幕对象">screen 屏幕对象</a> </strong>反映了当前用户的屏幕设置。</p>
<p><strong>属性</strong> </p>
<p><strong>width</strong> 返回屏幕的宽度（像素数）。<strong><br>height</strong> 返回屏幕的高度。<br><strong>availWidth</strong> 返回屏幕的可用宽度（除去了一些不自动隐藏的类似任务栏的东西所占用的宽度）。<br><strong>availHeight</strong> 返回屏幕的可用高度。<br><strong>colorDepth</strong> 返回当前颜色设置所用的位数 - 1：黑白；8：256色；16：增强色；24/32：真彩色</p>
<p><strong><a name="window 窗口对象">window 窗口对象</a> </strong>最大的对象，它描述的是一个浏览器窗口。一般要引用它的属性和方法时，不需要用&#8220;window.xxx&#8221;这种形式，而直接使用&#8220;xxx&#8221;。一个框架页面也是一个窗口。</p>
<p><strong>属性</strong> </p>
<p><strong>name</strong> 窗口的名称，由打开它的连接（&lt;a target="..."&gt;）或框架页（&lt;frame name="..."&gt;）或某一个窗口调用的 open() 方法（见下）决定。一般我们不会用这个属性。<br><strong>status</strong> 指窗口下方的&#8220;状态栏&#8221;所显示的内容。通过对 status 赋值，可以改变状态栏的显示。<br><strong>opener</strong> 用法：window.opener；返回打开本窗口的窗口对象。注意：返回的是一个窗口对象。如果窗口不是由其他窗口打开的，在 Netscape 中这个属性返回 null；在 IE 中返回&#8220;未定义&#8221;（undefined）。undefined 在一定程度上等于 null。注意：undefined 不是 JavaScript 常数，如果你企图使用&#8220;undefined&#8221;，那就真的返回&#8220;未定义&#8221;了。<br><strong>self</strong> 指窗口本身，它返回的对象跟 window 对象是一模一样的。最常用的是&#8220;self.close()&#8221;，放在&lt;a&gt;标记中：&#8220;&lt;a href="javascript:self.close()"&gt;关闭窗口&lt;/a&gt;&#8221;。<br><strong>parent</strong> 返回窗口所属的框架页对象。<br><strong>top</strong> 返回占据整个浏览器窗口的最顶端的框架页对象。<br><strong>history</strong> 历史对象，<a href="#history 历史对象">见下</a>。<br><strong>location</strong> 地址对象，<a href="#location 地址对象">见下</a>。<br><strong>document</strong> 文档对象，<a href="#document 文档对象">见下</a>。</p>
<p><strong>方法</strong> </p>
<p><strong>open()</strong> 打开一个窗口。用法：open(&lt;URL字符串&gt;, &lt;窗口名称字符串&gt;, &lt;参数字符串&gt;);<br>　　&lt;URL字符串&gt;：描述所打开的窗口打开哪一个网页。如果留空（''），则不打开任意网页。<br>　　&lt;窗口名称字符串&gt;：描述被打开的窗口的名称（window.name），可以使用'_top'、'_blank'等内建名称。这里的名称跟&#8220;&lt;a href="..." target="..."&gt;&#8221;里的&#8220;target&#8221;属性是一样的。<br>　　&lt;参数字符串&gt;：描述被打开的窗口的样貌。如果只需要打开一个普通窗口，该字符串留空（''），如果要指定样貌，就在字符串里写上一到多个参数，参数之间用逗号隔开。</p>
<p>例：打开一个 400 x 100 的干净的窗口：<br>open('','_blank','width=400,height=100,menubar=no,toolbar=no,<br>location=no,directories=no,status=no,scrollbars=yes,resizable=yes')</p>
<table width=400 border=0>
    <tbody>
        <tr>
            <td width=100>
            <p><strong>参数</strong> </p>
            </td>
            <td width=300></td>
        </tr>
        <tr>
            <td width=100>top=#</td>
            <td width=300>窗口顶部离开屏幕顶部的像素数</td>
        </tr>
        <tr>
            <td width=100>left=#</td>
            <td width=300>窗口左端离开屏幕左端的像素数</td>
        </tr>
        <tr>
            <td width=100>width=#</td>
            <td width=300>窗口的宽度</td>
        </tr>
        <tr>
            <td width=100>height=#</td>
            <td width=300>窗口的高度</td>
        </tr>
        <tr>
            <td width=100>menubar=...</td>
            <td width=300>窗口有没有菜单，取值yes或no</td>
        </tr>
        <tr>
            <td width=100>toolbar=...</td>
            <td width=300>窗口有没有工具条，取值yes或no</td>
        </tr>
        <tr>
            <td width=100>location=...</td>
            <td width=300>窗口有没有地址栏，取值yes或no</td>
        </tr>
        <tr>
            <td width=100>directories=...</td>
            <td width=300>窗口有没有连接区，取值yes或no</td>
        </tr>
        <tr>
            <td width=100>scrollbars=...</td>
            <td width=300>窗口有没有滚动条，取值yes或no</td>
        </tr>
        <tr>
            <td width=100>status=...</td>
            <td width=300>窗口有没有状态栏，取值yes或no</td>
        </tr>
        <tr>
            <td width=100>resizable=...</td>
            <td width=300>窗口给不给调整大小，取值yes或no</td>
        </tr>
    </tbody>
</table>
<p>open() 方法有返回值，返回的就是它打开的窗口对象。所以，</p>
<p>var newWindow = open('','_blank');</p>
<p>这样把一个新窗口赋值到&#8220;newWindow&#8221;变量中，以后通过&#8220;newWindow&#8221;变量就可以控制窗口了。</p>
<p><strong>close()</strong>&nbsp;关闭一个已打开的窗口。<br>用法：window.close() 或 self.close()：关闭本窗口；<br>　　　&lt;窗口对象&gt;.close()：关闭指定的窗口。<br>　　如果该窗口有状态栏，调用该方法后浏览器会警告：&#8220;网页正在试图关闭窗口，是否关闭？&#8221;然后等待用户选择是否；如果没有状态栏，调用该方法将直接关闭窗口。<strong><br>blur()</strong>&nbsp;使焦点从窗口移走，窗口变为&#8220;非活动窗口&#8221;。<strong><br>focus()</strong>&nbsp;是窗口获得焦点，变为&#8220;活动窗口&#8221;。不过在 Windows 98，该方法只能使窗口的标题栏和任务栏上的相应按钮闪烁，提示用户该窗口正在试图获得焦点。<strong><br>scrollTo()</strong>&nbsp;用法：[&lt;窗口对象&gt;.]scrollTo(x, y)；使窗口滚动，使文档从左上角数起的(x, y)点滚动到窗口的左上角。<strong><br>scrollBy()</strong>&nbsp;用法：[&lt;窗口对象&gt;.]scrollBy(deltaX, deltaY)；使窗口向右滚动 deltaX 像素，向下滚动 deltaY 像素。如果取负值，则向相反的方向滚动。<strong><br>resizeTo()</strong>&nbsp;用法：[&lt;窗口对象&gt;.]resizeTo(width, height)；使窗口调整大小到宽 width 像素，高 height 像素。<strong><br>resizeBy()</strong>&nbsp;用法：[&lt;窗口对象&gt;.]resizeBy(deltaWidth, deltaHeight)；使窗口调整大小，宽增大 deltaWidth 像素，高增大 deltaHeight 像素。如果取负值，则减少。<br><strong>alert()</strong> 用法：alert(&lt;字符串&gt;)；弹出一个只包含&#8220;确定&#8221;按钮的对话框，显示&lt;字符串&gt;的内容，整个文档的读取、Script 的运行都会暂停，直到用户按下&#8220;确定&#8221;。<br><strong>confirm()</strong> 用法：confirm(&lt;字符串&gt;)；弹出一个包含&#8220;确定&#8221;和&#8220;取消&#8221;按钮的对话框，显示&lt;字符串&gt;的内容，要求用户做出选择，整个文档的读取、Script 的运行都会暂停。如果用户按下&#8220;确定&#8221;，则返回 true 值，如果按下&#8220;取消&#8221;，则返回 false 值。<br><strong>prompt()</strong> 用法：prompt(&lt;字符串&gt;[, &lt;初始值&gt;])；弹出一个包含&#8220;确认&#8221;&#8220;取消&#8221;和一个文本框的对话框，显示&lt;字符串&gt;的内容，要求用户在文本框输入一些数据，整个文档的读取、Script 的运行都会暂停。如果用户按下&#8220;确认&#8221;，则返回文本框里已有的内容，如果用户按下&#8220;取消&#8221;，则返回 null 值。如果指定&lt;初始值&gt;，则文本框里会有默认值。</p>
<p><strong>事件</strong> </p>
<p><strong>onload; onunload; onresize;onblur; onfocus; onerror</strong> </p>
<p><strong><a name="history 历史对象">history 历史对象</a> </strong>历史对象指浏览器的浏览历史。鉴于安全性的需要，该对象收到很多限制，现在只剩下下列属性和方法。</p>
<p><strong>属性</strong> </p>
<p><strong>length</strong> 历史的项数。JavaScript 所能管到的历史被限制在用浏览器的&#8220;前进&#8221;&#8220;后退&#8221;键可以去到的范围。本属性返回的是&#8220;前进&#8221;和&#8220;后退&#8221;两个按键之下包含的地址数的和。</p>
<p><strong>方法</strong> </p>
<p><strong>back()</strong> 后退，跟按下&#8220;后退&#8221;键是等效的。<strong><br>forward()</strong> 前进，跟按下&#8220;前进&#8221;键是等效的。<br><strong>go()</strong> 用法：history.go(x)；在历史的范围内去到指定的一个地址。如果 x &lt; 0，则后退 x 个地址，如果 x &gt; 0，则前进 x 个地址，如果 x == 0，则刷新现在打开的网页。history.go(0) 跟 location.reload() 是等效的。</p>
<p><strong><a name="location 地址对象">location 地址对象</a> </strong>它描述的是某一个窗口对象所打开的地址。要表示当前窗口的地址，只需要使用&#8220;location&#8221;就行了；若要表示某一个窗口的地址，就使用&#8220;&lt;窗口对象&gt;.location&#8221;。</p>
<p><strong>注意</strong> 属于不同协议或不同主机的两个地址之间不能互相引用对方的 location 对象，这是出于安全性的需要。例如，当前窗口打开的是&#8220;www.a.com&#8221;下面的某一页，另外一个窗口（对象名为：bWindow）打开的是&#8220;www.b.com&#8221;的网页。如果在当前窗口使用&#8220;bWindow.location&#8221;，就会出错：&#8220;没有权限&#8221;。这个错误是不能用错误处理程序（Event Handler，参阅 onerror 事件)来接收处理的。</p>
<p><strong>属性</strong> </p>
<p><strong>protocol</strong> 返回地址的协议，取值为 'http:','https:','file:' 等等。<strong><br>hostname</strong> 返回地址的主机名，例如，一个&#8220;http://www.microsoft.com/china/&#8221;的地址，location.hostname == 'www.microsoft.com'。<strong><br>port</strong> 返回地址的端口号，一般 http 的端口号是 '80'。<strong><br>host</strong> 返回主机名和端口号，如：'www.a.com:8080'。<strong><br>pathname</strong> 返回路径名，如&#8220;http://www.a.com/b/c.html&#8221;，location.pathname == 'b/c.html'。<strong><br>hash</strong> 返回&#8220;#&#8221;以及以后的内容，如&#8220;http://www.a.com/b/c.html#chapter4&#8221;，location.hash == '#chapter4'；如果地址里没有&#8220;#&#8221;，则返回空字符串。<strong><br>search</strong> 返回&#8220;?&#8221;以及以后的内容，如&#8220;http://www.a.com/b/c.asp?selection=3&amp;jumpto=4&#8221;，location.search == '?selection=3&amp;jumpto=4'；如果地址里没有&#8220;?&#8221;，则返回空字符串。<strong><br>href</strong> 返回以上全部内容，也就是说，返回整个地址。在浏览器的地址栏上怎么显示它就怎么返回。如果想一个窗口对象打开某地址，可以使用&#8220;location.href = '...'&#8221;，也可以直接用&#8220;location = '...'&#8221;来达到此目的。</p>
<p><strong>方法</strong> </p>
<p><strong>reload()</strong> 相当于按浏览器上的&#8220;刷新&#8221;(IE)或&#8220;Reload&#8221;(Netscape)键。<strong><br>replace()</strong> 打开一个 URL，并取代历史对象中当前位置的地址。用这个方法打开一个 URL 后，按下浏览器的&#8220;后退&#8221;键将不能返回到刚才的页面。</p>
<p><strong><a name="frames[]; Frame 框架对象">frames[]; Frame 框架对象</a> </strong></p>
<p><strong><a name="document 文档对象">document 文档对象</a> </strong>描述当前窗口或指定窗口对象的文档。它包含了文档从&lt;head&gt;到&lt;/body&gt;的内容。<br>　　用法：document （当前窗口）<br>　　　或 &lt;窗口对象&gt;.document （指定窗口）</p>
<p><strong>属性</strong> </p>
<p><strong>cookie</strong> <strong><br>lastModified</strong> 当前文档的最后修改日期，是一个 Date 对象。<strong><br>referrer</strong> 如果当前文档是通过点击连接打开的，则 referrer 返回原来的 URL。<strong><br>title</strong> 指&lt;head&gt;标记里用&lt;title&gt;...&lt;/title&gt;定义的文字。在 Netscape 里本属性不接受赋值。<br><strong>fgColor</strong> 指&lt;body&gt;标记的 text 属性所表示的文本颜色。<br><strong>bgColor</strong> 指&lt;body&gt;标记的 bgcolor 属性所表示的背景颜色。<strong><br>linkColor</strong> 指&lt;body&gt;标记的 link 属性所表示的连接颜色。<strong><br>alinkColor</strong> 指&lt;body&gt;标记的 alink 属性所表示的活动连接颜色。<strong><br>vlinkColor</strong> 指&lt;body&gt;标记的 vlink 属性所表示的已访问连接颜色。</p>
<p><strong>方法</strong> </p>
<p><strong>open()</strong> 打开文档以便 JavaScript 能向文档的当前位置（指插入 JavaScript 的位置）写入数据。通常不需要用这个方法，在需要的时候 JavaScript 自动调用。<strong><br>write(); writeln()</strong> 向文档写入数据，所写入的会当成标准文档 HTML 来处理。writeln() 与 write() 的不同点在于，writeln() 在写入数据以后会加一个换行。这个换行只是在 HTML 中换行，具体情况能不能够是显示出来的文字换行，要看插入 JavaScript 的位置而定。如在&lt;pre&gt;标记中插入，这个换行也会体现在文档中。<br><strong>clear()</strong> 清空当前文档。<br><strong>close()</strong> 关闭文档，停止写入数据。如果用了 write[ln]() 或 clear() 方法，就一定要用 close() 方法来保证所做的更改能够显示出来。如果文档还没有完全读取，也就是说，JavaScript 是插在文档中的，那就不必使用该方法。</p>
<p>现在我们已经拥有足够的知识来做以下这个很多网站都有的弹出式更新通知了。</p>
<p>&lt;script language="JavaScript"&gt;<br>&lt;!--<br>var whatsNew = open('','_blank','top=50,left=50,width=200,height=300,' +<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'menubar=no,toolbar=no,directories=no,location=no,' +<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'status=no,resizable=no,scrollbars=yes');<br>whatsNew.document.write('&lt;center&gt;&lt;b&gt;更新通知&lt;/b&gt;&lt;/center&gt;');<br>whatsNew.document.write('&lt;p&gt;最后更新日期：00.08.01');<br>whatsNew.document.write('&lt;p&gt;00.08.01：增加了&#8220;我的最爱&#8221;栏目。');<br>whatsNew.document.write('&lt;p align="right"&gt;' +<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '&lt;a href="javascript:self.close()"&gt;关闭窗口&lt;/a&gt;');<br>whatsNew.document.close();<br>--&gt;<br>&lt;/script&gt;</p>
<p>当然也可以先写好一个 HTML 文件，在 open() 方法中直接 load 这个文件。</p>
<p><strong><a name="anchors[]; links[]; Link 连接对象">anchors[]; links[]; Link 连接对象</a> </strong></p>
<p>用法：document.anchors<strong>[</strong>[x]<strong>]</strong>; document.links<strong>[</strong>[x]<strong>]</strong>; &lt;anchorId&gt;; &lt;linkId&gt;<br>　　document.anchors 是一个数组，包含了文档中所有锚标记（包含 name 属性的&lt;a&gt;标记），按照在文档中的次序，从 0 开始给每个锚标记定义了一个下标。<br>　　document.links 也是一个数组，包含了文档中所有连接标记（包含 href 属性的&lt;a&gt;标记和&lt;map&gt;标记段里的&lt;area&gt;标记），按照在文档中的次序，从 0 开始给每个连接标记定义了一个下标。<br>　　如果一个&lt;a&gt;标记既有 name 属性，又有 href 属性，则它既是一个 Anchor 对象，又是一个 Link 对象。<br>　　在 IE 中，如果在&lt;a&gt;标记中添加&#8220;id="..."&#8221;属性，则这个&lt;a&gt;对象被赋予一个标识（ID），调用这个对象的时候只需要使用&#8220;&lt;id&gt;&#8221;就行了。很多文档部件都可以用这个方法来赋予 ID，但要注意不能有两个 ID 相同。</p>
<p>anchors 和 links 作为数组，有数组的属性和方法。单个 Anchor 对象没有属性；单个 Link 对象的属性见下。</p>
<p><strong>属性</strong> </p>
<p><strong>protocol; hostname; port; host; pathname; hash; search; href</strong> 与 location 对象相同。<strong><br>target</strong> 返回/指定连接的目标窗口（字符串），与&lt;a&gt;标记里的 target 属性是一样的。</p>
<p><strong>事件</strong> </p>
<p><strong>onclick; onmouseover;onmouseout; onmousedown; onmouseup</strong> </p>
<p><strong><a name="applets[] Java小程序对象">applets[] Java小程序对象</a> </strong>它是一个数组，包含了文档中所有的 Applet 对象（Java 小程序）。作为一个数组，有数组的属性和方法。关于单个 Applet 对象的属性和方法，我引用一句话：&#8220;Applet 对象继承了 Java 小程序的所有公共属性和方法。&#8221;(英文原句：The Applet object inherits all public properties of the Java applet./The Applet object inherits all public methodss of the Java applet.) 因为本人很厌恶 Java 小程序，所以对它的什么&#8220;公共&#8221;&#8220;私有&#8221;的问题不感兴趣，也就没有探讨了。</p>
<p><strong><a name="embeds[] 插件对象">embeds[] 插件对象</a> </strong>它是一个数组，包含了文档中所有的插件（&lt;embed&gt;标记）。因为每个插件的不同，每个 Embed 对象也有不同的属性和方法。</p>
<p><strong><a name="forms[]; Form 表单对象">forms[]; Form 表单对象</a> </strong>document.forms[] 是一个数组，包含了文档中所有的表单（&lt;form&gt;）。要引用单个表单，可以用 document.forms[x]，但是一般来说，人们都会这样做：在&lt;form&gt;标记中加上&#8220;name="..."&#8221;属性，那么直接用&#8220;document.&lt;表单名&gt;&#8221;就可以引用了。</p>
<p><strong>Form 对象的属性</strong> </p>
<p><strong>name</strong> 返回表单的名称，也就是&lt;form name="..."&gt;属性。<strong><br>action</strong> 返回/设定表单的提交地址，也就是&lt;form action="..."&gt;属性。<br><strong>method</strong> 返回/设定表单的提交方法，也就是&lt;form method="..."&gt;属性。<br><strong>target</strong> 返回/设定表单提交后返回的窗口，也就是&lt;form target="..."&gt;属性。<br><strong>encoding</strong> 返回/设定表单提交内容的编码方式，也就是&lt;form enctype="..."&gt;属性。<br><strong>length</strong> 返回该表单所含元素的数目。</p>
<p><strong>方法</strong> </p>
<p><strong>reset()</strong> 重置表单。这与按下&#8220;重置&#8221;按钮是一样的。<br><strong>submit()</strong> 提交表单。这与按下&#8220;提交&#8221;按钮是一样的。</p>
<p><strong>事件</strong> </p>
<p><strong>onreset; onsubmit</strong> </p>
<p>以下从&#8220;Button&#8221;到&#8220;Textarea&#8221;都是表单的元素对象。</p>
<p><strong><a name="Button 按钮对象">Button 按钮对象</a> </strong>由&#8220;&lt;input type="button"&gt;&#8221;指定。引用一个 Button 对象，可以使用&#8220;&lt;文档对象&gt;.&lt;表单对象&gt;.&lt;按钮名称&gt;&#8221;。&lt;按钮名称&gt;指在&lt;input&gt;标记中的&#8220;name="..."&#8221;属性的值。引用任意表单元素都可以用这种方法。</p>
<p><strong>属性</strong> </p>
<p><strong>name</strong> 返回/设定用&lt;input name="..."&gt;指定的元素名称。<strong><br>value</strong> 返回/设定用&lt;input value="..."&gt;指定的元素的值。<br><strong>form</strong> 返回包含本元素的表单对象。</p>
<p><strong>方法</strong> </p>
<p><strong>blur()</strong> 从对象中移走焦点。<br><strong>focus()</strong> 让对象获得焦点。<br><strong>click()</strong> 模拟鼠标点击该对象。</p>
<p><strong>事件</strong> </p>
<p><strong>onclick; onmousedown; onmouseup</strong> </p>
<p><strong><a name="Checkbox 复选框对象">Checkbox 复选框对象</a> </strong>由&#8220;&lt;input type="checkbox"&gt;&#8221;指定。</p>
<p><strong>属性</strong> </p>
<p><strong>name</strong> 返回/设定用&lt;input name="..."&gt;指定的元素名称。<strong><br>value</strong> 返回/设定用&lt;input value="..."&gt;指定的元素的值。<br><strong>form</strong> 返回包含本元素的表单对象。<br><strong>checked</strong> 返回/设定该复选框对象是否被选中。这是一个布尔值。<br><strong>defaultChecked</strong> 返回/设定该复选框对象默认是否被选中。这是一个布尔值。</p>
<p><strong>方法</strong> </p>
<p><strong>blur()</strong> 从对象中移走焦点。<strong><br>focus()</strong> 让对象获得焦点。<br><strong>click()</strong> 模拟鼠标点击该对象。</p>
<p><strong>事件</strong> </p>
<p><strong>onclick</strong> </p>
<p><strong><a name="elements[]; Element 表单元素对象">elements[]; Element 表单元素对象</a> </strong>&lt;表单对象&gt;.elements 是一个数组，包含了该表单所有的对象。一般我们不用该数组，而直接引用各个具体的对象。</p>
<p><strong><a name="Hidden 隐藏对象">Hidden 隐藏对象</a> </strong>由&#8220;&lt;input type="hidden"&gt;&#8221;指定。</p>
<p><strong>属性</strong> </p>
<p><strong>name</strong> 返回/设定用&lt;input name="..."&gt;指定的元素名称。<strong><br>value</strong> 返回/设定用&lt;input value="..."&gt;指定的元素的值。<strong><br>form</strong> 返回包含本元素的表单对象。</p>
<p><strong><a name="Password 密码输入区对象">Password 密码输入区对象</a> </strong>由&#8220;&lt;input type="password"&gt;&#8221;指定。</p>
<p><strong>属性</strong> </p>
<p><strong>name</strong> 返回/设定用&lt;input name="..."&gt;指定的元素名称。<strong><br>value</strong> 返回/设定密码输入区当前的值。<strong><br>defaultValue</strong> 返回用&lt;input value="..."&gt;指定的默认值。<strong><br>form</strong> 返回包含本元素的表单对象。</p>
<p><strong>方法</strong> </p>
<p><strong>blur()</strong> 从对象中移走焦点。<strong><br>focus()</strong> 让对象获得焦点。<br><strong>select()</strong> 选中密码输入区里全部文本。</p>
<p><strong>事件</strong> </p>
<p><strong>onchange</strong> </p>
<p><strong><a name="Radio 单选域对象">Radio 单选域对象</a> </strong>由&#8220;&lt;input type="radio"&gt;&#8221;指定。一组 Radio 对象有共同的名称（name 属性），这样的话，document.formName.radioName 就成了一个数组。要访问单个 Radio 对象就要用：document.formName.radioName[x]。</p>
<p><strong>单个 Radio 对象的属性</strong> </p>
<p><strong>name</strong> 返回/设定用&lt;input name="..."&gt;指定的元素名称。<strong><br>value</strong> 返回/设定用&lt;input value="..."&gt;指定的元素的值。<strong><br>form</strong> 返回包含本元素的表单对象。<strong><br>checked</strong> 返回/设定该单选域对象是否被选中。这是一个布尔值。<strong><br>defaultChecked</strong> 返回/设定该对象默认是否被选中。这是一个布尔值。</p>
<p><strong>方法</strong> </p>
<p><strong>blur()</strong> 从对象中移走焦点。<strong><br>focus()</strong> 让对象获得焦点。<strong><br>click()</strong> 模拟鼠标点击该对象。</p>
<p><strong>事件</strong> </p>
<p><strong>onclick</strong> </p>
<p><strong><a name="Reset 重置按钮对象">Reset 重置按钮对象</a> </strong>由&#8220;&lt;input type="reset"&gt;&#8221;指定。因为 Reset 也是按钮，所以也有 <a href="#Button 按钮对象">Button 对象</a>的属性和方法。至于&#8220;onclick&#8221;事件，一般用 <a href="#forms[]; Form 表单对象">Form</a> 对象的 onreset 代替。</p>
<p><strong><a name="Select 选择区（下拉菜单、列表）对象">Select 选择区（下拉菜单、列表）对象</a> </strong>由&#8220;&lt;select&gt;&#8221;指定。</p>
<p><strong>属性</strong> </p>
<p><strong>name</strong> 返回/设定用&lt;input name="..."&gt;指定的元素名称。<strong><br>length</strong> 返回 Select 对象下选项的数目。<strong><br>selectedIndex</strong> 返回被选中的选项的下标。这个下标就是在 options[] 数组中该选项的位置。如果 Select 对象允许多项选择，则返回第一个被选中的选项的下标。<strong><br>form</strong> 返回包含本元素的表单对象。</p>
<p><strong>方法</strong> </p>
<p><strong>blur()</strong> 从对象中移走焦点。<strong><br>focus()</strong> 让对象获得焦点。</p>
<p><strong>事件</strong> </p>
<p><strong>onchange</strong> </p>
<p><strong><a name="options[]; Option 选择项对象">options[]; Option 选择项对象</a> </strong>options[] 是一个数组，包含了在同一个 Select 对象下的 Option 对象。Option 对象由&#8220;&lt;select&gt;&#8221;下的&#8220;&lt;options&gt;&#8221;指定。</p>
<p><strong>options[] 数组的属性</strong> </p>
<p><strong>length; selectedIndex</strong> 与所属 Select 对象的同名属性相同。</p>
<p><strong>单个 Option 对象的属性</strong> </p>
<p><strong>text</strong> 返回/指定 Option 对象所显示的文本<strong><br>value</strong> 返回/指定 Option 对象的值，与&lt;options value="..."&gt;一致。<strong><br>index</strong> 返回该 Option 对象的下标。对此并没有什么好说，因为要指定特定的一个 Option 对象，都要先知道该对象的下标。这个属性好像没有什么用。<strong><br>selected</strong> 返回/指定该对象是否被选中。通过指定 true 或者 false，可以动态的改变选中项。<br><strong>defaultSelected</strong> 返回该对象默认是否被选中。true / false。</p>
<p><strong><a name="Submit 提交按钮对象">Submit 提交按钮对象</a> </strong>由&#8220;&lt;input type="submit"&gt;指定。因为 Submit 也是按钮，所以也有 <a href="#Button 按钮对象">Button 对象</a>的属性和方法。至于&#8220;onclick&#8221;事件，一般用 <a href="#forms[]; Form 表单对象">Form</a> 对象的 onsubmit 代替。</p>
<p><strong><a name="Text 文本框对象">Text 文本框对象</a> </strong>由&#8220;&lt;input type="text"&gt;&#8221;指定。Password 对象也是 Text 对象的一种，所以 <a href="#Password 密码输入区对象">Password 对象</a>所有的属性、方法和事件，Text 对象都有。</p>
<p><strong><a name="Textarea 多行文本输入区对象">Textarea 多行文本输入区对象</a> </strong>由&#8220;&lt;textarea&gt;&#8221;指定。Textarea 对象所有的属性、方法和事件和 <a href="#Text 文本框对象">Text 对象</a>相同，也就是跟 <a href="#Password 密码输入区对象">Password 对象</a>一样。</p>
<p><strong><a name="images[]; Image 图片对象">images[]; Image 图片对象</a> </strong>document.images[] 是一个数组，包含了文档中所有的图片（&lt;img&gt;）。要引用单个图片，可以用 document.images[x]。如果某图片包含&#8220;name&#8221;属性，也就是用&#8220;&lt;img name="..."&gt;&#8221;这种格式定义了一幅图片，就可以使用&#8220;document.images['...']&#8221;这种方法来引用图片。在 IE 中，如果某图片包含 ID 属性，也就是用&#8220;&lt;img id="..."&gt;&#8221;这种格式定义了一幅图片，就可以直接使用&#8220;&lt;imageID&gt;&#8221;来引用图片。</p>
<p><strong>单个 Image 对象的属性</strong> </p>
<p><strong>name; src; lowsrc; width; height; vspace; hspace; border</strong> 这些属性跟&lt;img&gt;标记里的同名属性是一样的。在 Netscape 里，除了 src 属性，其它属性（几乎全部）都不能改的，即使改了，在文档中也不能显示出效果来。这些属性最有用的就是 src 了，通过对 src 属性赋值，可以实时的更改图片。</p>
<p><strong>事件</strong> </p>
<p><strong>onclick</strong> </p>
<p><strong>不显示在文档中的 Image 对象</strong> </p>
<p>不显示在文档中的 Image 对象是用 var 语句定义的：</p>
<p>var myImage = new Image(); 或<br>var myImage = new Image(&lt;图片地址字符串&gt;);</p>
<p>然后就可以像一般 Image 对象一样对待 myImage 变量了。不过既然它不显示在文档中，以下属性：lowsrc, width, height, vspace, hspace, border 就没有什么用途了。一般这种对象只有一个用：预读图片(preload)。因为当对对象的 src 属性赋值的时候，整个文档的读取、JavaScript 的运行都暂停，让浏览器专心的读取图片。预读图片以后，浏览器的缓存里就有了图片的 Copy，到真正要把图片放到文档中的时候，图片就可以立刻显示了。现在的网页中经常会有一些图像连接，当鼠标指向它的时候，图像换成另外一幅图像，它们都是先预读图像的。</p>
<p><strong>预读图像的 JavaScript 例子</strong> </p>
<p>var imagePreload = new Image();</p>
<p>imagePreload.src = '001.gif';<br>imagePreload.src = '002.gif';<br>imagePreload.src = '003.gif';</p>
<p>以上例子适合预读少量图片。</p>
<p>function imagePreload() {<br>&nbsp; var imgPreload = new Image();<br>&nbsp; for (i = 0; i &lt; arguments.length; i++) {<br>&nbsp;&nbsp;&nbsp; imgPreload.src = arguments[i];<br>&nbsp; }<br>}</p>
<p>imagePreload('001.gif', '002.gif', '003.gif', '004.gif', '005.gif');</p>
<p>以上例子适合预读大量图片。&nbsp;</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/9239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-30 16:19 <a href="http://www.cppblog.com/andxie99/archive/2006/06/30/9239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用命令集（d o s,FTP,UNIX NOVEL...)</title><link>http://www.cppblog.com/andxie99/archive/2006/06/20/8761.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 20 Jun 2006 09:24:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/20/8761.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/8761.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/20/8761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/8761.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/8761.html</trackback:ping><description><![CDATA[<div align=center>
<p align=left>&nbsp;</p>
<p align=left>一.FTP命令集 </p>
<p align=left>ascii: 设定以ASCII方式传送文件(缺省值) </p>
<p align=left>bell: 每完成一次文件传送,报警提示. </p>
<p align=left>binary:设定以二进制方式传送文件. </p>
<p align=left>bye:终止主机FTP进程,并退出FTP管理方式. </p>
<p align=left>case: 当为ON时,用MGET命令拷贝的文件名到本地机器中,全部转换为小写字母. </p>
<p align=left>cd: 同UNIX的CD命令. </p>
<p align=left>cdup: 返回上一级目录. </p>
<p align=left>chmod: 改变远端主机的文件权限. </p>
<p align=left>c l o s e: 终止远端的FTP进程,返回到FTP命令状态,所有的宏定义都被删除. </p>
<p align=left>delete: 删除远端主机中的文件. </p>
<p align=left>dir [remote-directory] [local-file]列出当前远端主机目录中的文件.如果有本地文件, </p>
<p align=left>就将结果写至本地文件. </p>
<p align=left>get [remote-file] [local-file]从远端主机中传送至本地主机中. </p>
<p align=left>help [command]输出命令的解释. </p>
<p align=left>lcd: 改变当前本地主机的工作目录,如果缺省,就转到当前用户的HOME目录. </p>
<p align=left><br>ls [remote-directory] [local-file]同DIR. </p>
<p align=left>macdef: 定义宏命令. </p>
<p align=left>mdelete [remote-files]删除一批文件. </p>
<p align=left>mget [remote-files 从远端主机接收一批文件至本地主机. </p>
<p align=left>mkdir directory-name 在远端主机中建立目录. </p>
<p align=left>mput local-files 将本地主机中一批文件传送至远端主机. </p>
<p align=left>o p e n host [port] 重新建立一个新的连接. </p>
<p align=left>prompt: 交互提示模式. </p>
<p align=left>put local-file [remote-file] 将本地一个文件传送至远端主机中. </p>
<p align=left>pwd: 列出当前远端主机目录. </p>
<p align=left>quit: 同BYE. </p>
<p align=left>recv remote-file [local-file]同GET. </p>
<p align=left>rename [from] [to] 改变远端主机中的文件名. </p>
<p align=left>rmdir directory-name 删除远端主机中的目录 </p>
<p align=left>send local-file [remote-file]同PUT. </p>
<p align=left>status: 显示当前FTP的状态. </p>
<p align=left>system: 显示远端主机系统类型. </p>
<p align=left>user user-name [password] [account] 重新以别的用户名登录远端主机. </p>
<p align=left>?: 同HELP. </p>
<p align=left>二.8086/8088汇编语言指令集 </p>
<p align=left><br>一，数据传送指令集 <br>1.MOV <br>功能: 把源操作数送给目的操作数 <br>语法: MOV 目的操作数,源操作数 <br>格式: MOV r1,r2 <br>MOV r,m <br>MOV m,r <br>MOV r,data <br>2.XCHG <br>功能: 交换两个操作数的数据 <br>语法: XCHG <br>格式: XCHG r1,r2 XCHG m,r XCHG r,m <br>3.PUSH,POP <br>功能: 把操作数压入或取出堆栈 <br>语法: PUSH 操作数 POP 操作数 <br>格式: PUSH r PUSH M PUSH data POP r POP m <br>4.PUSHF,POPF,PUSHA,POPA <br>功能: 堆栈指令群 <br>格式: PUSHF POPF PUSHA POPA <br>5.LEA,LDS,LES <br>功能: 取地址至寄存器 <br>语法: LEA r,m LDS r,m LES r,m <br>6.XLAT(XLATB) <br>功能: 查表指令 <br>语法: XLAT XLAT m </p>
<p align=left>二，算数运算指令 <br>1..ADD,ADC <br>功能: 加法指令 <br>语法: ADD OP1,OP2 ADC OP1,OP2 <br>格式: ADD r1,r2 ADD r,m ADD m,r ADD r,data <br>影响标志: C,P,A,Z,S,O <br>2..S U B,SBB <br>功能:减法指令 <br>语法: S U B OP1,OP2 SBB OP1,OP2 <br>格式: S U B r1,r2 S U B r,m S U B m,r S U B r,data S U B m,data <br>影响标志: C,P,A,Z,S,O <br>3.INC,DEC <br>功能: 把OP的值加一或减一 <br>语法: INC OP DEC OP <br>格式: INC r/m DEC r/m <br>影响标志: P,A,Z,S,O <br>4.NEG <br>功能: 将OP的符号反相(取二进制补码) <br>语法: NEG OP <br>格式: NEG r/m <br>影响标志: C,P,A,Z,S,O <br>5.MUL,IMUL <br>功能: 乘法指令 <br>语法: MUL OP IMUL OP <br>格式: MUL r/m IMUL r/m <br>影响标志: C,P,A,Z,S,O(仅IMUL会影响S标志) <br>6.DIV,IDIV <br>功能:除法指令 <br>语法: DIV OP IDIV OP <br>格式: DIV r/m IDIV r/m <br>7.CBW,CWD <br>功能: 有符号数扩展指令 <br>语法: CBW CWD <br>8.AAA,AAS,AAM,AAD <br>功能: 非压BCD码运算调整指令 <br>语法: AAA AAS AAM AAD <br>影响标志: A,C(AAA,AAS) S,Z,P(AAM,AAD) <br>9.DAA,DAS <br>功能: 压缩BCD码调整指令 <br>语法: DAA DAS <br>影响标志: C,P,A,Z,S </p>
<p align=left>三，位运算指令集 <br>1.AND,OR,XOR,NOT,TEST <br>功能: 执行BIT与BIT之间的逻辑运算 <br>语法: AND r/m,r/m/data OR r/m,r/m/data XOR r/m,r/m/data TEST r/m,r/m/d <br>ata NOT r/m <br>影响标志: C,O,P,Z,S(其中C与O两个标志会被设为0) NOT指令不影响任何标志位 <br>2.SHR,SHL,SAR,SAL <br>功能: 移位指令 <br>语法: SHR r/m,data/CL SHL r/m,data/CL SAR r/m,data/CL SAL r/m,data/CL <br>影响标志: C,P,Z,S,O <br>3.ROR,ROL,RCR,RCL <br>功能: 循环移位指令 <br>语法: ROR r/m,data/CL ROL r/m,data/CL RCR r/m,data/CL RCL r/m,data/CL <br>影响标志: C,P,Z,S,O </p>
<p align=left>四，程序流程控制指令集 <br>1.CLC,STC,CMC <br>功能: 设定进位标志 <br>语法: CLC STC CMC <br>标志位: C <br>2.CLD,STD <br>功能: 设定方向标志 <br>语法: CLD STD <br>标志位: D <br>3.CLI,STI <br>功能: 设定中断标志 <br>语法: CLI STI <br>标志位: I <br>4.CMP <br>功能: 比较OP1与OP2的值 <br>语法: CMP r/m,r/m/data <br>标志位: C,P,A,Z,O <br>5.JMP <br>功能: 跳往指定地址执行 <br>语法: JMP 地址 <br>6.JXX <br>功能: 当特定条件成立则跳往指定地址执行 <br>语法: JXX 地址 <br>注: <br>A: ABOVE,当C=0,Z=0时成立 <br>B: BELOW,当C=1时成立 <br>C: CARRY,当弁时成立 CXZ: CX寄存器的值为0(ZERO)时成立 <br>E: EQUAL,当Z=1时成立 <br>G: GREATER(大于),当Z=0且S=0时成立 <br>L: LESS(小于),当S不为零时成立 <br>N: NOT(相反条件),需和其它符号配合使用 <br>O: OVERFLOW,O=1时成立 <br>P: PARITY,P=1时成立 <br>PE: PARITY EVEN,P=1时成立 <br>PO: PARITY ODD,P=0时成立 <br>S: SIGN,S=1时成立 <br>Z: ZERO,Z=1时成立 <br>7.LOOP <br>功能: 循环指令集 <br>语法: LOOP 地址 <br>8.LOOPE(Z) <br>地址 LOOPNE(Z) 地址 <br>标志位: 无 <br>9.CALL,RET <br>功能: 子程序调用,返回指令 <br>语法: CALL 地址 RET RET n <br>标志位: 无 <br>10.INT,IRET <br>功能: 中断调用及返回指令 <br>语法: INT n IRET <br>标志位: 在执行INT时,CPU会自动将标志寄存器的值入栈,在执行IRET时则会将堆 <br>栈中的标志值弹回寄存器 </p>
<p align=left>五，字符串操作指令集 <br>1.MOVSB,MOVSW,MOVSD <br>功能: 字符串传送指令 <br>语法: MOVSB MOVSW MOVSD <br>标志位: 无 <br>2.CMPSB,CMPSW,CMPSD <br>功能: 字符串比较指令 <br>语法: CMPSB CMPSW CMPSD <br>标志位: C,P,Z,S,O <br>3.SCASB,SCASW <br>功能: 字符串搜索指令 <br>语法: SCASB SCASW <br>标志位: C,P,Z,S,O <br>4.LODSB,LODSW,STOSB,STOSW <br>功能: 字符串载入或存贮指令 <br>语法: LODSB LODSW STOSB STOSW <br>标志位: 无 <br>5.REP,REPE,REPNE <br>功能: 重复前缀指令集 <br>语法: REP 指令S REPE 指令S REPNE 指令S <br>标志位: 依指令S而定 </p>
<p align=left><br>三.D O S命令集 </p>
<p align=left>一、DIR 命令的格式： <br>dir [D:][PATH][NAME][/A][:attrib][/o:[sorted][/s][/b][/l][/c[h] <br>(1)dir /a:attrib 缺省包含所有文件(系统文件.隐含文件) <br>attrib[:][h/-h]只显示隐含文件或非隐含文件. <br>[r/-r]只显示只读文件或非只读文件 <br>[s/-s]只显示系统文件或非系统文件 <br>[a/-a]只显示要归档文件或非归档文件 <br>(2)/o[:]sorted:缺省完全按字母顺序,子目录显示在文件之前 <br>/o[n/-n]:按字母顺序或按文件名顺序/反向显示 <br>[e/-e]:按扩展名字母顺序/反向显示 <br>[d/-d]:按时间顺序/反向显示 <br>[s/-s]:按大小从大到小或/反向显示 <br>[g/-g]:按子目录先于文件或文件先于子目录 <br>(3)/s 参数:对当前目录及其子目录中所有文件进行列表 <br>列名:dir /s/a/o:n c:\&gt;PRN <br>将c盘上的所有子目录和文件按隶属关系并根据子目录和文件字母顺序打印输出 <br>(4)/B 参数:将只显示文件名与扩展名 <br>(5)/L 参数:将全部用小写字母对文件或子目录进行列表 <br>训练: <br>dir /a 列当前目录所有文件(含隐含及系统文件) <br>dir /ah 列隐含文件(包含子目录(隐含的) dir /a-h <br>dir /as 列系统文件 dir /a-s <br>dir /ad 列子目录 dir /a-d <br>dir /o 按字母顺序 <br>dir /B 只显示文件名与扩展名 <br>二、attrib [+r|-r] [+a|-a] [+s|-s] [+h|-h] [d: ] [name] [/s] <br>缺省 attrib name 显示文件的(文件)属性 <br>attrib io.sys (或子目录) <br>shr c:\ io.sys 指定为系统(s) 隐含(h) 只读(r)文件 <br>也可以attrib *.sys 显示扩展名为sys的文件属性 <br>参数 [+r|-r] 将文件属性设置或解除 只读属性 <br>[+a|-a] 将文件属性设置或解除 归档属性 <br>[+h|-h] 将文件属性设置或解除 隐含属性 (尤其对子目录也起作用) <br>/s 参数 将当前及当前子目录下的所有文件均起作用 <br>可以用来查找文件 <br>例子: <br>attrib news86 列news86的文档属性 <br>attrib +r report.txt 设置为只读 attrib -s -h record.txt <br>attrib +a a:*.* <br>attrib -a a:*.bak <br>xcopy a: b: /a 将A盘上的所有标志为"归档"属性的文件拷到B盘 <br>xcopy a: b: /m 将A盘上的所有文件拷到B盘后并移去归档属性 <br>三、cd 介绍: cd...返回上二级目录 "."代表当前目录 "."代表父目录 <br>cd ..\..返回到上级目录的父目录(祖目录) <br>cd A:\ 将A盘的当前目录改为根目录 <br>cd A:\xx 将A盘的当前目录改为子目录xx下 <br>cd ..\98 先返回父目录,再进入父目录下的98子目录 <br>cd ..返回到父目录 <br>cd\98 进入根目录下的98子目录 <br>四、copy [/y][/-y][/v][ /B] <br>copy /y 不加提示,对所有文件加以覆盖 <br>/-y 加以提示,对所有文件 (yes或no提问 ) <br>/v 拷贝以后加以校验 <br>/B 按二进制进行显示 <br>copy w1.wps C O N/b 可以将wps文件在屏幕上显示,而不必进入wps状态 <br>copy ..\98 将父目录下的98子目录下的所有文件全拷到当前子目录 <br>copy .\97 当当前目录下的97子目录下文件全部拷到当前目录 <br>copy . c:\ 将当前目录下的所有文件拷到c盘根目录 <br>. 意味着 *.* 文件 <br>copy N U L a.abc 将a.abc 文件清空(文件长度改为0) <br>copy 文件名+C O N 向文本文件中追加命令或内容 <br>copy C O N 文件名 创建文本文件(F6存盘退出) <br>copy C O N prn 检测打印机的开关 <br>五、xcopy命令 <br>xcopy [source] [d:date] [/p] [/s] [/e] [/v] [/y] <br>xcopy [d:date] xcopy a:b:\ /d:08/18/98/s/v 拷贝98.08.18年后的文件 <br>xcopy [/p] 提示创建子目录 <br>xcopy [/s] 连带子目录一起拷贝. 注意:若目标盘上不存在此子目录,而在目标 <br>盘的结束符又不以"\"为结束,则将提示: <br>does destination specify a file name or directory name on the target <br>[f=file,d=directory]? <br>在目标盘上创建文件[按下]还是创建子目录[按下d] ?应选择d键 <br>xcopy[/v] 带较验 <br>*:(1) xcopy 不拷贝系统和隐含文件,应先予以修改属性再拷贝 <br>xcopy [/y] 覆盖时是否有提示, /y 不带提示 <br>若省略目标盘或子目录名,则拷贝到当前目录下 <br>六、 del /p <br>加/p 可以在删除前是否提示 <br>如del后加子目录名,则将子目录下所有文件(隐含.系统.只读文件除外)全删除, <br>加/p则可以确认. <br>七、undelete [name] /au <br>不加提示地将所有满足条件的文件恢复(能够恢复的),并将首字母置成"#",若已 <br>存在,则按"# % &amp; 0 1 2-9 a-z"顺序加上. <br>如:undelete *.dbf/au 将扩展名为"dbf"的文件全恢复,并以"#"开头,作为文件 <br>名, /list 仅列出可恢复的文件,而不恢复 <br>undelete /load 将undelete装入内存 <br>/unload 将undelete卸出内存 <br>/s[drive]对指定驱动器进行监测管理 <br>undelete/sc <br>将 undelete驻留内存,?并创建一个隐含的sentry 子目录对c盘删除的文件进行 <br>管理 undelete/ds 恢复 <br>相应恢复命令可以用undelete即可完整恢复出文件名(非常完整) <br>最常用undelete *.* <br>deltree /y [drive:path] <br>deltree 删除子目录及文件,尽管有些文件是系统文件或隐含文件 <br>它可以带有通配符,带有通配符时,它将删除符合条件的文件及子目录 <br>如:?undelete *.dbf/au 将扩展名为"dbf"的文件全恢复,并以"#"开头作为文件 <br>名. <br>/list 仅列出可恢复的文件,而不作恢复操作. <br>undelete/load 将undelete 装入内存. <br>/unload将undelete 卸出内存. <br>/s[drive] 对指定的驱动器进行监视管理. <br>undelete/sc 将undelete 驻留内存,并创建一个隐含的sentry子目录对C盘删除 <br>的文件进行管理.相应恢复命令可以用undelete/ds 即可完整恢复出文件名(很完善). <br>最常用的是undelete *.* <br>八、deltree /y [drive:path] <br>deltree 删除子目录及文件,尽管有些文件是系统或隐含的. <br>它可以带有通配符,这时它将删除符合条件的文件或子目录. <br>如:存在L1文件,L2子目录,L3文件,L4子目录 <br>deltree L*.* 将删除以上所有的文件和子目录,但在删除前加以确认,若不删除, <br>可以输入"N". <br>/y 参数是在删除时不加以确认就进行操作的. <br>它删除的文件可以用undelete恢复,?但不能恢复子目录及其下的文件,可以用特 <br>殊工具.如NORTON 8.0 等. <br>若提前使用了undelete/s,?则可以在sentry子目录下找到完整的文件,但名已经 <br>改变了. <br>九、d o s=high[|low[umb|noumb] <br>d o s=high,umb 则d o s将自身装入高端内存(high)并能管理上位内存(umb). <br>noumb 则不管理上位内存. <br>在写入d os =high及umb 前应装入device=himem.sys <br>为了将程序或驱动程序装入上位内存,必须使用d o s=umb,可省出大部分常规内存. <br>可以在c onfig.sys的任何位置写上d o s =high,umb <br>若显示hma not avoiable 或 load down low 则表明不能使用高端内存. <br>十、d o skey 记录以前敲过的d o s 命令,可以用F7来显示,用"&#8593;&#8595;"来选择,用F9来输入 <br>选择的命令号. <br>d o skey /restall 重新装入一次,以前的命令行撤消. <br>d o skey /history 显示内存中所有的命令,可以"&gt;"显示到其它文件中,缩写"/H". <br>d o skey dir=cls 则击入dir等同于cls一样. <br>d o skey /macros 可显示所有的宏定义,可使用"&gt;"重定义到文件中,可缩写"/M". <br>d o skey dir= 可撤消对dir 的宏定义. <br>d o skey p=dir$tdir*.exe/p$tdir c:\t$tdir c:\t$* <br>$t为命令的区分符,而$*为命令的结束符 <br>d o skey /insert(overstrike)?在重新输入命令时,对旧命令的修改是插入还是覆 <br>盖状态(默认). <br>十一、emm386.exe <br>提供对扩展内存的管理,使应用程序象使用常规内存一样能够使用它. <br>常见的用法是 在这个字眼被禁止！fig.sys 中 <br>device=c:\d o s\himem.sys <br>device=c:\d o s\emm386.exe ram <br>d=64 将DMA 内存数量设置为64K <br>noems 提供对上位内存的访问,但不提供对扩展内存的访问. <br>应注意的是在windows中最好不要用它,因为windows本身有对扩展内存进行管理 <br>的程序.应采用windows中的管理器. <br>十二、fc 命令 fc/b dt.dat dt2.dat&gt;b (作二进制代码比较) <br>比较两个文件,一般用作存取进度,修改游戏存储文件用. <br>实际代码位置应加上0100 如:0000 05E4:00 67 <br>实际用debug -e 修改时应加上0100 即 0000 06E4:00 67 <br>后面加上重定向文件"&gt;P" 可以将比较结果输出到p文件中. <br>十三、format /q /u /s /n:sectors /f:size /c <br>/q参数:快速格式化,仅扫描文件分配表和根目录区,仅对格式化过的磁盘有效. <br>使用时应确保格式化过后没有增加新的坏道. <br>/u参数:无条件格式化,并且不保存原来盘上的信息,可以防止"unformat". <br>/s参数:格式化为系统盘,也可以使用"sys"命令. <br>/f:size size 可以为160 180 320 360 720 1200 1440 2800 <br>/n:sector n可以为1 格式为单面盘,容量为160k 180k <br>可以为4 可以在5寸高密驱动器上格式化360k磁盘 <br>可以为8 可以在5寸高密驱动器上进行8个扇区的格式化. <br>/c 重新测试坏扇区,缺省时如果一个扇区标记为"坏",以后格式时就不在从新测 <br>试,仅作标记,使用"/C"时可以从新测试. <br>十四、unformat 命令 <br>对用format 格式过,且未用"/u"参数的命令起作用,用它可以来重新修复已经损 <br>坏的硬盘分区表,但对网络盘不起作用. <br>unformat drive:[/l][/test][/p] <br>/l 显示每一个被unformat发现的文件和子目录,如果没有这个开关,只显示那些 <br>破碎的文件和子目录,可以用ctrl+s 暂停,按任意键继续. <br>/test 仅作一个测试,不作实际的修复工作,作模拟过程. <br>/p 一边测试一边打印. <br>注:这种方法不能保证修复所有的文件,尤其是格式化后又添加过数据的磁盘. <br>恢复后的文件依次存放在s ubdir1....2....3等子目录中. <br>十五、interlnk </p>
<p align=left>语法 interlnk g=e ,它可以通过串口或并口在两机间进行通讯. <br>将服务器端上的e驱动器映射为客户端的g驱动器,以后对客户端而言,所有对g的 <br>操作都意味着对服务器的访问,取消映射的办法为interlnk g= <br>单独输入interlnk 则显示所有的映射情况. <br>注意:interlnk 必须在装入interlnk.exe 设备驱动程序才可以使用. <br>所用的驱动器符号与c onfig.?sys中lastdrv.exe设置的数目有关.可以作一个一 <br>端为25针,另一端为9针的串行线实现,具体接线方式如下: <br>5 - 7 2 - 15 <br>3 - 2 3 - 13 <br>7 - 4 4 - 12 <br>6 - 6 5 - 10 <br>3 - 3 6 - 11 <br>8 - 5 15 - 2 <br>4 - 20 13 - 3 <br>9针 25针 12 - 4 <br>10 - 5 <br>11 - 6 <br>25 - 25 <br>25针 25针 <br>十六、interlnk.exe 与intersvr.exe <br>interlnk.exe 重新定向对于客户驱动器或打印接口的请求到另外的服务器驱动 <br>器或打印机. <br>语法:c o nfig.sys 中加入: <br>device=c:\d o s\interlnk.exe [drive:n][/noprinter][com][lpt] <br>十七、memmaker[/b][/batch][session][/swap:drive] <br>使用memmaker能够优化内存配置,?并将配置写入auto e x e c.bat和c o nfig.sys中. <br>在这一过程中,需要重新启动几次机器. <br>十八、memitem memcolor memdefault s u bmenu 菜单选项include <br>autoe xec.bat 中如下: c onfig.sys中如下: <br>path c:\d o s;c:\u c d o s [menu] <br>d o s k e y menucolor=15,1(前景色15,背景色1) <br>\mouse\mouse menuitem=base_c o nf i g,this is a base <br>goto %c o n f i g% -&gt;选择项 menuitem=cced_c o nfig,this is a cced <br>选项 提示 <br>:base_c o nfig menudefault=base_c o nfig,5 <br>goto exit -&gt;跳出 缺省为base_c o nfig,延迟时间5秒 <br>:cced_c o nfig [common] <br>c:\d o s\smartdrv.exe /l device=c:\d o s\himem.sys <br>goto exit 各项都包含的共同部分 <br>:exit -&gt;结束 [base_c o nfig] <br>device=c:\d o s \emm386.exe ram <br>d o s=high,umb <br>[cced_c o nf i g] <br>device=c:\d o s \smartdrv.exe/double_buffer <br>include=base_c o nf i g 包含base_c o n f i g设置 <br>可以根据计算机的在不同情况下的配置要求来选择. <br>十九、mscdex.exe 提供对光驱进行读写的程序 <br>mscdex/d:drive [/D:drive][/e][/k][/s][/l:letter] <br>典型:这个c o nfig.sys 中device=c:\cdrom\cdrom.sys /d:mscd000 <br>a u t o e x e c.bat中 c:\d o s\mscdex /d:mscd000 /l:g <br>配置了一个光驱,符号为g <br>参数/d:drive1为光驱身份号,须与c o n f i g.sys中的符号一致,可有多个 <br>/d:mscd000 /d:mscd001 <br>/e:使用扩展内存装入光驱驱动程序. <br>/s:使光驱在ms_net或windows是否设置为共享光驱 <br>/V是否在加载时显示内存. <br>/L:letter 分配给光驱的盘符 <br>/m:number 指定缓冲器的数目 <br>应该注意的是:?如果用smartdrv.exe 加速对光驱的读写能力,应该在a u t o e x e c. <br>bat中将mscdex.?exe 写在smartdrv.exe 之前,smartdrv.exe的使用可大幅提高 <br>对驱动器的读写能力. <br>二十、msd的使用 <br>使用msd 可以整体检查计算机配置及系统信息 <br>包括:?驱动器参数,计算机cpu参数,内存大小参数,显示器类型,串.并口情况,以 <br>及各个IRQ占用情况,据此可以分析新增设备是否与原来设备有冲突. <br>同时也可以通过分析内存驻留程序,判断内存中是否有病毒,有则标为"???". <br>二十一、prompt d o s提示符 <br>$q 等于号 $t 当前时间 $d 当前日期 $p 当前驱动器符号 <br>$$ $号提示 $n当前驱动器 $g 大于号 $l小于号 $b 显示"|"管道号 <br>$h 隐去提示符 $E显示"&lt;-"号 <br>对于其它文字,则直接显示文本本身prompt ljw,则显示为ljw提示符 <br>prompt 则仅显示当前驱动器号及大于号. <br>二十二、ramdrive.sys 使用内存当做虚拟盘来使用 <br>应注意,所有数据都存在于内存中,应及时将其存到硬盘中,否则掉电后或者死机 <br>后将丢失全部数据,优点是运行速度快,但不能在windows中使用. <br>示例:这个字眼被禁止！fig.sys: device=c:\这个字眼被禁止！\ramdrive.sys /size[/e|a] <br>size为以k为单位的字节数,即建立的虚拟盘的大小. <br>/e或/a 都是使用扩展内存来建立虚拟盘,?加参数的前提是必须先加载内存管理 <br>器himem.sys及emm386.exe. <br>二十三、这个字眼被禁止！st 将一个驱动器与一个子目录联接 <br>如:将对A:\l1\l2 子目录的请求映射为S盘,则输入 <br>这个字眼被禁止！st s: a:\l1\l2 即可 <br>这样使用dir s:?等命令则显示的是a:\l1\l2子目录下的内容,其它copy del 一样 <br>可以用这个字眼被禁止！st s: d 来取消这种映射. <br>可以用这个字眼被禁止！st 来显示各种联接情况 <br>注意:?可以采用这个字眼被禁止！st a: c:a 来建立一个对于A的读写盘.对于某些安装软件 <br>来说,?必须使用A盘来安装,就可以使用先将所要安装的软件全部拷贝到C:a子 <br>目录中,然后输入这个字眼被禁止！st a: c:a,再转到A:,就可以进行软件的安装了. <br>二十四、mem /c /m /p /d 常规内存显示程序 <br>/c显示所有内存驻留程序的占用情况,分为这个字眼被禁止！ventional常规内存和uppermemory <br>高端内存占用,并显示总的占用情况(常规 高端 保留 扩展内存) <br>/p分页显示,页间暂停 <br>/m后加模块名 如:/m ms这个字眼被禁止！ 显示这个字眼被禁止！系统内存的占用. <br>/d对常规 高端 保留 扩展内存加以详细例表说明 <br>通过分析,可以看出内存占用是否合理,以及各种程序是否正常加载,从而在此基 <br>础上使用内存优化工具memmaker进行各种管理,同时又可以分析出一些程序死机 <br>的原因,若有的地方显示"???",则可以断定内存中有病毒的存在,有利于发现及消灭. <br>二十五、各种管道工具的使用"&gt; &lt; &gt;&gt; &lt;&lt;" <br>将各种命令造成的输出或所需要的输入重新定向 <br>如:dir *.bat /b&gt;p 可以将dir *.bat 例出的文件名输出到p文件中. <br>time&lt;p&gt;&gt;p.bat <br>p文件中仅存在一个回车符,则可以将时间追加进p.bat文件中 <br>"&gt; &gt;&gt;" 是将命令产生的输出重新定向,比如到文件或打印机中. <br>&gt;&gt;产生的内容将追加进文件中,&gt;则将原文件内容覆盖. <br>"&lt; &lt;&lt;" 是将命令所需要输入的内容重新定向. <br>如:time&lt;p 在批中可以是时间代码或回车符,可以以此改变时间. <br>需要说明的是 "prn "为打印机, "这个字眼被禁止！l"为空设备 <br>这个字眼被禁止！ 为显示器 <br>type p.bat&gt;prn 可将p.bat打印出来. <br>copy 这个字眼被禁止！l p 可将p文件删除掉 <br>copy 这个字眼被禁止！ p 可以在屏幕上编辑p文件,F6可以存盘退出 <br>type p&gt;pp 完成p文件到pp 的复制 <br>type p|more 可在屏满时暂停显示 <br>二十六、move 命令 <br>move [y/-y] filename1 filename2 <br>将文件1移动到文件2处 <br>如:move c:\这个字眼被禁止！\*.* c:\cced <br>将这个字眼被禁止！子目录下的所有文件全部移动到cced 子目录下 <br>/y|-y参数在目标目录不存在需要创建时,是否出现提示 <br>可以使用该命令修改子目录名称,如 move 这个字眼被禁止！ cced <br>将这个字眼被禁止！目录名改为cced <br>二十七、append 指定一些特殊数据文件的存放位置,如user.dat pe2.pro等一些非*. <br>exe *.com *.bat 文件 <br>格式:append [:]终止以前存在的指定目录 append 显示指定情况 <br>append [path] append c:\user 等 <br>二十八、 <br>call 在一个批处理命令中调用另外一个批处理文件 <br>(1)不终止现有文件的运行,执行完掉用程序后立即返回. <br>(2)被调用批处理命令必须以bat 为扩展名 <br>(3)调用批处理文件时,可以加上参数(%1-%9)以及环境变量如%baud% <br>(4)不能使用管道工具及重定向工具 <br>二十九、device devicehigh loadhigh <br>device 将指定的设备驱动程序装入内存中 <br>devicehigh将指定的设备驱动程序装入高端内存中 <br>loadhigh 将指定的设备驱动程序装入高端内存中 <br>三十、defrag 优化磁盘 <br>legend(传奇) optimize(优化) elapse(逝去) fragment(碎片) <br>该命令执行对指定的盘进行优化处理(包括检查文件分配表,各文件状态,纠正错 <br>误),在执行时,可按照文件名大小,时间,扩展名对文件进行排序. </p>
<p align=left><br>四.UNIX 常用的指令 <br>以下只说明各指令的基本用法, 若需详细说明, 请用 man 去读详细的 manual. <br>1. ls <br>这是最基本的档案指令。 ls 的意义为 "list"，也就是将某一个目录或是某一个档案的内容显示出来。如果你在下 ls 指令後头没有跟著任何的档名，它将会显示出目前目录中所有档案。也可以在 ls 後面加上所要察看的目录名称或档案的名称，如 <br>% ls /etc <br>ls 有一些特别的参数，可以给予使用者更多有关的资讯，如下: <br>-a : 在 UNIX 中若一个目录或档案名字的第一个字元为 "." , 则使用 ls <br>将不会显示出这个档案的名字，我们称此类档案为隐藏档。如 tcsh的初设档 .tcshrc；如果我们要察看这类档案，则必须加上参数 -a 。 <br>-l : 这个参数代表使用 ls 的长( long )格式，可以显示更多的资讯，如档案存取权，档案拥有者( owner )，档案大小，档案最後更新日期，甚而 symbolic link 的档案是 link 那一个档等等。如下 <br>% ls -l <br>2. cp <br>cp 这个指令的意义是复制("COPY") , 也就是将一个或多个档案复制成另一个档案或者是将其复制到另一个目录去。 <br>-i : 此参数是当已有档名为 f2 的档案时，若迳自使用 cp 将会将原来 f2 <br>的内容掩盖过去，因此在要盖过之前必须先询问使用者一下。如使用者 <br>的回答是y(yes)才执行复制的动作。 <br>-r : 此参数是用来做递回复制用，可将一整颗子树都复制到另一个 <br>目录中。 <br>3. mv <br>mv 的意义为 move , 主要是将一档案改名或换至另一个目录。如同 cp ，它也有三种格式: <br>mv 的参数有两个，-f 和 -i , 其中 -i 的意义与 cp 中的相同，均是 interactive <br>询问之意。而 -f 为强迫( force ) , 就是不管有没有同名的档案，反正我就是要 <br>搬过去，所有其他的参数遇到 -f 均会失效 <br>4. rm <br>rm 的意义是 remove ，也就是用来杀掉一个档案的指令。在 UNIX 中一 <br>个被杀掉的档案除非是系统恰好有做备份，否则是无法像 这个字眼被禁止！ 里面一样还能够救回 <br>来的。所以在做 rm 动作的时候使用者应该要特别小心。 <br>-f : 将会使得系统在删除时，不提出任何警告讯息。 <br>-i : 在除去档案之前均会询问是否真要除去。 <br>-r : 递回式的删除。 <br>5. mkdir <br>mkdir 是一个让使用者建立一个目录的指令。你可以在一个目录底下使用 <br>midir 建立一个子目录，使用的方法就不用多说了吧！ <br>6. chdir ( cd ) <br>这是让使用者用来转移工作目录用的。 <br>chdir dirname <br>如此你就可以将目前的目录转移到 dirname 这一个目录去。或使用 "chdir .." 来转移到上一层目录。 <br>7. rmdir <br>相对於 mkdir ，rmdir 是用来将一个"空的"目录杀掉的。如果一个目录下面没有任何档案，你就可以用 rmdir 指令将其除去。rmdir 的使用法如下: <br>rmdir dirname1 [ dirname2 .... ] <br>如果一个目录底下有其他的档案， rmdir 将无法将这个目录杀掉，除非使用 rm 指令的 -r 选项。 <br>8. pwd <br>pwd 会将目前目录的路径( path )显示出来，例如: <br>9. cat/more/less <br>以上三个指令均为察看档案内容的指令。cat 的意义是猫....不不不，是 这个字眼被禁止！catenate ，在字典上的意思是"连结,将&#8230;串成锁状"( 语出资工电子词典 cdict )，其实就是把档案的内容显示出来的意思。 cat 有许多奇怪的参数，较常为人所使用的是 -n 参数，也就是把显示出来的内容加上行号。 cat 的用法如下: <br>cat [-n] :自标准输入读进内容，你可以用 pipe 将别的程式的输出转向 <br>给 cat . <br>cat [-n] filename : 将 filename 的内容读进来，显示在标准输出上。问题在於 cat 它是不会停下来的，因此并不好用( 试想如果一个萤幕二十四行，而一个档案四百行，cat 一出来将会劈哩啪啦不断的卷上去，使用者很难据此得到他们所需的资讯。) 所以才有人又写了 more 出来。 <br>more ,可以将所观察的档案跟据终端机的形态一页页的显示出来，再根据使用者的要求换页或卷行。如果使用者要在某一个档案中搜寻一个特定的字串，则按 / 然後跟著打所要搜寻的单字即可进行搜寻。more 也可以找得到。more 的使用法如下: <br>more filename <br>如果你在使用中觉得已经看到了所要看的部份，可以按'q'离开 more 的使用。在使用中按'v' 亦可以使用编辑器来编辑所观看的档案。less 的用法与 more 极类似，原先它就是为了弥补 more 只能往前方卷页的缺点而设计。 less 的用法如下: <br>less filename <br>其与 more 不同的是它可以按 y 来往上卷一行，并且可以用"?"来往回搜寻你所要找的单字。 <br>10. chmod <br>chmod 为变更档案模式用( change mode ) . 这个指令是用来更改档案的存取模式( access mode )。在 UNIX 一个档案上有可读(r)可写(w)可执行(x)三种模式,分别针对该档案的拥有者( onwer )、同群者( group member )( 你可以 ls -lg来观看某一档案的所属的 group )，以及其他人( other )。一个档案如果改成可执行模式则系统就将其视为一个可执行档，而一个目录的可执行模式代表使用者有进入该目录之权利。chmod 就是用来变更一些档案的模式，其使用方式如下: <br>chmod [ -fR ] mode filename ... <br>其参数的意义如下: <br>-f Force. chmod 不会理会失败的动作。 <br>-R Recurive. 会将所有子树下的所有子目录及档案改为你所要改成的模式。 <br>mode 可以为一个三位或四位的八进位数字，来表示对某些对象的存取权。详情可参阅 chmod(1) 的 manual page 中有关 Absolute Modes 的说明。或是用一个字串来表示，请参考 chmod(1) 的说明。 </p>
<p align=left>二. 关於 Process 处理的指令: <br>1. ps <br>ps 是用来显示目前你的 process 或系统 processes 的状况。 <br>以下列出比较常用的参数: <br>其选项说明如下: <br>-a 列出包括其他 users 的 process 状况。 <br>-u 显示 user - oriented 的 process 状况 。 <br>-x 显示包括没有 terminal 控制的 process 状况 。 <br>-w 使用较宽的显示模式来显示 process 状况 。 <br>我们可以经由 ps 取得目前 processes 的状况，如 pid , running state 等。 <br>2. kill <br>kill 指令的用途是送一个 signal 给某一个 process 。因为大部份送的都是 <br>用来杀掉 process 的 SIGKILL 或 SIGHUP ，因此称为 kill 。kill 的用法 <br>为: <br>kill [ -SIGNAL ] pid ... <br>kill -l <br>SIGNAL 为一个 singal 的数字，从 0 到 31 ，其中 9 是 SIGKILL ，也就是一 <br>般用来杀掉一些无法正常 terminate 的讯号。其馀讯号的用途可参考 sigvec(2) <br>中对 signal 的说明。 <br>你也可以用 kill -l 来察看可代替 signal 号码的数目字。kill 的详细情形 <br>请参阅 man kill。 <br>三. 关於字串处理的指令: <br>1. echo <br>echo 是用来显示一字串在终端机上。□ echo -n 则是当显示完之後不会有跳行的动作。 <br>2. grep/fgrep <br>grep 为一过滤器，它可自一个或多个档案中过滤出具有某个字串的行，或是 <br>自标准输入过滤出具有某个字串的行。 <br>fgrep 可将欲过滤的一群字串放在某一个档案中，然後使用 fgrep 将包含有 <br>属於这一群字串的行过滤出来。 <br>grep 与 fgrep 的用法如下: <br>grep [-nv] match_pattern file1 file2 .... <br>fgrep [-nv] -f pattern_file file1 file2 .... <br>-n 把所找到的行在行前加上行号列出 <br>-v 把不包含 match_pattern 的行列出 <br>match_pattern 所要搜寻的字串 <br>-f 以 pattern_file 存放所要搜寻的字串 <br>四. 网路上查询状况的指令: <br>1. man <br>man 是手册 ( manual ) 的意思。 UNIX 提供线上辅助( on-line help )的功能， <br>man 就是用来让使用者在使用时查询指令、系统呼叫、标准程式库函式、各种表 <br>格等的使用所用的。man 的用法如下: <br>man [-M path] [section] title ] ..... <br>man [-M path] -k keyword ... <br>-M path man 所需要的 manual database 的路径。 <br>我们也可以用设定环境变数 MANPATH 的方式来取代 -M 选项。 <br>title 这是所要查询的目的物。 <br>section 为一个数字表示 manual 的分类，通常 1 代表可执行指令， <br>2 代表系统呼叫( system call ) ，3 代表标准函数，等等。 <br>我们如要参考 eqnchar(7) 的资料，则我们就输入 man 7 eqnchar ， <br>便能取得我们所要的辅助讯息。 <br>-k keyword <br>用来将含有这项 keyword 的 title 列出来。 <br>man 在 UNIX 上是一项非常重要的指令，我们在本讲义中所述之用法均仅只是一个大家比较常用的用法以及简单的说明，真正详细的用法与说明还是要请你使用 man 来得到。 <br>2. who <br>who 指令是用来查询目前有那些人在线上。 <br>3. w <br>w 指令是用来查询目前有那些人在线上，同时显示出那些人目前的工作。 <br>4. ku <br>ku 可以用来搜寻整个网路上的 user ，不像 w 跟 who 只是针对 local host 的查询. 而且 ku 提供让使用者建立搜寻特定使用者名单的功能。你可以建立一个档案 information-file 以条列的方式存放你的朋友的资料，再建立一个档案 hosts-file 来指定搜寻的机器名称。 ku 的指令格式可由 ku -h 得到。 </p>
<p align=left>五. 网路指令: <br>UNIX 提供网路的连接，使得你可以在各个不同的机器上做一些特殊的事情，如你可以在系上的 iris 图形工作站上做图形的处理，在系上的 Sun 上读 News ，甚至到学校的计中去找别系的同学 talk 。这些工作可以利用 UNIX 的网路指令，在你的位子上连到各个不同的机器上工作。如此一来，即使你在寝室，也能轻易的连至系上或计中来工作，不用像以前的人必须泡在冷冰冰的机房面。 <br>这些网路的指令如下所述: <br>1. rlogin 与 rsh <br>rlogin 的意义是 remote login , 也就是经由网路到另外一部机器 login 。 <br>rlogin 的格式是: <br>rlogin host [ -l username ] <br>选项 -l username 是当你在远方的机器上的 username 和 local host 不同的时後，必须输入的选项，否则 rlogin 将会假设你在那边的 username 与 localhost 相同，然後在第一次 login 时必然会发生错误。 <br>rsh 是在远方的机器上执行某些指令，而把结果传回 local host 。rsh 的格式 <br>如下: <br>rsh host [ -l username ] [ command ] <br>如同 rlogin 的参数 -l username , rsh 的 -l username 也是指定 remote host的 username 。而 command 则是要在 remote host 上执行的指令。如果没有 指定 command ，则 rsh 会去执行 rlogin ，如同直接执行 rlogin 。 <br>不过 rsh 在执行的时候并不会像一般的 login 程序一样还会问你 password , 而是如果你没有设定 trust table , 则 remote host 将不会接受你的 request 。 <br>rsh 须要在每个可能会做为 remote host 的机器上设定一个档案，称为 .rhosts。这个档案每一行分为两个部份，第一个是允许 login 的 hostname , 第二个部份则是允许 login 的username 。例如，在 ccsun7.csie.nctu.edu.tw 上头你的 username 为 QiangGe , 而你的 home 下面的 .rhost 有以下的一行: <br>ccsun6.cc.nctu.edu.tw u8217529 <br>则在 ccsun6.cc.nctu.edu.tw 机器上的 user u8217529 就可以用以下的方法来执行 rsh 程式: <br>% rsh ccsun7.csie.nctu.edu.tw -l ysjuang cat mbox <br>将 ysjuang 在 ccsun7.csie.nctu.edu.tw 上的 mbox 档案内容显示在 local host ccsun6.cc.nctu.edu.tw 上。 <br>而如果 .rhost 有这样的一行，则 ccsun6.cc.nctu.edu.tw 上的 user u8217529 <br>将可以不用输入 password 而直接经由 rsh 或 rlogin login 到 <br>ccsun7.csie.nctu.edu.tw 来。 <br>注意: <br>.rhost 是一个设定可以信任的人 login 的表格，因此如果设定不当将会让不法之徒有可以乘机侵入系统的机会。 如果你阅读 man 5 rhosts ，将会发现你可以在第一栏用 + 来取代任何 hostname ，第二栏用 + 来取代任何username 。 <br>如一般 user 喜欢偷懒利用 " + username " 来代替列一长串 hostname ，但是这样将会使得即使有一台 PC 上跑 UNIX 的 user 有与你相同的 username , 也可以得到你的 trust 而侵入你的系统。这样容易造成系统安全上的危险。因此本系禁止使用这样子的方式写你的 .rhost 档，如果 <br>发现将予以停机直到你找中心的工作人员将其改正为止。 同理，如果你的第二个栏位为 + ，如" hostname + " ,则你是允许在某一部机器上的"所有"user 可以不用经由输入 password 来进入你的帐号，是壹种更危险的行为。所以请自行小心。 <br>2. telnet <br>telnet 是一个提供 user 经由网路连到 remote host。 <br>telnet 的 格式如下: <br>telnet [ hostname | ip-address ] [ port ] <br>hostname 为一个像 ccsun1 或是 ccsun1.cc.nctu.edu.tw 的 name address，ip-address 则为一个由四个小於 255 的数字组成的 ip address ，如 ccsun1的 ip-address 为140.113.17.173 ，ccsun1.cc.nctu.edu.tw 的 ip-address为 140.113.4.11 。你可以利用 telnet ccsun1 或telnet 140.113.17.173 来连到 ccsun1。 <br>port 为一些特殊的程式所提供给外界的沟通点，如资工系的 MUD 其 server 便提供一些 port 让 user 由这些 port 进入 MUD 程式。详情请参阅 telnet(1)的说明。 <br>3. ftp <br>ftp 的意义是 File Transfer Program ，是一个很常应用在网路档案传输的 <br>程式。ftp 的格式如下: <br>ftp [ hostname | ip-address ] <br>其中 hostname | ip-address 的意义跟 telnet 中的相同。 <br>在进入 ftp 之後，如果与 remote host 连接上了，它将会询问你 username 与密码，如果输入对了就可以开始进行档案传输。 <br>在 ftp 中有许多的命令，详细的使用方式请参考 ftp(1) ，这里仅列出较常用的 cd , lcd , mkdir , put , mput , get , mget , binary , ascii , prompt , help 与 quit 的使用方式。 <br>ascii 将传输模式设为 ascii 模式。通常用於传送文字档。 <br>binary 将传输模式设为 binary 模式，通常用於传送执行档，压缩档与影像档等。 <br>cd remote-directory 将 remote host 上的工作目录改变。 <br>lcd [ directory ] 更改 local host 的工作目录。 <br>ls [ remote-directory ] [ local-file ] 列出 remote host 上的档案。 <br>get remote-file [ local-file ] 取得远方的档案。 <br>mget remote-files 可使用通用字元一次取得多个档案。 <br>put local-file [ remote-file] 将 local host 的档案送到 remote host。 <br>mput local-files 可使用通用字元一次将多个档案放到 remote host 上。 <br>help [ command ] 线上辅助指令。 <br>mkdir directory-name 在 remote host 造一个目录。 <br>prompt 更改交谈模式，若为 on 则在 mput 与 mget 时每作一个档案之传输时均会询问。 <br>quit/bye 离开ftp . <br>利用 ftp ，我们便可以在不同的机器上将所需要的资料做转移，某些特别的机器更存放大量的资料以供各地的使用者抓取，本校较著名的 ftp server 有 NCTUCCCA 与系上的ftp.csie.nctu.edu.tw 。这些 ftp server 均有提供一个 user 称为 anonymous ，一般的"外来客"可以利用这个 username 取得该 server 的公共资料。不过 anonymous 在询问 password 时是要求使用anonymous 的使用者输入其 email address，以往有许多台湾的使用者在使用国外的 ftp server 时并没有按照人家的要求输入其 email address，而仅是随便打一些字串，引起许多 internet user 和管理者的不满，对台湾的使用者的风评变得很差，因此遵循各 ftp server 的使用规则也是一件相当重要的事。 <br>六. 关於通讯用的指令: <br>1. write <br>这个指令是提供使用者传送讯息给另一个使用者，使用方式: <br>write username [tty] <br>2. talk/ytalk/cytalk/ctalk <br>UNIX 专用的交谈程式。会将萤幕分隔开为你的区域和交谈对象的区域，同时也可和不同机器的使用者交谈。使用方式: <br>talk username[@host] [tty] <br>3. mesg <br>选择是否接受他人的 messege , 若为 messege no 则他人的 messege 将无法传送给你，同时他也无法干扰你的工作。使用方法: <br>mesg [-n|-y] <br>4. mail/elm <br>在网路上的 email 程式，可经由此程式将信件 mail 给他人。 使用方式: <br>mail [username] <br>mail -f mailboxfile <br>如有信件，则直接键入 mail 可以读取你的 mail . <br>elm 提供较 mail 更为方便的介面，而且可做线上的 alias . 你可以进入 elm <br>使用上下左右键来选读取的信件，并可按 h 取得线上的 help 文件。 <br>使用方式: <br>elm [usernmae] <br>elm -f mailboxfile <br>七. 编译器( Compiler ): <br>Compiler 的用处在於将你所撰写的程式翻译成一个可执行档案。在资工系常用的程式语言是 C , pascal , FORTRAN 等。你可以先写好一个 C 或 Pascal 或 FORTRAN 的原始程式档，再用这些 compiler 将其翻成可执行档。你可以用这个方法来制造你自己的特殊指令。 <br>1. cc/gcc (C Compiler) <br>/usr/bin/cc <br>/usr/local/bin/gcc <br>语法: cc [ -o 这个字眼被禁止！file ] source <br>gcc [ -o 这个字眼被禁止！file ] source <br>这个字眼被禁止！file 是你所希望的执行档的名称，如果没有加上 -o 选项编译出来的可执行档会以 a.out 做为档名。 source 为一个以 .c 做为结尾的 C 程式档。请参阅 cc(1) 的说明。 <br>2. pc (Pascal Compiler) <br>/usr/local/bin/pc <br>语法: pc [ -o 这个字眼被禁止！file ] source <br>这个字眼被禁止！file 是你所希望的执行档的名称，如果没有加上 -o 选项编译出来的可执行档会以 a.out 做为档名。 source 为一个以 .p 做为结尾的 Pascal 程式档。 请参阅 /net/home5/lang/man 中 pc(1) 的说明。 <br>3. f77 (Fortran Compiler) <br>/net/home5/lang/f77 <br>语法: f77 [ -o 这个字眼被禁止！file ] source <br>这个字眼被禁止！file 是你所希望的执行档的名称，如果没有加上 -o 选项编译出来的可执行档会以 a.out 做为档名。 source 为一个以 .p 做为结尾的 FORTRAN 程式档。 </p>
<p align=left>八. 有关列印的指令: <br>以下为印表所会用到的指令，在本系的印表机有 lp1 , lp2 ( 点矩阵印表机 )， <br>lw , sp , ps , compaq ( 雷射印表机 )，供使用者使用。 <br>1. lpr <br>lpr 为用来将一个档案印至列表机的指令。 <br>用法: <br>lpr -P[ printer ] file1 file2 file3 .... <br>或 <br>lpr -P[ printer ] &lt; file1 <br>例子: <br>lpr -Plp1 hello.c hello.lst hello.map <br>lpr -Plp1 &lt; hello.c <br>前者以参数输入所要印出的档案内容，後者列印标准输入档案(standard input)的内容，因已将 hello.c 转向到标准输入，故会印出 hello.c 的档案内容。 <br>2. lpq <br>lpq 是用来观察 printer queue 上的 Jobs 。 <br>用法: <br>lpq -P[ printer ] <br>3. lprm <br>lprm 是用来取消列印要求的指令。 通常我们有时会印错，或是误送非文字档资料至 printer , 此时就必须利用 lprm 取消列印 request ，以免造成资源的浪费。 <br>用法: <br>lprm -P[ printer ] [ Jobs id | username ] <br>lprm 用来清除 printer queue 中的 Jobs , 如果你使用 Job Id 作为参数，则它将此 Job 自printer queue 清除，如果你用 username作为参数，则它将此 queue中所有 Owner 为此username 的 Jobs 清除。 <br>九. 更改个人使用资料: <br>1. passwd <br>passwd 是用来更改你的使用密码，用法为: <br>passwd [ username ] <br>在使用 passwd 的时候，它会先问你的旧密码，然後询问两次要更改的密码，确定无误後才将你的密码改掉。 <br>2. chsh <br>chsh 是提供使用者更换 login shell 的指令，你可经由此更换自己使用的 shell 。 </p>
<p align=left><br>五.Novell网络命令集 <br>1，A这个字眼被禁止！SOLE <br>用来接收可传送远端文件服务器的屏幕和键盘数据的管理程序。 <br>2，ALLOW <br>查看或修改目录或文件的继承权(Inheriter rights). <br>3，CASTOFF <br>作用是使接收消息的功能失效。目的是防止当前进行的工作被干扰可打断。 <br>4，CASTON <br>恢复接收消息的能力。 <br>5，CHKDIR <br>用来查看某个目录所占用的空间。 <br>6，CHKVOL <br>用来查看卷的磁盘空间。 <br>7，COLORPAL <br>用来改变各通用程序的颜色，建议使用缺省值。 <br>Color Palette 0:改变菜单的底色，菜单中的字样光标及外框的颜色。 <br>Color Palette 1：改变屏幕的背景颜色和主标题的颜色。 <br>Color Palette 2：改变帮助窗口的颜色。 <br>Color Palette 3：改变错误信息的颜色。 <br>Color Palette 4：改变退出与警告的画面颜色。 <br>8，DSPACE <br>与SYS这个字眼被禁止！的&#8220;volume/Disk Pestnetions&#8221;的功能相同，如果是SUPERVISOR则可设置其它用户的磁盘空间，如果是用户本身则只能查看自己的磁盘空间，另一功能是列出和改变连接到其他的FILE SERVER。 <br>9，F这个字眼被禁止！SOLE <br>可作为广播消息。 <br>改变到其他的FILE SERVER。 <br>连接到FILE SERVER的信息。 <br>关闭FILE SERVER。 <br>查看FILE SERVER的版本等。 <br>10，FLAG <br>属性可以在网络中提供目录或文件的安全性更多一层人保障，它有下列功能： <br>1，防止文件被写入 <br>2，防止文件被拷贝。 <br>3，防止目录/文件被误删。 <br>4，防止目录/文件内容被查看。 <br>以上功能与d o s 的ATTRIB的功能相当，但其余的功能在网络上具有特殊的用途。 <br>1，加上SHARABLE属性，则在同一时间内可让多位用户使用。 <br>2，加上ARCHIVE NEEDED，经跟踪的文件能被自动自制。 <br>11，FLAGDIR <br>用来查阅可改变目录/文件属性，也可用FILER设置文件属性。 <br>12，GRANT <br>赋予用户成为某目录/文件的使用者。 <br>13，LISTDIR <br>1，查看某目录下的子目录。 <br>2，查看每一个子目录的继承权限屏蔽。 <br>3，查看每一个子目录的有效权限。 <br>4，查看每一个子目录的建立日期与时间。 <br>5，查看子目录其所属的子目录。 <br>14，NCOPY <br>除具备d o s的COPY功能外，还可以在网络中不同的FILE SERVER的卷与目录间相互拷贝，并保留原先的文件属性。 <br>15，NDIR <br>除具备d o s的DIR相同的功能外，还能查询文件属性，有效权限，继承权限，拥有者等信息。 <br>16，NVER <br>它包含以下内容：Net BIOS,IPX,SPX,LAN driver,shell,d o s 版本，FILER SERVER版本。 <br>17，PURGE与SALVAGE <br>PURGE是永久删除文件，而SALVAGE可恢复非永久删除文件。 <br>18，REMOVE <br>用REMOVE可从文件或目录中的继承权列表中删除一个用户或一个组。即文件或目录的用户或组将被删除。 <br>19，RENDIR <br>更改目录的名称。 <br>20，REVOKE <br>用它可删除用户可组中对文件或目录的受托者权限，即用户或组所使用的文件或目录将被删除。 <br>21，SEND <br>用它可传送一个消息给所有已登录的用户，可列出用户列表，或连接号码列表。 <br>22，SESSION <br>1，连接到其他的FILE SERVER。 <br>2，磁盘映象。 <br>3，查看网络上的组或传送一些消息给组。 <br>4，暂时地建立，改变或删除搜索磁盘驱动器。 <br>5，选择缺省。 <br>6，列出用户信息并传送消息给用户。 <br>23，SETPASS <br>可建立可修改一个可多个FILE SERVER的密码，也可使多重FILE SERVER 上的password同步化。 <br>24，SETTTS <br>使用它可保证事务跟踪系统的有效使用。 <br>25，SLIST <br>它是用来查处在多重网络上的FILE SERVER列表及关于这此FILE SERVER的信息。 <br>26，SMODE <br>它是用来指定一个程序在寻找一数据文件时如何使用搜索磁盘驱动器。 <br>27，SYSTIME <br>它可用来查处在网络或多重网络上的FILE SERVER的日期及时间。 <br>28，TLIST <br>它可用来查看某目录可文件的受托者权限列表。 <br>29，USERDEF <br>系统管理员可用它来完成下列工作： <br>1，建立我重用户。 <br>2，提供简单的登录原稿。 <br>3，设置原始目录区。 <br>4，设置最小的登录/密码安全性。 <br>5，指定帐户及限制磁盘空间。 <br>6，设置打印工作选项。 <br>30，USERLIST <br>1，查看一已知的FILE SERVER当前用户列表。 <br>2，查看每一个用户的连接号码。 <br>3，查看登录时间。 <br>4，查看网络地址和节点地址。 <br>5，查看所连接的FILE SERVER的类型。 <br>31，VERSION <br>它是用来查看FILE SERVER的版本及版权须知。 <br>32，VILINFO <br>它可用来查看FILE SERVER上每个卷的信息。</p>
<p>&#160;</p>
<p>&#160;</p>
</div>
<hr align=left>
<img src ="http://www.cppblog.com/andxie99/aggbug/8761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-20 17:24 <a href="http://www.cppblog.com/andxie99/archive/2006/06/20/8761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>来个小测试^_^</title><link>http://www.cppblog.com/andxie99/archive/2006/06/16/8637.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Fri, 16 Jun 2006 06:07:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/16/8637.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/8637.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/16/8637.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/8637.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/8637.html</trackback:ping><description><![CDATA[<br><!--start of game-->
<table id=form_test>
    <tbody>
        <tr>
            <td>
            <center><font size=+0><strong>&nbsp; &nbsp; &nbsp; &nbsp; 您认为您能灵活运用鼠标吗？ 在这您自测一下吧：从您点击下面的复选框开始，您有20秒的时间，请尽可能的多勾选以下的复选框。Good luck!</strong> </font><script language="JavaScript">
														<!--
	document.write("<CENTER>");
	document.write('<INPUT TYPE="text" VALUE="0" NAME="num" SIZE=10 onFocus="this.blur()"><BR>');
	document.write("<HR SIZE=1 WIDTH=40%>");
	for (var i = 0; i < 10; ++i)
         {
	 for (var j = 0; j < 10; ++j)
          {
	  document.write('<INPUT TYPE="checkbox" name="chbBox" onClick="displayTest(this)">');
	  }	
	 document.write("<BR>");
	 }
	document.write("<HR SIZE=1 WIDTH=40%>");
	document.write('<INPUT TYPE="button" VALUE="重新开始" onClick="restart(document.getElementById())">');
	document.write("</CENTER>");
// -->
												</script></center></td>
        </tr>
    </tbody>
</table>
<!--end of game-->
<img src ="http://www.cppblog.com/andxie99/aggbug/8637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-16 14:07 <a href="http://www.cppblog.com/andxie99/archive/2006/06/16/8637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式之道</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7979.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:47:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7979.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7979.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7979.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7979.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7979.html</trackback:ping><description><![CDATA[<p>&#160;</p>
<div style="CLEAR: both"></div>
前一阵用C++写ISAPI筛选器，在筛选规则的正则表达式上折腾了好一阵，最后发现不同语言环境里的正则表达式的语法不同，整理了些资料，记录如下：<br>
<h1>目 录</h1>
<p><strong><a href="#WhatAreRegularExpressions"><u><span style="COLOR: #800080">什么是正则表达式</span></u></a></strong><br><strong><a href="#SimpleCommands"><u><span style="COLOR: #800080">范例</span></u></a></strong><br>&nbsp; &nbsp; <a href="#SimpleCommands"><u><span style="COLOR: #800080">简单</span></u></a><br>&nbsp; &nbsp; <a href="#MediumDifficultyExamples"><u><span style="COLOR: #800080">中级（神奇的咒语）</span></u></a><br>&nbsp; &nbsp; <a href="#HardExamples"><span style="COLOR: #800080"><u>困难（不可思议的象形文字）</u></span></a><br><strong><a href="#Regular_Expressions_In_Various_Tools"><u><span style="COLOR: #800080">不同工具中的正则表达式</span></u></a></strong></p>
<hr width="100%">
<br>
<h1><a name=WhatAreRegularExpressions></a>什么是正则表达式</h1>
一个正则表达式，就是用某种模式去匹配一类字符串的一个公式。很多人因为它们看上去比较古怪而且复杂所以不敢去使用——很不幸，这篇文章也不能够改变这一点，不过，经过一点点练习之后我就开始觉得这些复杂的表达式其实写起来还是相当简单的，而且，一旦你弄懂它们，你就能把数小时辛苦而且易错的文本处理工作压缩在几分钟（甚至几秒钟）内完成。正则表达式被各种文本编辑软件、类库（例如Rogue Wave的tools.h++）、脚本工具（像awk/grep/sed）广泛的支持，而且像Microsoft的Visual C++这种交互式IDE也开始支持它了。
<p>我们将在如下的章节中利用一些例子来解释正则表达式的用法，绝大部分的例子是基于<strong><tt>vi</tt></strong>中的文本替换命令和<strong><tt>grep</tt></strong>文件搜索命令来书写的，不过它们都是比较典型的例子，其中的概念可以在sed、awk、perl和其他支持正则表达式的编程语言中使用。你可以看看<a href="#Regular_Expressions_In_Various_Tools"><u><span style="COLOR: #800080">不同工具中的正则表达式</span></u></a>这一节，其中有一些在别的工具中使用正则表达式的例子。还有一个关于vi中文本替换命令（s）的<a href="#ViSubstitutionCommandSyntax"><u><span style="COLOR: #800080">简单说明</span></u></a>附在文后供参考。</p>
<h2>正则表达式基础</h2>
正则表达式由一些普通字符和一些<em>元字符（metacharacters）</em>组成。普通字符包括大小写的字母和数字，而元字符则具有特殊的含义，我们下面会给予解释。
<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><span style="FONT-FAMILY: Courier New">.</span></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>。 </td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt>$</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>"。 </td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><span>^</span></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>*</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>\</tt></strong></center></td>
            <td></td>
            <td>这是引用府，用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式<strong><tt>\$</tt></strong>被用来匹配美元符号，而不是行尾，类似的，正则表达式<tt><strong>\.</strong></tt>用来匹配点字符，而不是任何字符的通配符。</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt>[ ] </tt></strong><strong><tt>[c<span>1</span><span>-c</span><span>2</span><span>]</span></tt></strong><strong><tt>[^c<span>1</span><span>-c</span><span>2</span><span>]</span></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>\&lt; \&gt;</tt></strong></center></td>
            <td></td>
            <td>匹配词（<em>word</em>）的开始（\&lt;）和结束（\&gt;）。例如正则表达式<strong><tt><span style="FONT-FAMILY: Courier New">\&lt;the</span></tt></strong>能够匹配字符串"<em>for the wise</em>"中的"the"，但是不能匹配字符串"<em>otherwise</em>"中的"the"。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
        <tr>
            <td vAlign=top>
            <center><strong><tt>\( \)</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></tt></strong></center></td>
            <td></td>
            <td>将两个匹配条件进行逻辑&#8220;或&#8221;（<em>Or</em>）运算。例如正则表达式<strong><tt><span style="FONT-FAMILY: Courier New">(himher)</span></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>+</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><span>?</span></tt></strong></center></td>
            <td></td>
            <td>匹配0或1个正好在它之前的那个字符。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
        <tr vAlign=baseline>
            <td>
            <center><strong><span><tt><span style="FONT-FAMILY: Courier New">\{</span></tt><em>i</em><tt><span style="FONT-FAMILY: Courier New">\}</span></tt></span></strong><strong><span><tt><span style="FONT-FAMILY: Courier New">\{</span></tt><em>i</em><tt><span style="FONT-FAMILY: Courier New">,</span></tt><em>j</em><tt><span style="FONT-FAMILY: Courier New">\}</span></tt></span></strong></center></td>
            <td></td>
            <td vAlign=baseline>匹配指定数目的字符，这些字符是在它之前的表达式定义的。例如正则表达式<strong><tt><span style="FONT-FAMILY: Courier New">A[0-9]\{3\}</span></tt></strong> 能够匹配字符"A"后面跟着正好3个数字字符的串，例如A123、A348等，但是不匹配A1234。而正则表达式<strong><tt><span style="FONT-FAMILY: Courier New">[0-9]\{4,6\}</span></tt></strong> 匹配连续的任意4个、5个或者6个数字字符。<strong>注意</strong>：这个元字符不是所有的软件都支持的。</td>
        </tr>
    </tbody>
</table>
<hr width="100%">
<br>
<p>最简单的元字符是点，它能够匹配任何单个字符（注意<strong>不</strong>包括新行符）。假定有个文件test.txt包含以下几行内容：</p>
<ul><tt>he is a rat</tt><tt>he is in a rut</tt><tt>the food is Rotten</tt><tt>I like root beer</tt></ul>
    我们可以使用grep命令来测试我们的正则表达式，grep命令使用正则表达式去尝试匹配指定文件的每一行，并将至少有一处匹配表达式的所有行显示出来。命令
    <ul><tt>grep r.t test.txt</tt></ul>
        在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>要想匹配行首的字符要使用抑扬字符（<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="#Regular%20Expressions%20Syntax"><u><span style="COLOR: #800080">正则表达式语法支持情况</span></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>:%s/ */ /g</tt></strong></td>
                    <td>把一个或者多个空格替换为一个空格。</td>
                </tr>
                <tr>
                    <td><strong><tt>:%s/ *$//</tt></strong></td>
                    <td>去掉行尾的所有空格。</td>
                </tr>
                <tr>
                    <td><strong><tt>:%s/^/ /</tt></strong></td>
                    <td>在每一行头上加入一个空格。</td>
                </tr>
                <tr>
                    <td><strong><tt>:%s/^[0-9][0-9]* //</tt></strong></td>
                    <td>去掉行首的所有数字字符。</td>
                </tr>
                <tr>
                    <td><strong><tt>:%s/b[aeio]g/bug/g</tt></strong></td>
                    <td>将所有的<em>bag</em>、<em>beg</em>、<em>big</em>和<em>bog</em>改为<em>bug</em>。 </td>
                </tr>
                <tr>
                    <td><strong><tt>:%s/t\([aou]\)g/h\1t/g</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>
        <p>&#160;</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><span style="FONT-FAMILY: Courier New">:%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g</span></tt></strong></ul>
            <p>现在让我们把它打散来加以分析。写出这个表达式的基本思路是找出foo()和它的括号中的三个参数的位置。第一个参数是用这个表达式来识别的：：<strong><tt><span style="FONT-FAMILY: Courier New">\([^,]*\)</span></tt></strong>，我们可以从里向外来分析它： </p>
            <p>&#160;</p>
            <table>
                <tbody>
                    <tr>
                        <td><strong><tt><span style="FONT-FAMILY: Courier New">[^,]</span></tt></strong></td>
                        <td>&nbsp;</td>
                        <td>除了逗号之外的任何字符</td>
                    </tr>
                    <tr>
                        <td><strong><tt><span style="FONT-FAMILY: Courier New">[^,]*</span></tt></strong></td>
                        <td></td>
                        <td>0或者多个非逗号字符</td>
                    </tr>
                    <tr>
                        <td><strong><tt><span style="FONT-FAMILY: Courier New">\([^,]*\)</span></tt></strong></td>
                        <td></td>
                        <td>将这些非逗号字符标记为<strong><tt>\1</tt></strong>，这样可以在之后的替换模式表达式中引用它</td>
                    </tr>
                    <tr vAlign=baseline>
                        <td><strong><tt><span style="FONT-FAMILY: Courier New">\([^,]*\),</span></tt></strong></td>
                        <td></td>
                        <td>我们必须找到0或者多个非逗号字符后面跟着一个逗号，并且非逗号字符那部分要标记出来以备后用。</td>
                    </tr>
                </tbody>
            </table>
            <p>现在正是指出一个使用正则表达式常见错误的最佳时机。为什么我们要使用<strong><tt><span style="FONT-FAMILY: Courier New">[^,]*</span></tt></strong>这样的一个表达式，而不是更加简单直接的写法，例如：<strong><tt><span style="FONT-FAMILY: Courier New">.*</span></tt></strong>，来匹配第一个参数呢？设想我们使用模式<strong><tt><span style="FONT-FAMILY: Courier New">.*</span></tt></strong>来匹配字符串"10,7,2"，它应该匹配"10,"还是"10,7,"？为了解决这个两义性（ambiguity），正则表达式规定一律按照最长的串来，在上面的例子中就是"10,7,"，显然这样就找出了两个参数而不是我们期望的一个。所以，我们要使用<strong><tt><span style="FONT-FAMILY: Courier New">[^,]*</span></tt></strong>来强制取出第一个逗号之前的部分。</p>
            <p>这个表达式我们已经分析到了：<strong><tt><span style="FONT-FAMILY: Courier New">foo(\([^,]*\)</span></tt></strong>，这一段可以简单的翻译为&#8220;当你找到<strong><tt>foo(</tt></strong>就把其后直到第一个逗号之前的部分标记为<strong><tt><span style="FONT-FAMILY: Courier New">\1</span></tt></strong>&#8221;。然后我们使用同样的办法标记第二个参数为<strong><tt><span style="FONT-FAMILY: Courier New">\2</span></tt></strong>。对第三个参数的标记方法也是一样，只是我们要搜索所有的字符直到右括号。我们并没有必要去搜索第三个参数，因为我们不需要调整它的位置，但是这样的模式能够保证我们只去替换那些有三个参数的foo()方法调用，在foo()是一个重载（overoading）方法时这种明确的模式往往是比较保险的。然后，在替换部分，我们找到foo()的对应实例，然后利用标记好的部分进行替换，是的第一和第二个参数交换位置。</p>
            <h3>例2</h3>
            假设有一个CSV（comma separated value）文件，里面有一些我们需要的信息，但是格式却有问题，目前数据的列顺序是：姓名，公司名，州名缩写，邮政编码，现在我们希望讲这些数据重新组织，以便在我们的某个软件中使用，需要的格式为：姓名，州名缩写-邮政编码，公司名。也就是说，我们要调整列顺序，还要合并两个列来构成一个新列。另外，我们的软件不能接受逗号前后面有任何空格（包括空格和制表符）所以我们还必须要去掉逗号前后的所有空格。
            <p>这里有几行我们现在的数据：</p>
            <ul><tt>Bill Jones, HI-TEK Corporation , CA, 95011</tt><tt><span style="FONT-FAMILY: Courier New">Sharon Lee Smith, Design Works Incorporated, CA, 95012</span></tt><tt><span style="FONT-FAMILY: Courier New">B. Amos , Hill Street Cafe, CA, 95013</span></tt><tt><span style="FONT-FAMILY: Courier New">Alexander Weatherworth, The Crafts Store, CA, 95014</span></tt><tt><span style="FONT-FAMILY: Courier New">...</span></tt></ul>
                我们希望把它变成这个样子：
                <ul><tt>Bill Jones,CA 95011,HI-TEK Corporation</tt><tt><span style="FONT-FAMILY: Courier New">Sharon Lee Smith,CA 95012,Design Works Incorporated</span></tt><tt><span style="FONT-FAMILY: Courier New">B. Amos,CA 95013,Hill Street Cafe</span></tt><tt><span style="FONT-FAMILY: Courier New">Alexander Weatherworth,CA 95014,The Crafts Store</span></tt><tt><span style="FONT-FAMILY: Courier New">...</span></tt></ul>
                    我们将用两个正则表达式来解决这个问题。第一个移动列和合并列，第二个用来去掉空格。
                    <p>下面就是第一个替换命令：</p>
                    <ul><strong><tt><span style="FONT-FAMILY: Courier New">:%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/</span></tt></strong></ul>
                        这里的方法跟例1基本一样，第一个列（姓名）用这个表达式来匹配：<strong><tt><span style="FONT-FAMILY: Courier New">\([^,]*\)</span></tt></strong>，即第一个逗号之前的所有字符，而姓名内容被用<strong><tt><span style="FONT-FAMILY: Courier New">\1</span></tt></strong>标记下来。公司名和州名缩写字段用同样的方法标记为<strong><tt><span style="FONT-FAMILY: Courier New">\2</span></tt></strong>和<strong><tt><span style="FONT-FAMILY: Courier New">\3</span></tt></strong>，而最后一个字段用<strong><tt><span style="FONT-FAMILY: Courier New">\(.*\)</span></tt></strong>来匹配（"匹配所有字符直到行末"）。替换部分则引用上面标记的那些内容来进行构造。
                        <p>下面这个替换命令则用来去除空格：</p>
                        <ul><strong><tt><span style="FONT-FAMILY: Courier New">:%s/[ \t]*,[ \t]*/,/g</span></tt></strong></ul>
                            我们还是分解来看：<strong><tt><span style="FONT-FAMILY: Courier New">[ \t]</span></tt></strong>匹配空格/制表符，<strong><tt><span style="FONT-FAMILY: Courier New">[ \t]*</span></tt></strong> 匹配0或多个空格/制表符，<strong><tt>[ \t]*</tt></strong>,匹配0或多个空格/制表符后面再加一个逗号，最后，<strong><tt><span style="FONT-FAMILY: Courier New">[ \t]*,[ \t]*</span></tt></strong>匹配0或多个空格/制表符接着一个逗号再接着0或多个空格/制表符。在替换部分，我们简单的我们找到的所有东西替换成一个逗号。这里我们使用了结尾的可选的<strong><tt>g</tt></strong>参数，这表示在每行中对所有匹配的串执行替换（而不是缺省的只替换第一个匹配串）。
                            <h3>例3</h3>
                            假设有一个多字符的片断重复出现，例如：
                            <blockquote><tt>Billy tried really hard</tt><tt>Sally tried really really hard</tt><tt>Timmy tried really really really hard</tt><tt>Johnny tried really really really really hard</tt></blockquote>而你想把"really"、"really really"，以及任意数量连续出现的"really"字符串换成一个简单的"very"（simple is good!），那么以下命令：
                            <blockquote><strong><tt>:%s/\(really \)\(really \)*/very /</tt></strong></blockquote>就会把上述的文本变成：
                            <blockquote><tt>Billy tried very hard</tt><tt>Sally tried very hard</tt><tt>Timmy tried very hard</tt><tt>Johnny tried very hard</tt></blockquote>表达式<strong><tt>\(really \)*</tt></strong>匹配0或多个连续的"really "（注意结尾有个空格），而<strong><tt>\(really \)\(really \)*</tt></strong> 匹配1个或多个连续的"really "实例。
                            <h2><a name=HardExamples></a>困难的例子（不可思议的象形文字）</h2>
                            <em>Coming soon</em>.
                            <hr>
                            <br>
                            <h1><a name=Regular_Expressions_In_Various_Tools></a>不同工具中的正则表达式</h1>
                            OK，你已经准备使用RE（regular expressions，正则表达式），但是你并准备使用vi。所以，在这里我们给出一些在其他工具中使用RE的例子。另外，我还会总结一下你在不同程序之间使用RE可能发现的区别。
                            <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>
                            <h2>awk</h2>
                            awk是一种编程语言，可以用来对文本数据进行复杂的分析和处理。可以在手册中得到关于awk的详细信息。这个古怪的名字是它作者们的姓的缩写（Aho，Weinberger和Kernighan）。
                            <p>在Aho，Weinberger和Kernighan的书<u>The AWK Programming Language</u>中有很多很好的awk的例子，请不要让下面这些微不足道的脚本例子限制你对awk强大能力的理解。我们同样假定我们针对price.txt文件进行处理，跟sed一样，awk也只是把结果显示在终端上。 </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><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 ~ /JohnFred/ {print $0}' price.txt</tt></strong></td>
                                        <td></td>
                                        <td>如果第二个字段包含'John'或者'Fred'则打印整行</td>
                                    </tr>
                                </tbody>
                            </table>
                            <h2>grep</h2>
                            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>下面的例子中我们假定在文件phone.txt中包含以下的文本，——其格式是姓加一个逗号，然后是名，然后是一个制表符，然后是电话号码：</p>
                            <ul>
                                <p><tt>Francis, John 5-3871</tt><tt>Wong, Fred 4-4123</tt><tt>Jones, Thomas 1-4122</tt><tt>Salazar, Richard 5-2522</tt></p>
                            </ul>
                            <p>&#160;</p>
                            <table>
                                <tbody>
                                    <tr>
                                        <td><strong><em>grep命令</em></strong></td>
                                        <td><strong><em></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><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>
                            egrep是grep的一个扩展版本，它在它的正则表达式中支持更多的元字符。下面的例子中我们假定在文件phone.txt中包含以下的文本，——其格式是姓加一个逗号，然后是名，然后是一个制表符，然后是电话号码：
                            <ul><tt>Francis, John 5-3871</tt><tt>Wong, Fred 4-4123</tt><tt>Jones, Thomas 1-4122</tt><tt>Salazar, Richard 5-2522</tt></ul>
                                <p>&#160;</p>
                                <table>
                                    <tbody>
                                        <tr>
                                            <td><strong><em>egrep command</em></strong></td>
                                            <td><strong><em></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 '(JohnFred)' phone.txt</tt></strong></td>
                                            <td></td>
                                            <td>打印所有包含名字<em>John</em>或者<em>Fred</em>的行</td>
                                        </tr>
                                        <tr vAlign=baseline>
                                            <td><strong><tt>egrep 'John22$^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>
                                <table cellSpacing=0 border=1>
                                    <tbody>
                                        <tr>
                                            <td><strong>命令或环境</strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">.</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">[ ]</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">^</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">$</span></tt></strong></td>
                                            <td><strong><tt><span style="FONT-FAMILY: Courier New">\( \)</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">\{ \}</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">?</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">+</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">|</span></tt></strong></td>
                                            <td width=30><strong><tt><span style="FONT-FAMILY: Courier New">( )</span></tt></strong></td>
                                        </tr>
                                        <tr>
                                            <td>vi</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>Visual C++</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>awk</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                        </tr>
                                        <tr>
                                            <td>sed</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>Tcl</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                        </tr>
                                        <tr>
                                            <td>ex</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>grep</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>egrep</td>
                                            <td>X </td>
                                            <td>X</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                        </tr>
                                        <tr>
                                            <td>fgrep</td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>X </td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                            <td>&nbsp;</td>
                                        </tr>
                                        <tr>
                                            <td>perl</td>
                                            <td>X</td>
                                            <td>X</td>
                                            <td>X</td>
                                            <td>X</td>
                                            <td>X</td>
                                            <td>&nbsp;</td>
                                            <td>X</td>
                                            <td>X</td>
                                            <td>X</td>
                                            <td>X</td>
                                        </tr>
                                    </tbody>
                                </table>
                                <hr>
                                <br>
                                <h1><a name=ViSubstitutionCommandSyntax></a>vi替换命令简介</h1>
                                Vi的替换命令：
                                <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>
                                    其中
                                    <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>
                                        网上有很多vi的在线手册，你可以访问他们以获得更加完整的信息。
                                        <hr width="100%">
<img src ="http://www.cppblog.com/andxie99/aggbug/7979.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:47 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7979.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC++中进程与多进程管理的方法</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7976.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:44:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7976.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7976.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7976.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7976.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7976.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;　　进程 　　进程是当前操作系统下一个被加载到内存的、正在运行的应用程序的实例。每一个进程都是由内核对象和地址空间所组成的，内核对象可以让系统在其内存放有关进程的统计信息并使系统能够以此来管理进程，而地址空间则包括了所有程序模块的代码和数据以及线程堆栈、堆分配空间等动态分配的空间。进程仅仅是一个存在，是不能独自完成任何操作的，必须拥有至少一个在其环境下运行的线程，并由其负责执行...&nbsp;&nbsp;<a href='http://www.cppblog.com/andxie99/archive/2006/05/31/7976.html'>阅读全文</a><img src ="http://www.cppblog.com/andxie99/aggbug/7976.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:44 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7976.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>整理的一些ISAPI编程基础</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7975.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7975.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7975.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7975.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7975.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7975.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &#160;一、 ISAPI 简介 通用网关接口 CommonGatewayInterface(CGI) 很早就作为交互式的 Web 应用程序的一个标准广泛应用在 Internet 之中。 CGI 脚本允许人们用多种编程语言 ( 如 Basic 、 C 、 Perl 、 Shell 等等 ) 来编写简单的应用程序。这些脚本运行在 Web 服务器上， 而在客户的 Web 浏览器上输出运行结果...&nbsp;&nbsp;<a href='http://www.cppblog.com/andxie99/archive/2006/05/31/7975.html'>阅读全文</a><img src ="http://www.cppblog.com/andxie99/aggbug/7975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:43 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出理解索引结构（转）</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7974.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:40:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7974.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7974.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7974.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7974.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7974.html</trackback:ping><description><![CDATA[<div style="LINE-HEIGHT: 23px">&nbsp; &nbsp; &nbsp; &nbsp; （一）深入浅出理解索引结构<br>&nbsp; &nbsp; &nbsp; &nbsp;实际上，您可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索引：聚集索引（clustered index，也称聚类索引、簇集索引）和非聚集索引（nonclustered index，也称非聚类索引、非簇集索引）。下面，我们举例来说明一下聚集索引和非聚集索引的区别：<br>&nbsp; &nbsp; &nbsp; &nbsp;其实，我们的汉语字典的正文本身就是一个聚集索引。比如，我们要查&#8220;安&#8221;字，就会很自然地翻开字典的前几页，因为&#8220;安&#8221;的拼音是&#8220;an&#8221;，而按照拼音排序汉字的字典是以英文字母&#8220;a&#8221;开头并以&#8220;z&#8221;结尾的，那么&#8220;安&#8221;字就自然地排在字典的前部。如果您翻完了所有以&#8220;a&#8221;开头的部分仍然找不到这个字，那么就说明您的字典中没有这个字；同样的，如果查&#8220;张&#8221;字，那您也会将您的字典翻到最后部分，因为&#8220;张&#8221;的拼音是&#8220;zhang&#8221;。也就是说，字典的正文部分本身就是一个目录，您不需要再去查其他目录来找到您需要找的内容。<br>&nbsp; &nbsp; &nbsp; &nbsp;我们把这种正文内容本身就是一种按照一定规则排列的目录称为&#8220;聚集索引&#8221;。<br>&nbsp; &nbsp; &nbsp; &nbsp;如果您认识某个字，您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字，不知道它的发音，这时候，您就不能按照刚才的方法找到您要查的字，而需要去根据&#8220;偏旁部首&#8221;查到您要找的字，然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合&#8220;部首目录&#8221;和&#8220;检字表&#8221;而查到的字的排序并不是真正的正文的排序方法，比如您查&#8220;张&#8221;字，我们可以看到在查部首之后的检字表中&#8220;张&#8221;的页码是672页，检字表中&#8220;张&#8221;的上面是&#8220;驰&#8221;字，但页码却是63页，&#8220;张&#8221;的下面是&#8220;弩&#8221;字，页面是390页。很显然，这些字并不是真正的分别位于&#8220;张&#8221;字的上下方，现在您看到的连续的&#8220;驰、张、弩&#8221;三字实际上就是他们在非聚集索引中的排序，是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字，但它需要两个过程，先找到目录中的结果，然后再翻到您所需要的页码。<br>&nbsp; &nbsp; &nbsp; &nbsp;我们把这种目录纯粹是目录，正文纯粹是正文的排序方式称为&#8220;非聚集索引&#8221;。<br>&nbsp; &nbsp; &nbsp; &nbsp;通过以上例子，我们可以理解到什么是&#8220;聚集索引&#8221;和&#8220;非聚集索引&#8221;。<br>&nbsp; &nbsp; &nbsp; &nbsp;进一步引申一下，我们可以很容易的理解：每个表只能有一个聚集索引，因为目录只能按照一种方法进行排序。<br>&nbsp; &nbsp; &nbsp; &nbsp;（二）何时使用聚集索引或非聚集索引<br>&nbsp; &nbsp; &nbsp; &nbsp;下面的表总结了何时使用聚集索引或非聚集索引（很重要）。
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>动作描述</td>
            <td>使用聚集索引</td>
            <td>使用非聚集索引</td>
        </tr>
        <tr>
            <td>列经常被分组排序</td>
            <td>应</td>
            <td>应</td>
        </tr>
        <tr>
            <td>返回某范围内的数据</td>
            <td>应</td>
            <td>不应</td>
        </tr>
        <tr>
            <td>一个或极少不同值</td>
            <td>不应</td>
            <td>不应</td>
        </tr>
        <tr>
            <td>小数目的不同值</td>
            <td>应</td>
            <td>不应</td>
        </tr>
        <tr>
            <td>大数目的不同值</td>
            <td>不应</td>
            <td>应</td>
        </tr>
        <tr>
            <td>频繁更新的列</td>
            <td>不应</td>
            <td>应</td>
        </tr>
        <tr>
            <td>外键列</td>
            <td>应</td>
            <td>应</td>
        </tr>
        <tr>
            <td>主键列</td>
            <td>应</td>
            <td>应</td>
        </tr>
        <tr>
            <td>频繁修改索引列</td>
            <td>不应</td>
            <td>应</td>
        </tr>
    </tbody>
</table>
&nbsp; &nbsp; &nbsp; &nbsp; 事实上，我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如：返回某范围内的数据一项。比如您的某个表有一个时间列，恰好您把聚合索引建立在了该列，这时您查询2004年1月1日至2004年10月1日之间的全部数据时，这个速度就将是很快的，因为您的这本字典正文是按日期进行排序的，聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可；而不像非聚集索引，必须先查到目录中查到每一项数据对应的页码，然后再根据页码查到具体内容。<br>&nbsp; &nbsp; &nbsp; &nbsp;（三）结合实际，谈索引使用的误区<br>&nbsp; &nbsp; &nbsp; &nbsp;理论的目的是应用。虽然我们刚才列出了何时应使用聚集索引或非聚集索引，但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析。下面我们将根据在实践中遇到的实际问题来谈一下索引使用的误区，以便于大家掌握索引建立的方法。<br>&nbsp; &nbsp; &nbsp; &nbsp;1、主键就是聚集索引<br>&nbsp; &nbsp; &nbsp; &nbsp;这种想法笔者认为是极端错误的，是对聚集索引的一种浪费。虽然SQL SERVER默认是在主键上建立聚集索引的。<br>&nbsp; &nbsp; &nbsp; &nbsp;通常，我们会在每个表中都建立一个ID列，以区分每条数据，并且这个ID列是自动增大的，步长一般为1。我们的这个办公自动化的实例中的列Gid就是如此。此时，如果我们将这个列设为主键，SQL SERVER会将此列默认为聚集索引。这样做有好处，就是可以让您的数据在数据库中按照ID进行物理排序，但笔者认为这样做意义不大。<br>&nbsp; &nbsp; &nbsp; &nbsp;显而易见，聚集索引的优势是很明显的，而每个表中只能有一个聚集索引的规则，这使得聚集索引变得更加珍贵。<br>&nbsp; &nbsp; &nbsp; &nbsp;从我们前面谈到的聚集索引的定义我们可以看出，使用聚集索引的最大好处就是能够根据查询要求，迅速缩小查询范围，避免全表扫描。在实际应用中，因为ID号是自动生成的，我们并不知道每条记录的ID号，所以我们很难在实践中用ID号来进行查询。这就使让ID号这个主键作为聚集索引成为一种资源浪费。其次，让每个ID号都不同的字段作为聚集索引也不符合&#8220;大数目的不同值情况下不应建立聚合索引&#8221;规则；当然，这种情况只是针对用户经常修改记录内容，特别是索引项的时候会负作用，但对于查询速度并没有影响。<br>&nbsp; &nbsp; &nbsp; &nbsp;在办公自动化系统中，无论是系统首页显示的需要用户签收的文件、会议还是用户进行文件查询等任何情况下进行数据查询都离不开字段的是&#8220;日期&#8221;还有用户本身的&#8220;用户名&#8221;。<br>&nbsp; &nbsp; &nbsp; &nbsp;通常，办公自动化的首页会显示每个用户尚未签收的文件或会议。虽然我们的where语句可以仅仅限制当前用户尚未签收的情况，但如果您的系统已建立了很长时间，并且数据量很大，那么，每次每个用户打开首页的时候都进行一次全表扫描，这样做意义是不大的，绝大多数的用户1个月前的文件都已经浏览过了，这样做只能徒增数据库的开销而已。事实上，我们完全可以让用户打开系统首页时，数据库仅仅查询这个用户近3个月来未阅览的文件，通过&#8220;日期&#8221;这个字段来限制表扫描，提高查询速度。如果您的办公自动化系统已经建立的2年，那么您的首页显示速度理论上将是原来速度8倍，甚至更快。<br>&nbsp; &nbsp; &nbsp; &nbsp;在这里之所以提到&#8220;理论上&#8221;三字，是因为如果您的聚集索引还是盲目地建在ID这个主键上时，您的查询速度是没有这么高的，即使您在&#8220;日期&#8221;这个字段上建立的索引（非聚合索引）。下面我们就来看一下在1000万条数据量的情况下各种查询的速度表现（3个月内的数据为25万条）：<br>&nbsp; &nbsp; &nbsp; &nbsp;（1）仅在主键上建立聚集索引，并且不划分时间段：<br>&nbsp; &nbsp; &nbsp; &nbsp;Select gid,fariqi,neibuyonghu,title from tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：128470毫秒（即：128秒）<br>&nbsp; &nbsp; &nbsp; &nbsp;（2）在主键上建立聚集索引，在fariq上建立非聚集索引：<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,title from Tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;where fariqi&gt; dateadd(day,-90,getdate())<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：53763毫秒（54秒）<br>&nbsp; &nbsp; &nbsp; &nbsp;（3）将聚合索引建立在日期列（fariqi）上：<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,title from Tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;where fariqi&gt; dateadd(day,-90,getdate())<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：2423毫秒（2秒）<br>&nbsp; &nbsp; &nbsp; &nbsp;虽然每条语句提取出来的都是25万条数据，各种情况的差异却是巨大的，特别是将聚集索引建立在日期列时的差异。事实上，如果您的数据库真的有1000万容量的话，把主键建立在ID列上，就像以上的第1、2种情况，在网页上的表现就是超时，根本就无法显示。这也是我摒弃ID列作为聚集索引的一个最重要的因素。<br>&nbsp; &nbsp; &nbsp; &nbsp;得出以上速度的方法是：在各个select语句前加：declare @d datetime<br>&nbsp; &nbsp; &nbsp; &nbsp;set @d=getdate()<br>&nbsp; &nbsp; &nbsp; &nbsp;并在select语句后加：<br>&nbsp; &nbsp; &nbsp; &nbsp;select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())<br>&nbsp; &nbsp; &nbsp; &nbsp;2、只要建立索引就能显著提高查询速度<br>&nbsp; &nbsp; &nbsp; &nbsp;事实上，我们可以发现上面的例子中，第2、3条语句完全相同，且建立索引的字段也相同；不同的仅是前者在fariqi字段上建立的是非聚合索引，后者在此字段上建立的是聚合索引，但查询速度却有着天壤之别。所以，并非是在任何字段上简单地建立索引就能提高查询速度。<br>&nbsp; &nbsp; &nbsp; &nbsp;从建表的语句中，我们可以看到这个有着1000万数据的表中fariqi字段有5003个不同记录。在此字段上建立聚合索引是再合适不过了。在现实中，我们每天都会发几个文件，这几个文件的发文日期就相同，这完全符合建立聚集索引要求的：&#8220;既不能绝大多数都相同，又不能只有极少数相同&#8221;的规则。由此看来，我们建立&#8220;适当&#8221;的聚合索引对于我们提高查询速度是非常重要的。<br>&nbsp; &nbsp; &nbsp; &nbsp;3、把所有需要提高查询速度的字段都加进聚集索引，以提高查询速度<br>&nbsp; &nbsp; &nbsp; &nbsp;上面已经谈到：在进行数据查询时都离不开字段的是&#8220;日期&#8221;还有用户本身的&#8220;用户名&#8221;。既然这两个字段都是如此的重要，我们可以把他们合并起来，建立一个复合索引（compound index）。<br>&nbsp; &nbsp; &nbsp; &nbsp;很多人认为只要把任何字段加进聚集索引，就能提高查询速度，也有人感到迷惑：如果把复合的聚集索引字段分开查询，那么查询速度会减慢吗？带着这个问题，我们来看一下以下的查询速度（结果集都是25万条数据）：（日期列fariqi首先排在复合聚集索引的起始列，用户名neibuyonghu排在后列）<br>&nbsp; &nbsp; &nbsp; &nbsp;（1）select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi&gt;'2004-5-5' <br>&nbsp; &nbsp; &nbsp; &nbsp;查询速度：2513毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;（2）select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi&gt;'2004-5-5' and neibuyonghu='办公室'<br>&nbsp; &nbsp; &nbsp; &nbsp;查询速度：2516毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;（3）select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='办公室'<br>&nbsp; &nbsp; &nbsp; &nbsp;查询速度：60280毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;从以上试验中，我们可以看到如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的，甚至比用上全部的复合索引列还要略快（在查询结果集数目一样的情况下）；而如果仅用复合聚集索引的非起始列作为查询条件的话，这个索引是不起任何作用的。当然，语句1、2的查询速度一样是因为查询的条目数一样，如果复合索引的所有列都用上，而且查询结果少的话，这样就会形成&#8220;索引覆盖&#8221;，因而性能可以达到最优。同时，请记住：无论您是否经常使用聚合索引的其他列，但其前导列一定要是使用最频繁的列。<br>&nbsp; &nbsp; &nbsp; &nbsp;（四）其他书上没有的索引使用经验总结<br>&nbsp; &nbsp; &nbsp; &nbsp;1、用聚合索引比用不是聚合索引的主键速度快<br>&nbsp; &nbsp; &nbsp; &nbsp;下面是实例语句：（都是提取25万条数据）<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'<br>&nbsp; &nbsp; &nbsp; &nbsp;使用时间：3326毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid&lt;=250000<br>&nbsp; &nbsp; &nbsp; &nbsp;使用时间：4470毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;这里，用聚合索引比用不是聚合索引的主键速度快了近1/4。<br>&nbsp; &nbsp; &nbsp; &nbsp;2、用聚合索引比用一般的主键作order by时速度快，特别是在小数据量情况下<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：12936<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：18843<br>&nbsp; &nbsp; &nbsp; &nbsp;这里，用聚合索引比用一般的主键作order by时，速度快了3/10。事实上，如果数据量很小的话，用聚集索引作为排序列要比使用非聚集索引速度快得明显的多；而数据量如果很大的话，如10万以上，则二者的速度差别不明显。<br>&nbsp; &nbsp; &nbsp; &nbsp;3、使用聚合索引内的时间段，搜索时间会按数据占整个数据表的百分比成比例减少，而无论聚合索引使用了多少个<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&gt;'2004-1-1'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：6343毫秒（提取100万条） <br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&gt;'2004-6-6'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：3170毫秒（提取50万条）<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：3326毫秒（和上句的结果一模一样。如果采集的数量一样，那么用大于号和等于号是一样的）<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&gt;'2004-1-1' and fariqi&lt;'2004-6-6'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：3280毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;4 、日期列不会因为有分秒的输入而减慢查询速度<br>&nbsp; &nbsp; &nbsp; &nbsp;下面的例子中，共有100万条数据，2004年1月1日以后的数据有50万条，但只有两个不同的日期，日期精确到日；之前有数据50万条，有5000个不同的日期，日期精确到秒。<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&gt;'2004-1-1' order by fariqi<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：6390毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi&lt;'2004-1-1' order by fariqi<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：6453毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;（五）其他注意事项<br>&nbsp; &nbsp; &nbsp; &nbsp;&#8220;水可载舟，亦可覆舟&#8221;，索引也一样。索引有助于提高检索性能，但过多或不当的索引也会导致系统低效。因为用户在表中每加进一个索引，数据库就要做更多的工作。过多的索引甚至会导致索引碎片。<br>&nbsp; &nbsp; &nbsp; &nbsp;所以说，我们要建立一个&#8220;适当&#8221;的索引体系，特别是对聚合索引的创建，更应精益求精，以使您的数据库能得到高性能的发挥。<br>&nbsp; &nbsp; &nbsp; &nbsp;当然，在实践中，作为一个尽职的数据库管理员，您还要多测试一些方案，找出哪种方案效率最高、最为有效。<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;二、改善SQL语句<br>&nbsp; &nbsp; &nbsp; &nbsp;很多人不知道SQL语句在SQL SERVER中是如何执行的，他们担心自己所写的SQL语句会被SQL SERVER误解。比如：<br>&nbsp; &nbsp; &nbsp; &nbsp;select * from table1 where name='zhangsan' and tID &gt; 10000<br>&nbsp; &nbsp; &nbsp; &nbsp;和执行:<br>&nbsp; &nbsp; &nbsp; &nbsp;select * from table1 where tID &gt; 10000 and name='zhangsan'<br>&nbsp; &nbsp; &nbsp; &nbsp;一些人不知道以上两条语句的执行效率是否一样，因为如果简单的从语句先后上看，这两个语句的确是不一样，如果tID是一个聚合索引，那么后一句仅仅从表的10000条以后的记录中查找就行了；而前一句则要先从全表中查找看有几个name='zhangsan'的，而后再根据限制条件条件tID&gt;10000来提出查询结果。<br>&nbsp; &nbsp; &nbsp; &nbsp;事实上，这样的担心是不必要的。SQL SERVER中有一个&#8220;查询分析优化器&#8221;，它可以计算出where子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间，也就是说，它能实现自动优化。<br>&nbsp; &nbsp; &nbsp; &nbsp;虽然查询优化器可以根据where子句自动的进行查询优化，但大家仍然有必要了解一下&#8220;查询优化器&#8221;的工作原理，如非这样，有时查询优化器就会不按照您的本意进行快速查询。<br>&nbsp; &nbsp; &nbsp; &nbsp;在查询分析阶段，查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数（SARG），那么就称之为可优化的，并且可以利用索引快速获得所需数据。<br>&nbsp; &nbsp; &nbsp; &nbsp;SARG的定义：用于限制搜索的一个操作，因为它通常是指一个特定的匹配，一个值得范围内的匹配或者两个以上条件的AND连接。形式如下：<br>&nbsp; &nbsp; &nbsp; &nbsp;列名 操作符 &lt;常数 或 变量&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp;或<br>&nbsp; &nbsp; &nbsp; &nbsp;&lt;常数 或 变量&gt; 操作符列名<br>&nbsp; &nbsp; &nbsp; &nbsp;列名可以出现在操作符的一边，而常数或变量出现在操作符的另一边。如：<br>&nbsp; &nbsp; &nbsp; &nbsp;Name=&#8217;张三&#8217;<br>&nbsp; &nbsp; &nbsp; &nbsp;价格&gt;5000<br>&nbsp; &nbsp; &nbsp; &nbsp;5000&lt;价格<br>&nbsp; &nbsp; &nbsp; &nbsp;Name=&#8217;张三&#8217; and 价格&gt;5000<br>&nbsp; &nbsp; &nbsp; &nbsp;如果一个表达式不能满足SARG的形式，那它就无法限制搜索的范围了，也就是SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。所以一个索引对于不满足SARG形式的表达式来说是无用的。<br>&nbsp; &nbsp; &nbsp; &nbsp;介绍完SARG后，我们来总结一下使用SARG以及在实践中遇到的和某些资料上结论不同的经验：<br>&nbsp; &nbsp; &nbsp; &nbsp;1、Like语句是否属于SARG取决于所使用的通配符的类型<br>&nbsp; &nbsp; &nbsp; &nbsp;如：name like &#8216;张%&#8217; ，这就属于SARG<br>&nbsp; &nbsp; &nbsp; &nbsp;而：name like &#8216;%张&#8217; ,就不属于SARG。<br>&nbsp; &nbsp; &nbsp; &nbsp;原因是通配符%在字符串的开通使得索引无法使用。<br>&nbsp; &nbsp; &nbsp; &nbsp;2、or 会引起全表扫描<br>&nbsp; &nbsp; &nbsp; &nbsp;Name=&#8217;张三&#8217; and 价格&gt;5000 符号SARG，而：Name=&#8217;张三&#8217; or 价格&gt;5000 则不符合SARG。使用or会引起全表扫描。<br>&nbsp; &nbsp; &nbsp; &nbsp;3、非操作符、函数引起的不满足SARG形式的语句<br>&nbsp; &nbsp; &nbsp; &nbsp;不满足SARG形式的语句最典型的情况就是包括非操作符的语句，如：NOT、!=、&lt;&gt;、!&lt;、!&gt;、NOT EXISTS、NOT IN、NOT LIKE等，另外还有函数。下面就是几个不满足SARG形式的例子：<br>&nbsp; &nbsp; &nbsp; &nbsp;ABS(价格)&lt;5000<br>&nbsp; &nbsp; &nbsp; &nbsp;Name like &#8216;%三&#8217;<br>&nbsp; &nbsp; &nbsp; &nbsp;有些表达式，如：<br>&nbsp; &nbsp; &nbsp; &nbsp;WHERE 价格*2&gt;5000<br>&nbsp; &nbsp; &nbsp; &nbsp;SQL SERVER也会认为是SARG，SQL SERVER会将此式转化为：<br>&nbsp; &nbsp; &nbsp; &nbsp;WHERE 价格&gt;2500/2<br>&nbsp; &nbsp; &nbsp; &nbsp;但我们不推荐这样使用，因为有时SQL SERVER不能保证这种转化与原始表达式是完全等价的。<br>&nbsp; &nbsp; &nbsp; &nbsp;4、IN 的作用相当与OR<br>&nbsp; &nbsp; &nbsp; &nbsp;语句：<br>&nbsp; &nbsp; &nbsp; &nbsp;Select * from table1 where tid in (2,3)<br>&nbsp; &nbsp; &nbsp; &nbsp;和<br>&nbsp; &nbsp; &nbsp; &nbsp;Select * from table1 where tid=2 or tid=3<br>&nbsp; &nbsp; &nbsp; &nbsp;是一样的，都会引起全表扫描，如果tid上有索引，其索引也会失效。<br>&nbsp; &nbsp; &nbsp; &nbsp;5、尽量少用NOT<br>&nbsp; &nbsp; &nbsp; &nbsp;6、exists 和 in 的执行效率是一样的<br>&nbsp; &nbsp; &nbsp; &nbsp;很多资料上都显示说，exists要比in的执行效率要高，同时应尽可能的用not exists来代替not in。但事实上，我试验了一下，发现二者无论是前面带不带not，二者之间的执行效率都是一样的。因为涉及子查询，我们试验这次用SQL SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开。<br>&nbsp; &nbsp; &nbsp; &nbsp;（1）select title,price from titles where title_id in (select title_id from sales where qty&gt;30)<br>&nbsp; &nbsp; &nbsp; &nbsp;该句的执行结果为：<br>&nbsp; &nbsp; &nbsp; &nbsp;表 'sales'。扫描计数 18，逻辑读 56 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;表 'titles'。扫描计数 1，逻辑读 2 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;（2）select title,price from titles where exists (select * from sales where sales.title_id=titles.title_id and qty&gt;30)<br>&nbsp; &nbsp; &nbsp; &nbsp;第二句的执行结果为：<br>&nbsp; &nbsp; &nbsp; &nbsp;表 'sales'。扫描计数 18，逻辑读 56 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;表 'titles'。扫描计数 1，逻辑读 2 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;我们从此可以看到用exists和用in的执行效率是一样的。<br>&nbsp; &nbsp; &nbsp; &nbsp;7、用函数charindex()和前面加通配符%的LIKE执行效率一样<br>&nbsp; &nbsp; &nbsp; &nbsp;前面，我们谈到，如果在LIKE前面加上通配符%，那么将会引起全表扫描，所以其执行效率是低下的。但有的资料介绍说，用函数charindex()来代替LIKE速度会有大的提升，经我试验，发现这种说明也是错误的：<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,title,fariqi,reader from tgongwen where charindex('刑侦支队',reader)&gt;0 and fariqi&gt;'2004-5-5'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：7秒，另外：扫描计数 4，逻辑读 7155 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,title,fariqi,reader from tgongwen where reader like '%' + '刑侦支队' + '%' and fariqi&gt;'2004-5-5'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：7秒，另外：扫描计数 4，逻辑读 7155 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;8、union并不绝对比or的执行效率高<br>&nbsp; &nbsp; &nbsp; &nbsp;我们前面已经谈到了在where子句中使用or会引起全表扫描，一般的，我所见过的资料都是推荐这里用union来代替or。事实证明，这种说法对于大部分都是适用的。<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or gid&gt;9990000<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：68秒。扫描计数 1，逻辑读 404008 次，物理读 283 次，预读 392163 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' <br>&nbsp; &nbsp; &nbsp; &nbsp;union<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid&gt;9990000<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：9秒。扫描计数 8，逻辑读 67489 次，物理读 216 次，预读 7499 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;看来，用union在通常情况下比用or的效率要高的多。<br>&nbsp; &nbsp; &nbsp; &nbsp;但经过试验，笔者发现如果or两边的查询列是一样的话，那么用union则反倒和用or的执行速度差很多，虽然这里union扫描的是索引，而or扫描的是全表。<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or fariqi='2004-2-5'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：6423毫秒。扫描计数 2，逻辑读 14726 次，物理读 1 次，预读 7176 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' <br>&nbsp; &nbsp; &nbsp; &nbsp;union<br>&nbsp; &nbsp; &nbsp; &nbsp;select gid,fariqi,neibuyonghu,reader,title from Tgongwen where&nbsp;&nbsp;fariqi='2004-2-5'<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：11640毫秒。扫描计数 8，逻辑读 14806 次，物理读 108 次，预读 1144 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;9、字段提取要按照&#8220;需多少、提多少&#8221;的原则，避免&#8220;select *&#8221;<br>&nbsp; &nbsp; &nbsp; &nbsp;我们来做一个试验：<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：4673毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,title from tgongwen order by gid desc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：1376毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi from tgongwen order by gid desc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：80毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;由此看来，我们每少提取一个字段，数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。<br>&nbsp; &nbsp; &nbsp; &nbsp;10、count(*)不比count(字段)慢<br>&nbsp; &nbsp; &nbsp; &nbsp;某些资料上说：用*会统计所有列，显然要比一个世界的列名效率低。这种说法其实是没有根据的。我们来看：<br>&nbsp; &nbsp; &nbsp; &nbsp;select count(*) from Tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：1500毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select count(gid) from Tgongwen <br>&nbsp; &nbsp; &nbsp; &nbsp;用时：1483毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select count(fariqi) from Tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：3140毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;select count(title) from Tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：52050毫秒<br>&nbsp; &nbsp; &nbsp; &nbsp;从以上可以看出，如果用count(*)和用count(主键)的速度是相当的，而count(*)却比其他任何除主键以外的字段汇总速度要快，而且字段越长，汇总的速度就越慢。我想，如果用count(*)， SQL SERVER可能会自动查找最小字段来汇总的。当然，如果您直接写count(主键)将会来的更直接些。<br>&nbsp; &nbsp; &nbsp; &nbsp;11、order by按聚集索引列排序效率最高<br>&nbsp; &nbsp; &nbsp; &nbsp;我们来看：（gid是主键，fariqi是聚合索引列）<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,reader,title from tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：196 毫秒。 扫描计数 1，逻辑读 289 次，物理读 1 次，预读 1527 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：4720毫秒。 扫描计数 1，逻辑读 41956 次，物理读 0 次，预读 1287 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：4736毫秒。 扫描计数 1，逻辑读 55350 次，物理读 10 次，预读 775 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：173毫秒。 扫描计数 1，逻辑读 290 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc<br>&nbsp; &nbsp; &nbsp; &nbsp;用时：156毫秒。 扫描计数 1，逻辑读 289 次，物理读 0 次，预读 0 次。<br>&nbsp; &nbsp; &nbsp; &nbsp;从以上我们可以看出，不排序的速度以及逻辑读次数都是和&#8220;order by 聚集索引列&#8221; 的速度是相当的，但这些都比&#8220;order by 非聚集索引列&#8221;的查询速度是快得多的。<br>&nbsp; &nbsp; &nbsp; &nbsp;同时，按照某个字段进行排序的时候，无论是正序还是倒序，速度是基本相当的。<br>&nbsp; &nbsp; &nbsp; &nbsp;12、高效的TOP<br>&nbsp; &nbsp; &nbsp; &nbsp;事实上，在查询和提取超大容量的数据集时，影响数据库响应时间的最大因素不是数据查找，而是物理的I/0操作。如：<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10 * from (<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 10000 gid,fariqi,title from tgongwen<br>&nbsp; &nbsp; &nbsp; &nbsp;where neibuyonghu='办公室'<br>&nbsp; &nbsp; &nbsp; &nbsp;order by gid desc) as a<br>&nbsp; &nbsp; &nbsp; &nbsp;order by gid asc<br>&nbsp; &nbsp; &nbsp; &nbsp;这条语句，从理论上讲，整条语句的执行时间应该比子句的执行时间长，但事实相反。因为，子句执行后返回的是10000条记录，而整条语句仅返回10条语句，所以影响数据库响应时间最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效方法之一就是使用TOP关键词了。TOP关键词是SQL SERVER中经过系统优化过的一个用来提取前几条或前几个百分比数据的词。经笔者在实践中的应用，发现TOP确实很好用，效率也很高。但这个词在另外一个大型数据库ORACLE中却没有，这不能说不是一个遗憾，虽然在ORACLE中可以用其他方法（如：rownumber）来解决。在以后的关于&#8220;实现千万级数据的分页显示存储过程&#8221;的讨论中，我们就将用到TOP这个关键词。<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;到此为止，我们上面讨论了如何实现从大容量的数据库中快速地查询出您所需要的数据方法。当然，我们介绍的这些方法都是&#8220;软&#8221;方法，在实践中，我们还要考虑各种&#8220;硬&#8221;因素，如：网络性能、服务器的性能、操作系统的性能，甚至网卡、交换机等。<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;三、实现小数据量和海量数据的通用分页显示存储过程<br>&nbsp; &nbsp; &nbsp; &nbsp;建立一个web 应用，分页浏览功能必不可少。这个问题是数据库处理中十分常见的问题。经典的数据分页方法是:ADO 纪录集分页法，也就是利用ADO自带的分页功能（利用游标）来实现分页。但这种分页方法仅适用于较小数据量的情形，因为游标本身有缺点：游标是存放在内存中，很费内存。游标一建立，就将相关的记录锁住，直到取消游标。游标提供了对特定集合中逐行扫描的手段，一般使用游标来逐行遍历数据，根据取出数据条件的不同进行不同的操作。而对于多表和大表中定义的游标（大的数据集合）循环很容易使程序进入一个漫长的等待甚至死机。<br>&nbsp; &nbsp; &nbsp; &nbsp;更重要的是，对于非常大的数据模型而言，分页检索时，如果按照传统的每次都加载整个数据源的方法是非常浪费资源的。现在流行的分页方法一般是检索页面大小的块区的数据，而非检索所有的数据，然后单步执行当前行。<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最早较好地实现这种根据页面大小和页码来提取数据的方法大概就是&#8220;俄罗斯存储过程&#8221;。这个存储过程用了游标，由于游标的局限性，所以这个方法并没有得到大家的普遍认可。<br>&nbsp; &nbsp; &nbsp; &nbsp;后来，网上有人改造了此存储过程，下面的存储过程就是结合我们的办公自动化实例写的分页存储过程：<br>&nbsp; &nbsp; &nbsp; &nbsp;CREATE procedure pagination1<br>&nbsp; &nbsp; &nbsp; &nbsp;(@pagesize int,&nbsp;&nbsp;--页面大小，如每页存储20条记录<br>&nbsp; &nbsp; &nbsp; &nbsp;@pageindex int&nbsp;&nbsp; --当前页码<br>&nbsp; &nbsp; &nbsp; &nbsp;)<br>&nbsp; &nbsp; &nbsp; &nbsp;as<br>&nbsp; &nbsp; &nbsp; &nbsp;set nocount on<br>&nbsp; &nbsp; &nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;declare @indextable table(id int identity(1,1),nid int)&nbsp;&nbsp;--定义表变量<br>&nbsp; &nbsp; &nbsp; &nbsp;declare @PageLowerBound int&nbsp;&nbsp;--定义此页的底码<br>&nbsp; &nbsp; &nbsp; &nbsp;declare @PageUpperBound int&nbsp;&nbsp;--定义此页的顶码<br>&nbsp; &nbsp; &nbsp; &nbsp;set @PageLowerBound=(@pageindex-1)*@pagesize<br>&nbsp; &nbsp; &nbsp; &nbsp;set @PageUpperBound=@PageLowerBound+@pagesize<br>&nbsp; &nbsp; &nbsp; &nbsp;set rowcount @PageUpperBound<br>&nbsp; &nbsp; &nbsp; &nbsp;insert into @indextable(nid) select gid from TGongwen where fariqi &gt;dateadd(day,-365,getdate()) order by fariqi desc<br>&nbsp; &nbsp; &nbsp; &nbsp;select O.gid,O.mid,O.title,O.fadanwei,O.fariqi from TGongwen O,@indextable t where O.gid=t.nid<br>&nbsp; &nbsp; &nbsp; &nbsp;and t.id&gt;@PageLowerBound and t.id&lt;=@PageUpperBound order by t.id<br>&nbsp; &nbsp; &nbsp; &nbsp;end<br>&nbsp; &nbsp; &nbsp; &nbsp;set nocount off<br>&nbsp; &nbsp; &nbsp; &nbsp;以上存储过程运用了SQL SERVER的最新技术――表变量。应该说这个存储过程也是一个非常优秀的分页存储过程。当然，在这个过程中，您也可以把其中的表变量写成临时表：CREATE TABLE #Temp。但很明显，在SQL SERVER中，用临时表是没有用表变量快的。所以笔者刚开始使用这个存储过程时，感觉非常的不错，速度也比原来的ADO的好。但后来，我又发现了比此方法更好的方法。<br>&nbsp; &nbsp; &nbsp; &nbsp;笔者曾在网上看到了一篇小短文《从数据表中取出第n条到第m条的记录的方法》，全文如下：<br>&nbsp; &nbsp; &nbsp; &nbsp;从publish 表中取出第 n 条到第 m 条的记录： <br>&nbsp; &nbsp; &nbsp; &nbsp;SELECT TOP m-n+1 * <br>&nbsp; &nbsp; &nbsp; &nbsp;FROM publish <br>&nbsp; &nbsp; &nbsp; &nbsp;WHERE (id NOT IN <br>&nbsp; &nbsp; &nbsp; &nbsp;　　　　(SELECT TOP n-1 id <br>&nbsp; &nbsp; &nbsp; &nbsp;　　　　 FROM publish)) <br>&nbsp; &nbsp; &nbsp; &nbsp;id 为publish 表的关键字 <br>&nbsp; &nbsp; &nbsp; &nbsp;我当时看到这篇文章的时候，真的是精神为之一振，觉得思路非常得好。等到后来，我在作办公自动化系统（ASP.NET+ C#＋SQL SERVER）的时候，忽然想起了这篇文章，我想如果把这个语句改造一下，这就可能是一个非常好的分页存储过程。于是我就满网上找这篇文章，没想到，文章还没找到，却找到了一篇根据此语句写的一个分页存储过程，这个存储过程也是目前较为流行的一种分页存储过程，我很后悔没有争先把这段文字改造成存储过程：<br>&nbsp; &nbsp; &nbsp; &nbsp;CREATE PROCEDURE pagination2<br>&nbsp; &nbsp; &nbsp; &nbsp;(<br>&nbsp; &nbsp; &nbsp; &nbsp;@SQL nVARCHAR(4000),&nbsp;&nbsp;&nbsp;&nbsp;--不带排序语句的SQL语句<br>&nbsp; &nbsp; &nbsp; &nbsp;@Page int,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--页码<br>&nbsp; &nbsp; &nbsp; &nbsp;@RecsPerPage int,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --每页容纳的记录数<br>&nbsp; &nbsp; &nbsp; &nbsp;@ID VARCHAR(255),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --需要排序的不重复的ID号<br>&nbsp; &nbsp; &nbsp; &nbsp;@Sort VARCHAR(255)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--排序字段及规则<br>&nbsp; &nbsp; &nbsp; &nbsp;)<br>&nbsp; &nbsp; &nbsp; &nbsp;AS<br>&nbsp; &nbsp; &nbsp; &nbsp;DECLARE @Str nVARCHAR(4000)<br>&nbsp; &nbsp; &nbsp; &nbsp;SET @Str='SELECT&nbsp;&nbsp; TOP '+CAST(@RecsPerPage AS VARCHAR(20))+' * FROM ('+@SQL+') T WHERE T.'+@ID+'NOT IN <br>&nbsp; &nbsp; &nbsp; &nbsp;(SELECT&nbsp;&nbsp; TOP '+CAST((@RecsPerPage*(@Page-1)) AS VARCHAR(20))+' '+@ID+' FROM ('+@SQL+') T9 ORDER BY '+@Sort+') ORDER BY '+@Sort<br>&nbsp; &nbsp; &nbsp; &nbsp;PRINT @Str<br>&nbsp; &nbsp; &nbsp; &nbsp;EXEC sp_ExecuteSql @Str<br>&nbsp; &nbsp; &nbsp; &nbsp;GO<br>&nbsp; &nbsp; &nbsp; &nbsp;其实，以上语句可以简化为：<br>&nbsp; &nbsp; &nbsp; &nbsp;SELECT TOP 页大小 *<br>&nbsp; &nbsp; &nbsp; &nbsp;FROM Table1<br>&nbsp; &nbsp; &nbsp; &nbsp;WHERE (ID NOT IN<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(SELECT TOP 页大小*页数 id<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM 表<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY id))<br>&nbsp; &nbsp; &nbsp; &nbsp;ORDER BY ID<br>&nbsp; &nbsp; &nbsp; &nbsp;但这个存储过程有一个致命的缺点，就是它含有NOT IN字样。虽然我可以把它改造为：<br>&nbsp; &nbsp; &nbsp; &nbsp;SELECT TOP 页大小 *<br>&nbsp; &nbsp; &nbsp; &nbsp;FROM Table1<br>&nbsp; &nbsp; &nbsp; &nbsp;WHERE not exists<br>&nbsp; &nbsp; &nbsp; &nbsp;(select * from (select top (页大小*页数) * from table1 order by id) b where b.id=a.id )<br>&nbsp; &nbsp; &nbsp; &nbsp;order by id<br>&nbsp; &nbsp; &nbsp; &nbsp;即，用not exists来代替not in，但我们前面已经谈过了，二者的执行效率实际上是没有区别的。<br>&nbsp; &nbsp; &nbsp; &nbsp;既便如此，用TOP 结合NOT IN的这个方法还是比用游标要来得快一些。<br>&nbsp; &nbsp; &nbsp; &nbsp;虽然用not exists并不能挽救上个存储过程的效率，但使用SQL SERVER中的TOP关键字却是一个非常明智的选择。因为分页优化的最终目的就是避免产生过大的记录集，而我们在前面也已经提到了TOP的优势，通过TOP 即可实现对数据量的控制。<br>&nbsp; &nbsp; &nbsp; &nbsp;在分页算法中，影响我们查询速度的关键因素有两点：TOP和NOT IN。TOP可以提高我们的查询速度，而NOT IN会减慢我们的查询速度，所以要提高我们整个分页算法的速度，就要彻底改造NOT IN，同其他方法来替代它。<br>&nbsp; &nbsp; &nbsp; &nbsp;我们知道，几乎任何字段，我们都可以通过max(字段)或min(字段)来提取某个字段中的最大或最小值，所以如果这个字段不重复，那么就可以利用这些不重复的字段的max或min作为分水岭，使其成为分页算法中分开每页的参照物。在这里，我们可以用操作符&#8220;&gt;&#8221;或&#8220;&lt;&#8221;号来完成这个使命，使查询语句符合SARG形式。如：<br>&nbsp; &nbsp; &nbsp; &nbsp;Select top 10 * from table1 where id&gt;200<br>&nbsp; &nbsp; &nbsp; &nbsp;于是就有了如下分页方案：<br>&nbsp; &nbsp; &nbsp; &nbsp;select top 页大小 *<br>&nbsp; &nbsp; &nbsp; &nbsp;from table1 <br>&nbsp; &nbsp; &nbsp; &nbsp;where id&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(select max (id) from <br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(select top ((页码-1)*页大小) id from table1 order by id) as T<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;order by id<br>&nbsp; &nbsp; &nbsp; &nbsp;在选择即不重复值，又容易分辨大小的列时，我们通常会选择主键。下表列出了笔者用有着1000万数据的办公自动化系统中的表，在以GID（GID是主键，但并不是聚集索引。）为排序列、提取gid,fariqi,title字段，分别以第1、10、100、500、1000、1万、10万、25万、50万页为例，测试以上三种分页方案的执行速度：（单位：毫秒）<br>&nbsp; &nbsp; &nbsp; &nbsp;页&nbsp;&nbsp;码<br>&nbsp; &nbsp; &nbsp; &nbsp;方案1<br>&nbsp; &nbsp; &nbsp; &nbsp;方案2<br>&nbsp; &nbsp; &nbsp; &nbsp;方案3<br>&nbsp; &nbsp; &nbsp; &nbsp;1<br>&nbsp; &nbsp; &nbsp; &nbsp;60<br>&nbsp; &nbsp; &nbsp; &nbsp;30<br>&nbsp; &nbsp; &nbsp; &nbsp;76<br>&nbsp; &nbsp; &nbsp; &nbsp;10<br>&nbsp; &nbsp; &nbsp; &nbsp;46<br>&nbsp; &nbsp; &nbsp; &nbsp;16<br>&nbsp; &nbsp; &nbsp; &nbsp;63<br>&nbsp; &nbsp; &nbsp; &nbsp;100<br>&nbsp; &nbsp; &nbsp; &nbsp;1076<br>&nbsp; &nbsp; &nbsp; &nbsp;720<br>&nbsp; &nbsp; &nbsp; &nbsp;130<br>&nbsp; &nbsp; &nbsp; &nbsp;500<br>&nbsp; &nbsp; &nbsp; &nbsp;540<br>&nbsp; &nbsp; &nbsp; &nbsp;12943<br>&nbsp; &nbsp; &nbsp; &nbsp;83<br>&nbsp; &nbsp; &nbsp; &nbsp;1000<br>&nbsp; &nbsp; &nbsp; &nbsp;17110<br>&nbsp; &nbsp; &nbsp; &nbsp;470<br>&nbsp; &nbsp; &nbsp; &nbsp;250<br>&nbsp; &nbsp; &nbsp; &nbsp;1万<br>&nbsp; &nbsp; &nbsp; &nbsp;24796<br>&nbsp; &nbsp; &nbsp; &nbsp;4500<br>&nbsp; &nbsp; &nbsp; &nbsp;140<br>&nbsp; &nbsp; &nbsp; &nbsp;10万<br>&nbsp; &nbsp; &nbsp; &nbsp;38326<br>&nbsp; &nbsp; &nbsp; &nbsp;42283<br>&nbsp; &nbsp; &nbsp; &nbsp;1553<br>&nbsp; &nbsp; &nbsp; &nbsp;25万<br>&nbsp; &nbsp; &nbsp; &nbsp;28140<br>&nbsp; &nbsp; &nbsp; &nbsp;128720<br>&nbsp; &nbsp; &nbsp; &nbsp;2330<br>&nbsp; &nbsp; &nbsp; &nbsp;50万<br>&nbsp; &nbsp; &nbsp; &nbsp;121686<br>&nbsp; &nbsp; &nbsp; &nbsp;127846<br>&nbsp; &nbsp; &nbsp; &nbsp;7168<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;从上表中，我们可以看出，三种存储过程在执行100页以下的分页命令时，都是可以信任的，速度都很好。但第一种方案在执行分页1000页以上后，速度就降了下来。第二种方案大约是在执行分页1万页以上后速度开始降了下来。而第三种方案却始终没有大的降势，后劲仍然很足。<br>&nbsp; &nbsp; &nbsp; &nbsp;在确定了第三种分页方案后，我们可以据此写一个存储过程。大家知道SQL SERVER的存储过程是事先编译好的SQL语句，它的执行效率要比通过WEB页面传来的SQL语句的执行效率要高。下面的存储过程不仅含有分页方案，还会根据页面传来的参数来确定是否进行数据总数统计。<br>&nbsp; &nbsp; &nbsp; &nbsp;-- 获取指定页的数据<br>&nbsp; &nbsp; &nbsp; &nbsp;CREATE PROCEDURE pagination3<br>&nbsp; &nbsp; &nbsp; &nbsp;@tblName&nbsp;&nbsp; varchar(255),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- 表名<br>&nbsp; &nbsp; &nbsp; &nbsp;@strGetFields varchar(1000) = '*',&nbsp;&nbsp;-- 需要返回的列 <br>&nbsp; &nbsp; &nbsp; &nbsp;@fldName varchar(255)='',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- 排序的字段名<br>&nbsp; &nbsp; &nbsp; &nbsp;@PageSize&nbsp;&nbsp; int = 10,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- 页尺寸<br>&nbsp; &nbsp; &nbsp; &nbsp;@PageIndex&nbsp;&nbsp;int = 1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- 页码<br>&nbsp; &nbsp; &nbsp; &nbsp;@doCount&nbsp;&nbsp;bit = 0,&nbsp;&nbsp; -- 返回记录总数, 非 0 值则返回<br>&nbsp; &nbsp; &nbsp; &nbsp;@OrderType bit = 0,&nbsp;&nbsp;-- 设置排序类型, 非 0 值则降序<br>&nbsp; &nbsp; &nbsp; &nbsp;@strWhere&nbsp;&nbsp;varchar(1500) = ''&nbsp;&nbsp;-- 查询条件 (注意: 不要加 where)<br>&nbsp; &nbsp; &nbsp; &nbsp;AS<br>&nbsp; &nbsp; &nbsp; &nbsp;declare @strSQL&nbsp;&nbsp; varchar(5000)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- 主语句<br>&nbsp; &nbsp; &nbsp; &nbsp;declare @strTmp&nbsp;&nbsp; varchar(110)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- 临时变量<br>&nbsp; &nbsp; &nbsp; &nbsp;declare @strOrder varchar(400)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- 排序类型<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;if @doCount != 0<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if @strWhere !=''<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strSQL = "select count(*) as Total from [" + @tblName + "]"<br>&nbsp; &nbsp; &nbsp; &nbsp;end&nbsp;&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;--以上代码的意思是如果@doCount传递过来的不是0，就执行总数统计。以下的所有代码都是@doCount为0的情况<br>&nbsp; &nbsp; &nbsp; &nbsp;else<br>&nbsp; &nbsp; &nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;if @OrderType != 0<br>&nbsp; &nbsp; &nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strTmp = "&lt;(select min"<br>&nbsp; &nbsp; &nbsp; &nbsp;set @strOrder = " order by [" + @fldName +"] desc"<br>&nbsp; &nbsp; &nbsp; &nbsp;--如果@OrderType不是0，就执行降序，这句很重要！<br>&nbsp; &nbsp; &nbsp; &nbsp;end<br>&nbsp; &nbsp; &nbsp; &nbsp;else<br>&nbsp; &nbsp; &nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strTmp = "&gt;(select max"<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strOrder = " order by [" + @fldName +"] asc"<br>&nbsp; &nbsp; &nbsp; &nbsp;end<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;if @PageIndex = 1<br>&nbsp; &nbsp; &nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if @strWhere != ''&nbsp;&nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "&nbsp;&nbsp;from [" + @tblName + "] where " + @strWhere + " " + @strOrder<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "&nbsp;&nbsp;from ["+ @tblName + "] "+ @strOrder<br>&nbsp; &nbsp; &nbsp; &nbsp;--如果是第一页就执行以上代码，这样会加快执行速度<br>&nbsp; &nbsp; &nbsp; &nbsp;end<br>&nbsp; &nbsp; &nbsp; &nbsp;else<br>&nbsp; &nbsp; &nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; &nbsp;--以下代码赋予了@strSQL以真正执行的SQL代码<br>&nbsp; &nbsp; &nbsp; &nbsp;set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "&nbsp;&nbsp;from ["<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;if @strWhere != ''<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "&nbsp;&nbsp;from ["<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ @fldName + "] from [" + @tblName + "] where " + @strWhere + " "<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder<br>&nbsp; &nbsp; &nbsp; &nbsp;end <br>&nbsp; &nbsp; &nbsp; &nbsp;end&nbsp;&nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp;exec (@strSQL)<br>&nbsp; &nbsp; &nbsp; &nbsp;GO<br>&nbsp; &nbsp; &nbsp; &nbsp;上面的这个存储过程是一个通用的存储过程，其注释已写在其中了。<br>&nbsp; &nbsp; &nbsp; &nbsp;在大数据量的情况下，特别是在查询最后几页的时候，查询时间一般不会超过9秒；而用其他存储过程，在实践中就会导致超时，所以这个存储过程非常适用于大容量数据库的查询。<br>&nbsp; &nbsp; &nbsp; &nbsp;笔者希望能够通过对以上存储过程的解析，能给大家带来一定的启示，并给工作带来一定的效率提升，同时希望同行提出更优秀的实时数据分页算法。<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;四、聚集索引的重要性和如何选择聚集索引<br>&nbsp; &nbsp; &nbsp; &nbsp;在上一节的标题中，笔者写的是：实现小数据量和海量数据的通用分页显示存储过程。这是因为在将本存储过程应用于&#8220;办公自动化&#8221;系统的实践中时，笔者发现这第三种存储过程在小数据量的情况下，有如下现象：<br>&nbsp; &nbsp; &nbsp; &nbsp;1、分页速度一般维持在1秒和3秒之间。<br>&nbsp; &nbsp; &nbsp; &nbsp;2、在查询最后一页时，速度一般为5秒至8秒，哪怕分页总数只有3页或30万页。<br>&nbsp; &nbsp; &nbsp; &nbsp;虽然在超大容量情况下，这个分页的实现过程是很快的，但在分前几页时，这个1－3秒的速度比起第一种甚至没有经过优化的分页方法速度还要慢，借用户的话说就是&#8220;还没有ACCESS数据库速度快&#8221;，这个认识足以导致用户放弃使用您开发的系统。<br>&nbsp; &nbsp; &nbsp; &nbsp;笔者就此分析了一下，原来产生这种现象的症结是如此的简单，但又如此的重要：排序的字段不是聚集索引！<br>&nbsp; &nbsp; &nbsp; &nbsp;本篇文章的题目是：&#8220;查询优化及分页算法方案&#8221;。笔者只所以把&#8220;查询优化&#8221;和&#8220;分页算法&#8221;这两个联系不是很大的论题放在一起，就是因为二者都需要一个非常重要的东西――聚集索引。<br>&nbsp; &nbsp; &nbsp; &nbsp;在前面的讨论中我们已经提到了，聚集索引有两个最大的优势：<br>&nbsp; &nbsp; &nbsp; &nbsp;1、以最快的速度缩小查询范围。<br>&nbsp; &nbsp; &nbsp; &nbsp;2、以最快的速度进行字段排序。<br>&nbsp; &nbsp; &nbsp; &nbsp;第1条多用在查询优化时，而第2条多用在进行分页时的数据排序。<br>&nbsp; &nbsp; &nbsp; &nbsp;而聚集索引在每个表内又只能建立一个，这使得聚集索引显得更加的重要。聚集索引的挑选可以说是实现&#8220;查询优化&#8221;和&#8220;高效分页&#8221;的最关键因素。<br>&nbsp; &nbsp; &nbsp; &nbsp;但要既使聚集索引列既符合查询列的需要，又符合排序列的需要，这通常是一个矛盾。<br>&nbsp; &nbsp; &nbsp; &nbsp;笔者前面&#8220;索引&#8221;的讨论中，将fariqi，即用户发文日期作为了聚集索引的起始列，日期的精确度为&#8220;日&#8221;。这种作法的优点，前面已经提到了，在进行划时间段的快速查询中，比用ID主键列有很大的优势。<br>&nbsp; &nbsp; &nbsp; &nbsp;但在分页时，由于这个聚集索引列存在着重复记录，所以无法使用max或min来最为分页的参照物，进而无法实现更为高效的排序。而如果将ID主键列作为聚集索引，那么聚集索引除了用以排序之外，没有任何用处，实际上是浪费了聚集索引这个宝贵的资源。<br>&nbsp; &nbsp; &nbsp; &nbsp;为解决这个矛盾，笔者后来又添加了一个日期列，其默认值为getdate()。用户在写入记录时，这个列自动写入当时的时间，时间精确到毫秒。即使这样，为了避免可能性很小的重合，还要在此列上创建UNIQUE约束。将此日期列作为聚集索引列。<br>&nbsp; &nbsp; &nbsp; &nbsp;有了这个时间型聚集索引列之后，用户就既可以用这个列查找用户在插入数据时的某个时间段的查询，又可以作为唯一列来实现max或min，成为分页算法的参照物。<br>&nbsp; &nbsp; &nbsp; &nbsp;经过这样的优化，笔者发现，无论是大数据量的情况下还是小数据量的情况下，分页速度一般都是几十毫秒，甚至0毫秒。而用日期段缩小范围的查询速度比原来也没有任何迟钝。<br>&nbsp; &nbsp; &nbsp; &nbsp;聚集索引是如此的重要和珍贵，所以笔者总结了一下，一定要将聚集索引建立在：<br>&nbsp; &nbsp; &nbsp; &nbsp;1、您最频繁使用的、用以缩小查询范围的字段上；<br>&nbsp; &nbsp; &nbsp; &nbsp;2、您最频繁使用的、需要排序的字段上。<br>&nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp;结束语：<br>&nbsp; &nbsp; &nbsp; &nbsp;本篇文章汇集了笔者近段在使用数据库方面的心得，是在做&#8220;办公自动化&#8221;系统时实践经验的积累。希望这篇文章不仅能够给大家的工作带来一定的帮助，也希望能让大家能够体会到分析问题的方法；最重要的是，希望这篇文章能够抛砖引玉，掀起大家的学习和讨论的兴趣，以共同促进，共同为公安科技强警事业和金盾工程做出自己最大的努力。<br>&nbsp; &nbsp; &nbsp; &nbsp;最后需要说明的是，在试验中，我发现用户在进行大数据量查询的时候，对数据库速度影响最大的不是内存大小，而是CPU。在我的P4 2.4机器上试验的时候，查看&#8220;资源管理器&#8221;，CPU经常出现持续到100%的现象，而内存用量却并没有改变或者说没有大的改变。即使在我们的HP ML 350 G3服务器上试验时，CPU峰值也能达到90%，一般持续在70%左右。<br>&nbsp; &nbsp; &nbsp; &nbsp;本文的试验数据都是来自我们的HP ML 350服务器。服务器配置：双Inter Xeon 超线程 CPU 2.4G，内存1G，操作系统Windows Server 2003 Enterprise Edition，数据库SQL Server 2000 SP3</div>
<img src ="http://www.cppblog.com/andxie99/aggbug/7974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:40 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入分析MFC文档视图结构（项目实践）</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7972.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:39:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7972.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7972.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7972.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7972.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1 必备基础知识概述 1.1 MFC 文档视图结构程序结构总揽 当我们使用 MFC AppWizard 生成一个 MFC 程序，选用所有默认的设置（当然也是 Multiple Documents ，本文讨论主要基于 Multiple Documents ，对于 Single Document 情况仅以简单表述提及，皆因后者和前者很多相似相同之处，但前者更为复杂，并且更加常用。），假设你的程...&nbsp;&nbsp;<a href='http://www.cppblog.com/andxie99/archive/2006/05/31/7972.html'>阅读全文</a><img src ="http://www.cppblog.com/andxie99/aggbug/7972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:39 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式基础知识</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7971.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:37:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7971.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7971.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7971.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7971.html</trackback:ping><description><![CDATA[　<strong>一、正则表达式基础知识</strong><br>　　我们先从简单的开始。假设你要搜索一个包含字符&#8220;cat&#8221;的字符串，搜索用的正则表达式就是&#8220;cat&#8221;。如果搜索对大小写不敏感，单词&#8220;catalog&#8221;、&#8220;Catherine&#8221;、&#8220;sophisticated&#8221;都可以匹配。也就是说：<br>
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-1.jpg" border=0></div>
<br>　　<strong>1.1句点符号</strong><br>　　假设你在玩英文拼字游戏，想要找出三个字母的单词，而且这些单词必须以&#8220;t&#8221;字母开头，以&#8220;n&#8221;字母结束。另外，假设有一本英文字典，你可以用正则表达式搜索它的全部内容。要构造出这个正则表达式，你可以使用一个通配符??句点符号&#8220;.&#8221;。这样，完整的表达式就是&#8220;t.n&#8221;，它匹配&#8220;tan&#8221;、&#8220;ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;，还匹配&#8220;t#n&#8221;、&#8220;tpn&#8221;甚至&#8220;tn&#8221;，还有其他许多无意义的组合。这是因为句点符号匹配所有字符，包括空格、Tab字符甚至换行符：<br>
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-2.jpg" border=0></div>
　　<strong>1.2方括号符号</strong>　　为了解决句点符号匹配范围过于广泛这一问题，你可以在方括号（&#8220;[]&#8221;）里面指定看来有意义的字符。此时，只有方括号里面指定的字符才参与匹配。也就是说，正则表达式&#8220;t[aeio]n&#8221;只匹配&#8220;tan&#8221;、&#8220;Ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;。但&#8220;Toon&#8221;不匹配，因为在方括号之内你只能匹配单个字符：
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-3.jpg" border=0></div>
　　<strong>1.4表示匹配次数的符号</strong>　　表一显示了表示匹配次数的符号，这些符号用来确定紧靠该符号左边的符号出现的次数：
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-4.jpg" border=0></div>
　　假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中，连字符（&#8220;-&#8221;）有着特殊的意义，它表示一个范围，比如从0到9。因此，匹配社会安全号码中的连字符号时，它的前面要加上一个转义字符&#8220;\&#8221;。
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-5.gif" width=420 border=0></div>
　　图一：匹配所有123-12-1234形式的社会安全号码　　假设进行搜索的时候，你希望连字符号可以出现，也可以不出现??即，999-99-9999和999999999都属于正确的格式。这时，你可以在连字符号后面加上&#8220;？&#8221;数量限定符号，如图二所示：
<div align=center><img height=90 src="http://www.webjx.com/img1/jsp04121114-6.gif" width=420 border=0></div>
　　图二：匹配所有123-12-1234和123121234形式的社会安全号码　　下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分&#8220;[0-9]{ 4}&#8221;，再加上字母部分&#8220;[A-Z]{ 2}&#8221;。图三显示了完整的正则表达式。
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-7.gif" border=0></div>
　　图三：匹配典型的美国汽车牌照号码，如8836KV　　1.5&#8220;否&#8221;符号　　&#8220;^&#8221;符号称为&#8220;否&#8221;符号。如果用在方括号内，&#8220;^&#8221;表示不想要匹配的字符。例如，图四的正则表达式匹配所有单词，但以&#8220;X&#8221;字母开头的单词除外。
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-8.gif" width=420 border=0></div>
　　图四：匹配所有单词，但&#8220;X&#8221;开头的除外　　1.6圆括号和空白符号　　假设要从格式为&#8220;June26,1951&#8221;的生日日期中提取出月份部分，用来匹配该日期的正则表达式可以如图五所示：
<div align=center><img height=107 src="http://www.webjx.com/img1/jsp04121114-9.gif" width=420 border=0></div>
　　图五：匹配所有MothDD,YYYY格式的日期　　新出现的&#8220;\s&#8221;符号是空白符号，匹配所有的空白字符，包括Tab字符。如果字符串正确匹配，接下来如何提取出月份部分呢？只需在月份周围加上一个圆括号创建一个组，然后用OROAPI（本文后面详细讨论）提取出它的值。修改后的正则表达式如图六所示：
<div align=center><img height=118 src="http://www.webjx.com/img1/jsp04121114-10.gif" width=420 border=0></div>
　　图六：匹配所有MonthDD,YYYY格式的日期，定义月份值为第一个组　　<strong>1.7其它符号</strong>　　为简便起见，你可以使用一些为常见正则表达式创建的快捷符号。如表二所示：　　表二：常用符号
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-11.jpg" border=0></div>
　　例如，在前面社会安全号码的例子中，所有出现&#8220;[0-9]&#8221;的地方我们都可以使用&#8220;\d&#8221;。修改后的正则表达式如图七所示：
<div align=center><img src="http://www.webjx.com/img1/jsp04121114-12.gif" border=0></div>
一些常用的正则表达式：
<p>^\d+$　　//匹配非负整数（正整数 + 0） <br>^[0-9]*[1-9][0-9]*$　　//匹配正整数 <br>^((-\d+)|(0+))$　　//匹配非正整数（负整数 + 0） <br>^-[0-9]*[1-9][0-9]*$　　//匹配负整数 <br>^-?\d+$　　　　//匹配整数 <br>^\d+(\.\d+)?$　　//匹配非负浮点数（正浮点数 + 0） <br>^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$　　//匹配正浮点数 <br>^((-\d+(\.\d+)?)|(0+(\.0+)?))$　　//匹配非正浮点数（负浮点数 + 0） <br>^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$　　//匹配负浮点数 <br>^(-?\d+)(\.\d+)?$　　//匹配浮点数 <br>^[A-Za-z]+$　　//匹配由26个英文字母组成的字符串 <br>^[A-Z]+$　　//匹配由26个英文字母的大写组成的字符串 <br>^[a-z]+$　　//匹配由26个英文字母的小写组成的字符串 <br>^[A-Za-z0-9]+$　　//匹配由数字和26个英文字母组成的字符串 <br>^\w+$　　//匹配由数字、26个英文字母或者下划线组成的字符串 <br>^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$　　　　//匹配email地址 <br>^[a-zA-z]+://匹配(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$　　//匹配url </p>
<img src ="http://www.cppblog.com/andxie99/aggbug/7971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:37 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中自定义消息实现</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7967.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:33:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7967.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7967.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7967.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7967.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7967.html</trackback:ping><description><![CDATA[<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-list: l0 level1 lfo1; tab-stops: list 42.0pt"><span lang=EN-US style="FONT-FAMILY: Wingdings; mso-bidi-font-family: Wingdings; mso-fareast-font-family: Wingdings"><span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">自定义消息</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; LINE-HEIGHT: 150%"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我们可以通过一下两种方法来自定义一个消息：</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 36pt; TEXT-INDENT: -18pt; LINE-HEIGHT: 150%; mso-list: l1 level1 lfo2; tab-stops: list 36.0pt"><span lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1）<span style="FONT: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法一</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; LINE-HEIGHT: 150%"><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial">Step 1</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：使用</span> <span lang=EN-US>WM_TASKBARCREATED</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来确定一个没有被</span> <span lang=EN-US>windows</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">本身抢占的消息值，在想添加消息文件中添加代码：</span> </p>
<table class=MsoTableGrid style="BACKGROUND: #d9d9d9" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes">
            <td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" vAlign=top width=568>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>const UINT WM_USERDEFMSG = ::<span style="COLOR: blue">RegisterWindowMessage</span>(_T("UserDefMsg"));</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; LINE-HEIGHT: 150%"><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial">Step 2</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：定义消息的处理过程：在处理消息的类（如</span> <span lang=EN-US>Dlg</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类或者</span> <span lang=EN-US>MainFrame</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等）添加消息处理函数声明：</span> </p>
<table class=MsoTableGrid style="BACKGROUND: #d9d9d9" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes">
            <td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" vAlign=top width=568>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="COLOR: blue">afx_msg</span> <span lang=EN-US><span style="COLOR: blue">LRESULT</span> OnUserDefMsg(WPARAM wParam,LPARAM lParam);</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在实现文件中添加消息处理实现，这里给出一个实现例子：</span> </p>
<table class=MsoTableGrid style="BACKGROUND: #d9d9d9" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes">
            <td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" vAlign=top width=568>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>LRESULT </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&#215;&#215;&#215;&#215;</span> <span lang=EN-US>::OnUserDefMsg(WPARAM wParam,LPARAM lParam)</span> </p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><em style="mso-bidi-font-style: normal"><span lang=EN-US style="COLOR: green">//</span> </em><em style="mso-bidi-font-style: normal"><span style="COLOR: green; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&#215;&#215;&#215;&#215;代表处理该消息的类名</span> <span lang=EN-US style="COLOR: green"><o:p></o:p></span></em></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>{</span> </p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MessageBox("</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">响应了自定义的消息，</span> <span lang=EN-US>^_^","</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">自定义消息响应</span> <span lang=EN-US>",MB_ICONQUESTION | MB_OK);</span> </p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return 0;</span> </p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>}</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial">Step 3</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：添加消息处理宏，在处理该消息的类的消息宏中添加自定义消息的宏，即在</span> <span lang=EN-US>BEGIN_MESSAGE_MAP</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">代码块中添加代码：</span> </p>
<table class=MsoTableGrid style="BACKGROUND: #d9d9d9" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes">
            <td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" vAlign=top width=568>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>ON_REGISTERED_MESSAGE(WM_USERDEFMSG, OnUserDefMsg)</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">自定义消息完毕。</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 36pt; TEXT-INDENT: -18pt; LINE-HEIGHT: 150%; mso-list: l1 level1 lfo2; tab-stops: list 36.0pt"><span lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">2）<span style="FONT: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法二</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; LINE-HEIGHT: 150%"><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial">Step 1</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：定义消息值，这里不通过</span> <span lang=EN-US style="COLOR: blue">RegisterWindowMessage</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">获取，而是自定义方式实现，在想添加消息文件中添加代码：</span> </p>
<table class=MsoTableGrid style="BACKGROUND: #d9d9d9" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes">
            <td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" vAlign=top width=568>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>#define WM_USERDEFMSG (WM_USER + 101)</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Microsoft</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">推荐自定义消息值至少为</span> <span lang=EN-US style="COLOR: blue">WM_USER + 100</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial">Step 2</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：同方法一中实现；</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial">Step 3</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：同方法一中，但是宏名称改为</span> <span lang=EN-US>ON_MESSAGE</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-list: l0 level1 lfo1; tab-stops: list 42.0pt"><span lang=EN-US style="FONT-FAMILY: Wingdings; mso-bidi-font-family: Wingdings; mso-fareast-font-family: Wingdings"><span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">发送消息</span> </p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; LINE-HEIGHT: 150%"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">按照上面方式我们已经自定义了消息，并为该消息实现了简单的处理过程，这里就通过发送消息获得自定义消息的响应。在要触发自定义消息地方添加代码：</span> </p>
<table class=MsoTableGrid style="BACKGROUND: #d9d9d9" cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes">
            <td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" vAlign=top width=568>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>::<span style="COLOR: blue">SendMessage</span>(<span style="COLOR: blue">GetSafeHwnd</span>(),WM_USERDEFMSG,<st1:chmetcnv unitname="l" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0L</st1:chmetcnv>,<st1:chmetcnv unitname="l" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0L</st1:chmetcnv>);</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 150%"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这样你就触发了该自定义消息，并将得到提示对话框显示。</span> </p>
<img src ="http://www.cppblog.com/andxie99/aggbug/7967.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:33 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7967.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>句柄的本质（转）</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7966.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:32:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7966.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7966.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7966.html</trackback:ping><description><![CDATA[<p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><strong>一、书上定义：</strong> </font></span></p>
<p><font size=2><u>&lt;&lt;Microsoft Windows 3 Developer's Workshop&gt;&gt;(Microsoft Press,by Richard Wilton)</u> <br>&nbsp;&nbsp;&nbsp; 在Windows环境中，句柄是用来标识项目的，这些项目包括：模块(module)、任务(task)、实例 </font><font size=2>(instance)、文件(file)、内存块(block of memory)、菜单(menu)、控制(control)、字体(font)、资</font> <font size=2>源(resource)，包括图标(icon)，光标 (cursor)，字符串(string)等、GDI对象(GDI object)，包括位</font> <font size=2>图(bitmap)，画刷(brush)，元文件（metafile）,调色板(palette)，画笔(pen)，区域 (region)，以及</font> <font size=2>设备描述表(device context)。 </font></p>
<p><font size=2><u>&lt;&lt;WINDOWS编程短平快&gt;&gt;(南京大学出版社)：</u> <br>&nbsp;&nbsp;&nbsp; 句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数，WINDOWS使用各种各样的句柄</font> <font size=2>标识诸如应用程序实例，窗口，控制，位图，GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。 </font></p>
<p><font size=2><strong>二、MFC源代码：</strong> </font></p>
<p><font size=2>#ifdef STRICT<br>typedef void *<font color=#ff0000>HANDLE</font>;<br>#define <font color=#ff0000>DECLARE_HANDLE(name)</font> struct name##__ { int <font color=#ff0000>unused</font>; }; typedef struct name##__ *name<br>#else<br>typedef PVOID HANDLE;<br>#define DECLARE_HANDLE(name) typedef HANDLE name<br>#endif</font> </p>
<p><font size=2>DECLARE_HANDLE(HMODULE); <br>DECLARE_HANDLE(HINSTANCE); <br>DECLARE_HANDLE(HLOCAL); <br>DECLARE_HANDLE(HGLOBAL); <br>DECLARE_HANDLE(HDC); <br>DECLARE_HANDLE(HRGN); <br>DECLARE_HANDLE(HWND); <br>DECLARE_HANDLE(HMENU); <br>DECLARE_HANDLE(HACCEL); <br>DECLARE_HANDLE(HTASK); </font></p>
<font size=2>
<p><br><strong>三、理解：</strong> <br>&nbsp;&nbsp;&nbsp; HANDLE就是PVOID，也就是无类型指针，<br>&nbsp;&nbsp;&nbsp; 上面这些资源的句柄Handles都不过是指向struct的指针，至于这个struct的用处，连M$都说unused了，现在解释下M$这么做的意义，这就是所谓数据封装，你可以在你的程序中把M$的内部结构指针传来传去，可是你却不知道它到底指向的内容是什么。</p>
<p>&nbsp;&nbsp;&nbsp; 句柄与指针确实是完全不同的两个概念。句柄仅仅是一个32位整数，WIN32中用于标记某个系统或进程的对象，可以理解为对象索引（由于M$未完全公开相关技术，在一定程度上只能如此理解），这个索引更像是一种映射关系（从句柄到对象指针的映射），而不是纯粹意义上的&#8220;数组下标&#8221;。 <br></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 句柄可以理解为用于指向或标识内存的一块&#8220;资源&#8221;，这些资源如：文件(file)、内存块(block of memory)、菜单(menu)等等。操作系统通过句柄来定位核心对象和系统资源。<br>&nbsp;&nbsp;&nbsp; 指针即为指向内存的&#8220;数据或指令&#8221;某一单元。</p>
<p>&nbsp;&nbsp;&nbsp; 说的确切一点，句柄实际上是一种指向某种资源的指针，但与指针又有所不同：指针对应着一个数据在内存中的地址，得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构，因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针，但不要直接操作它)，平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。</p>
<p><strong>&nbsp;&nbsp;&nbsp; <br>四、引喻：</strong> <br>&nbsp;&nbsp; 牧童遥指杏花村<br>&nbsp;&nbsp; 牧童的手为指针，杏花村的牌子为句柄，杏花村酒店为对象的实例. </p>
<p>&#160;</p>
<p><strong>附注：获得窗口句柄三种方法</strong> </p>
<p>1.HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)&nbsp;</p>
<p dir=ltr style="MARGIN-RIGHT: 0px">&nbsp;&nbsp;&nbsp;HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)&nbsp;</p>
<p dir=ltr style="MARGIN-RIGHT: 0px">2.HWND WindowFromPoint(POINT&amp; Point)//获得当前鼠标光标位置的窗口HWND</p>
<p dir=ltr style="MARGIN-RIGHT: 0px">3.BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)</p>
<p dir=ltr style="MARGIN-RIGHT: 0px">&nbsp;&nbsp; BOOL CALLBACK EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc,LPARAM lParam)</p>
<p dir=ltr style="MARGIN-RIGHT: 0px">&nbsp;&nbsp; BOOL CALLBACK EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)</p>
<p dir=ltr style="MARGIN-RIGHT: 0px">&nbsp;&nbsp; BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)<br></p>
</font>
<img src ="http://www.cppblog.com/andxie99/aggbug/7966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:32 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visulal C++是什么?--兼谈其他    原作 weizhisheng</title><link>http://www.cppblog.com/andxie99/archive/2006/05/31/7958.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 31 May 2006 09:24:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/05/31/7958.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/7958.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/05/31/7958.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/7958.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/7958.html</trackback:ping><description><![CDATA[<p>这个问题很奇怪吗？大概是。不过，当我又看到有人发表诸如&#8220;Windows/Office是VC编写的&#8221;或者&#8220;VC是无所不能的&#8221;这种高论，我就禁不住这样问自己。</p>
<p>Visual C++究竟是什么？你平常在其中工作的那个标记着&#8220;Microsoft Visual C++&#8221;的窗口，真的就代表Visual C++吗？</p>
<p>按照我的理解，Visual C++是一个开发工具包，它大概可以分成三个主要的部分：</p>
<p>1． Developer Studio，这是一个集成开发环境，我们日常工作的99%都是在它上面完成的，再加上它的标题赫然写着&#8220;Microsoft Visual C++&#8221;，所以很多人理所当然的认为，那就是Visual C++了。其实不然，虽然Developer Studio提供了一个很好的编辑器和很多Wizard，但实际上它没有任何编译和链接程序的功能，真正完成这些工作的幕后英雄后面会介绍。我们也知道，Developer Studio并不是专门用于VC的，它也同样用于VB，VJ，VID等Visual Studio家族的其他同胞兄弟。所以不要把Developer Studio当成Visual C++， 它充其量只是Visual C++的一个壳子而已。这一点请切记！</p>
<p>2． MFC。从理论上来讲，MFC也不是专用于Visual C++，Borland C++，C++Builder和Symantec C++同样可以处理MFC。同时，用Visual C++编写代码也并不意味着一定要用MFC，只要愿意，用Visual C++来编写SDK程序，或者使用STL，ATL，一样没有限制。不过，Visual C++本来就是为MFC打造的，Visual C++中的许多特征和语言扩展也是为MFC而设计的，所以用Visual C++而不用MFC就等于抛弃了Visual C++中很大的一部分功能。但是，Visual C++也不等于MFC。</p>
<p>3． Platform SDK。这才是Visual C++和整个Visual Studio的精华和灵魂，虽然我们很少能直接接触到它。大致说来，Platform SDK是以Microsoft C/C++编译器为核心（不是Visual C++，看清楚了），配合MASM，辅以其他一些工具和文档资料。上面说到Developer Studio没有编译程序的功能，那么这项工作是由谁来完成的呢？是CL，是NMAKE，和其他许许多多命令行程序，这些我们看不到的程序才是构成Visual Studio的基石。</p>
<p>为什么我会觉得&#8220;Windows是用VC开发的&#8221;这种说法很奇怪？因为它太含糊了。用VC，可以编写MFC应用，也可以编写纯SDK程序，不论哪一种方式，都不一定是非VC不可。只要乐意，我完全可以用UltraEdit来写出一个MFC程序，再用CL编译之，没有必要一定动用VC这个大家伙。而且有许多黑客和买不起Visual Studio的人就是这么干的！用SDK编程就更不需要VC了，Down一个Borlan C++ Compiler下来，或者用lcc之类的编译器，同样可以达到目的。再说了，Windows可不是一个单纯的产品。用VC来编写Windows外围程序是完全不成问题的，可是操作系统的核心部分呢？就算可以用VC来编写代码，调试怎么办？VC自身的调试器对一般的应用功能是够强大的，可是对于系统级的调试根本无能为力，因为这个调试器本身就是依赖于操作系统的。只有系统级的调试程序如debug，SoftIce和Wdebug这些工具才能完成如此重大的任务。</p>
<p>从历史上来看，Visual C++ 1.0的出现晚于Windows 3.0，而且那时候的MFC只有一个雏形而已，用来开发操作系统根本是不可能的事情。在Visual C++ 1.0的前面倒是有一个Microsoft C/C++ 7.0，但是它整体水平不如Borland C++ 3.1，在扩展内存管理方面的功能又不如Watcom C++ ，所以一直没有占据很大的市场。它现在已经不作为单独的产品，但仍然作为Platform SDK的主要组成部分而存在于Visual Studio产品中，而且其功能比过去也不可同日而语了。到Windows 95问世的时候，MFC仍然在尽力追赶操作系统的功能。应该说Visual C++ 5.0是一个转折点，一方面MFC已经发展比较完善，另一方面，操作系统的基本结构也已经稳定，后面就主要着眼于系统整合与完善作为商务平台的功能。已经稳定的系统不可能再进行翻天覆地的修改，所以，我比较能够接受&#8220;Windows系统是用Microsoft C++和MASM作为编译器完成的&#8221;这种说法。研究Windows的系统文件可以看出，很多文件显示出来的Linker Version明显是Microsoft C++编译器。至于代码是用什么编写的？我不知道，也不想知道，除了Developer Studio的编辑器之外，任何好的文本编辑器都能够做到这一点。</p>
<p>Visual C++是无所不能的吗？唔，最好也是分开来说。Developer Studio肯定不是—它只是个外壳而已。MFC呢？也不是。一方面它是对API的封装，离开了API它就什么也干不了；另一方面，MFC对API的封装也不够全面，有些时候还是要直接调用API函数才能够&#8220;为所欲为&#8221;。至于Platform SDK，倒真的可以说它几乎是无所不能的。不过，过分强调这一点并没有太大意义。只要有一套完整的编译器，和必须的支持文件，其他开发工具也可以说是&#8220;无所不能&#8221;的，比如Borland C++ Compiler或者lcc都可。</p>
<p>老实说，我并不喜欢&#8220;无所不能&#8221;这类字眼。关键在于各人的理解不同。如果我较起真来，说能不能写个VC程序让电脑拿起鼠标砸向我不喜欢的老板，你说它能办得到吗？所谓的&#8220;无所不能&#8221;究竟有何意义？让我用VC写一个Server，能在普通工作站上支持每秒几千万的访问量，杀了我也办不到，不管VC的优化手段是多么有效。在具体的平台上，在特定的操作系统中，不论多么强大的工具，最终还是要受到平台和系统本身的限制。大家应该知道这个悖论吧：上帝能否制造出一块他自己也举不起来的石头？</p>
<p>我也常常看到&#8220;MFC永远不会过时&#8221;或者&#8220;C++是不会灭亡的&#8221;这种发言。我理解发言人的心情，不过这种说法绝不客观。一种语言也好，一个Application Framework也罢，它们之所以有今天的地位，并不是纯粹自然形成的，有许多复杂因素的作用，也有时势造英雄的理由在内，所谓&#8220;居高声自远，非是籍秋风&#8221;是也。历史的舞台从来不是为某人专设，即使真有所谓万古长青的怪胎，恐怕也正应了那句老话：&#8220;众人都死了，只剩咱们两个老妖精，有什么意思！&#8221;我们现在使用的语言，不论Basic，Pascal还是C++，甚至如日中天的Java和C#，终究都会有功成身退的一天。这并不是我们的损失，相反，薪尽火传，一种语言中好的，合理的因素，肯定会被后续者所继承和发扬，自然界的新陈代谢本该如此。</p>
<p>天空没有飞翔的痕迹，而飞鸟已经飞过。一种语言只要曾经在历史上留下浓墨重彩的一笔，完成它&#8220;为先贤继圣学，为万世开太平&#8221;的历史使命（有点夸张），这就够了，何必缠绵不舍作儿女之态！不知道我有生之年会不会看到C++的消亡，如果真有这么一天，我会拍手欢呼，因为这说明已经有了另外一种更新更好的语言来代替它（或许是几种）。不过照我猜想，像C++这种轰动武林惊万教的语言，其灭亡恐怕也不会是悄无声息，而多半属于&#8220;始皇既没，余威震于殊俗&#8221;那种情况。</p>
<p>最后请允许我发表一点感慨。语言的优劣其实是一个无需讨论的问题，个人的经历和所处环境在很大程度上就决定了你对某种语言的看法，这是很个人的东西。好比碰到一位法国朋友，他多半会自豪的告诉你：法语是世界上最好最优美的语言。对这种说法我会微笑表示赞同，并且欣赏他的民族自豪感，而不会觉得这是对汉语或者英语的贬低—虽然我心底里一直深信，汉语才是世界上最好的语言。当然，如果他对我说&#8220;你们那些破烂中文是些什么玩意&#8221;，那我可能就是另外一种反应了。</p>
<p>说了这么多，意思无非是想少些无谓的争论罢了。常在论坛上看到&#8220;XXX是最好的语言(编译器)，XX是什么东西&#8221;之类发言。我不想和他们争论，一个人对一样东西既然完全失去了接触和了解的兴趣，那么说什么大概都没有用了。只是觉得遗憾而已。人世间的隔膜与误会，大多是由于彼此不了解而引起，而多少悲剧正是由此而发生呵。在编程的世界里大概不会这么严重，不过言为心声，多少也可看出个人的品行。如果某个人A常在我面前说B的坏话，那么我对B不会有恶感，相反我对A的印象分要减去20。自己不了解的人或者事，不管，不说，也就是了。何至于恶言相加呢。</p>
<p>我参加工作的时间不长，各种各样的软件工程师倒是见过不少。就我看到的情况，程序员实在是很沉默寡言的一类人，平时总是表现的温文尔雅，有时候却难得的能见到他们大发脾气，扔鼠标，砸键盘，捶显示器，干什么的都有（这种情况多半是遇到没有办法除掉的Bug了）。面对亲人和朋友的时候他们有时候会选择长久的沉默，只有坐到机器前面时才会发现他们的痴迷和狂热。虽然普遍的不善言谈，但是他们似乎总能在游戏或者网络中找到发泄的方式。所以我在各种各样的论坛上看到语法错误不忍卒读的文字，看到互相指责乃至于人身攻击的情况，甚至看到许多不雅的词汇，虽然心情无论如何愉快不起来，但是我想我能理解。只是，我仍然感到担心，毕竟程序员这一行干几年就了不起了，而人生还有很长的路要走呢。没有一个健全的心态，没有足够为人处世的技巧，30岁以后的人生该如何把握呢？</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/7958.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-05-31 17:24 <a href="http://www.cppblog.com/andxie99/archive/2006/05/31/7958.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>