<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[我是程序员   -Shosh's Blog - 程序开发]]></title>
<link>http://www.wscxy.com/shosh/</link>
<description><![CDATA[]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[shosh.zhu@qisda.com(shosh)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>我是程序员   -Shosh&#39;s Blog</title>
	<url>http://www.wscxy.com/shosh/images/logos.gif</url>
	<link>http://www.wscxy.com/shosh/</link>
	<description>我是程序员   -Shosh&#39;s Blog</description>
</image>

			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=130</link>
			<title><![CDATA[代码排版中的缩进和行长]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Sun,25 Apr 2010 23:32:56 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=130</guid>
		<description><![CDATA[大家都知道，代码的排版虽然不影响代码的编译和程序的运行，但是对于开发人员来说，它同样很重要。当我们看到排版整齐质量又高的代码的时候，我们会像欣赏艺术品一样去欣赏它，而如果代码排版混乱，哪怕思想再好的代码也会让你看了心烦。本文主要和大家探讨一下代码排版中的缩进和行长问题。<br/><br/>代码的缩进主要使用两个字符：tab键的缩进（\t）和空格。而对于到底使用tab还是空格，目前基本上没有形成统一的说法。使用tab的好处是需要缩进的时候，程序员只要敲一下tab键即可，而且多数程序员（包括我）都比较习惯使用tab。缺点是：tab的宽度是可变的。正常情况下，一个tab的长度是8个普通字符的宽度，而习惯上，我们认为用4个普通字符的宽度作为tab的长度是比较理想的，大多数代码编辑器都可以设定tab的长度。而空格除了缩进比较麻烦（得敲多个空格键），在对齐上比较容易。<br/><br/>另外还有一个问题，如果使用tab，在不同的编辑下显示的效果不同。比如在VC下排版得很好，可是用source insight或者Clear Case里的Merge工具打开，发现排列不整齐了。这个事情真的很头疼，所以有人（公司）就直接规定不许使用tab，只使用空格缩进。不过这样做对开发者来说确实是烦人的事情。<br/><br/>本文提供一个想法，即要有tab缩进的便利性，又要不影响对齐。方法如下：<br/>1、行首的缩进统一使用tab，不能使用空格代替（这样不过设置tab的宽度是多少，都能对齐）<br/>2、有效代码开始后如果还想缩进对齐（如变量的类型和变量名直接），不要使用tab，而使用空格。例如：<br/>typedef struct<br/>{<br/>\tint\s\s\s\s\s\s\s\smember1;<br/>\tfloat\s\s\s\s\s\s\smember2;<br/>} typeName;<br/><br/>int function()<br/>{<br/>\tint\s\s\s\s\s\s\s\s\s\sa;<br/>\tmydefinedtype\s\s\sbbb;<br/>}<br/>上面的\t表示tab缩进，\s表示空格。如果使用等宽的字体，不管\t用几个字符的宽度，上面的代码都能对齐。<br/><br/>对你常用的代码编辑器做如下设置：<br/>1、将代码编辑器的字体设置为等宽字体，如Courier New或比较经典的Fixedsys<br/>2、将代码编辑器的缩进宽度设为4个字节（可选）<br/><br/>这样你的代码就能够时刻对齐了。<br/><br/>再来说说行长的问题：<br/>很多文章或编程书籍都推荐代码一行的长度不要超过80（有的也说75）个字符，如果超过就需要换行，然后说了一堆换行的规则。他们说的换行规则我都赞同，不过我觉得一行不超过80个字符这一条可以改改了。<br/>为什么他们推荐一行的长度不超过80个字符？我想主要有以下几点原因：<br/>1、如果将代码打印，太长的代码会打印不下。<br/>2、这个说法应该在很早的时候就提出来的了，当时的显示器和现在的没法比，当时的显示器分辨率可能只有800*600，甚至只有640*480，如果代码写得太长就会出现水平滚动条，这样很麻烦。<br/>不过对于现在的我们来说：<br/>1、我们的代码基本上不会用来打印，最多放到网页上。<br/>2、我们现在的显示器分辨率比较高，甚至有很多宽屏的，最小的水平分辨率也能达到1024个像素。<br/>我们编写的代码首先应该考虑让自己写得顺手，自己看到舒服，其次再是如果在别人的机器上，别人看你的代码的时候，他们也能看得很舒服，最后再考虑如果放到网页上会显示成什么样。<br/><br/>所以我想说的是：我们不用太去在意80个字符长度的约定，我们可以适当加长。不然老是看到一句代码分成好几行，也不会感觉太美观。<br/><br/>以上只是我个人的看法，没有所谓的对与错，适合自己的就是最好的，不用去管太多的陈旧的条条框框。]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=127</link>
			<title><![CDATA[copydir.bat: 拷贝目录及各级子目录下的文件到一个目录的工具]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Sun,14 Mar 2010 20:55:18 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=127</guid>
		<description><![CDATA[<p>背景：工作中，UI工程师提供图片资源是分目录放置的，可是提交给CM的时候却需要在一个目录下的，如果手动拷贝非常麻烦，而如果直接用COPY 或 XCOPY命令把文件从A目录拷贝到B目录，B目录还是会维持A目录的目录结构。昨天晚上手动写了一根批处理工具，正是用来解决该问题的。具体用法代码中也有，这里不赘述。</p>
<p>copydir.bat代码如下：</p>
<div id="shoCodeAreaWscxy">
<ol id="shoCodeMain43ID" class="shoCodeMain">
    <li id="scli"><span style="color: black">::&nbsp;Auther:&nbsp;Shosh</span></li>
    <li id="scli"><span style="color: black">::&nbsp;Site:&nbsp;&nbsp;http://www.wscxy.com</span></li>
    <li id="scli"><span style="color: black">::&nbsp;Date:&nbsp;&nbsp;2010.03.13</span></li>
    <li id="scli"><span style="color: black">::&nbsp;This&nbsp;bat&nbsp;copies&nbsp;all&nbsp;the&nbsp;files&nbsp;under&nbsp;a&nbsp;directory&nbsp;and&nbsp;all&nbsp;levels&nbsp;of&nbsp;subdirectories&nbsp;to&nbsp;another&nbsp;folder(no&nbsp;subfolder)</span></li>
    <li id="scli"><span style="color: black">@ECHO&nbsp;OFF</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">SET&nbsp;DefSrcRootDir=.</span></li>
    <li id="scli"><span style="color: black">SET&nbsp;DefDestDir=.</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">:FunBegin</span></li>
    <li id="scli"><span style="color: black">SET&nbsp;bConfirm=NO</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;&quot;%1&quot;&nbsp;==&nbsp;&quot;/?&quot;&nbsp;GOTO&nbsp;FunUsage</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">SET&nbsp;bHaveOption=FALSE</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;&quot;%1&quot;&nbsp;==&nbsp;&quot;/c&quot;&nbsp;SET&nbsp;bHaveOption=TRUE</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;&quot;%1&quot;&nbsp;==&nbsp;&quot;/C&quot;&nbsp;SET&nbsp;bHaveOption=TRUE</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;&quot;%1&quot;&nbsp;==&nbsp;&quot;-c&quot;&nbsp;SET&nbsp;bHaveOption=TRUE</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;&quot;%1&quot;&nbsp;==&nbsp;&quot;-C&quot;&nbsp;SET&nbsp;bHaveOption=TRUE</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;bHaveOption&nbsp;==&nbsp;TRUE&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;bConfirm=YES</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;&quot;%2&quot;&nbsp;==&nbsp;&quot;&quot;&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;srcRootDir=%DefSrcRootDir%</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;destDir=%DefDestDir%</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;ELSE&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;NOT&nbsp;&quot;%4&quot;&nbsp;==&nbsp;&quot;&quot;&nbsp;GOTO&nbsp;FunErrorUsing</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;srcRootDir=%2</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;destDir=%3</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)</span></li>
    <li id="scli"><span style="color: black">)&nbsp;ELSE&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;bConfirm=NO</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;&quot;%1&quot;&nbsp;==&nbsp;&quot;&quot;&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;srcRootDir=%DefSrcRootDir%</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;destDir=%DefDestDir%</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;ELSE&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;NOT&nbsp;&quot;%3&quot;&nbsp;==&nbsp;&quot;&quot;&nbsp;GOTO&nbsp;FunErrorUsing</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;srcRootDir=%1</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET&nbsp;destDir=%2</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)</span></li>
    <li id="scli"><span style="color: black">)</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;&quot;%destDir%&quot;&nbsp;==&nbsp;&quot;&quot;&nbsp;GOTO&nbsp;FunErrorUsing</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">::confirm&nbsp;settings</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;================================================================</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;&nbsp;&nbsp;Source&nbsp;Root&nbsp;Dir:&nbsp;%srcRootDir%</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Dest&nbsp;Dir:&nbsp;%destDir%</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;Overwrite&nbsp;Confirm:&nbsp;%bConfirm%</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;================================================================</span></li>
    <li id="scli"><span style="color: black">SET&nbsp;/P&nbsp;choice=Start&nbsp;executing?&nbsp;[Y/N]&nbsp;</span></li>
    <li id="scli"><span style="color: black">if&nbsp;NOT&nbsp;%choice%&nbsp;==&nbsp;Y&nbsp;(</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;NOT&nbsp;%choice%&nbsp;==&nbsp;y&nbsp;GOTO&nbsp;FunCancel</span></li>
    <li id="scli"><span style="color: black">)</span></li>
    <li id="scli"><span style="color: black">::check&nbsp;input&nbsp;directories&nbsp;settings</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;NOT&nbsp;EXIST&nbsp;%srcRootDir%&nbsp;ECHO&nbsp;[%srcRootDir%]&nbsp;not&nbsp;found!!!</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;NOT&nbsp;EXIST&nbsp;%destDir%&nbsp;ECHO&nbsp;[%destDir%]&nbsp;not&nbsp;found,&nbsp;we&nbsp;will&nbsp;create&nbsp;it.</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">::check&nbsp;source&nbsp;root&nbsp;dir&nbsp;before&nbsp;starting&nbsp;coping</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;NOT&nbsp;EXIST&nbsp;%srcRootDir%&nbsp;GOTO&nbsp;FunPause</span></li>
    <li id="scli"><span style="color: black">IF&nbsp;%bConfirm%&nbsp;==&nbsp;YES&nbsp;(</span></li>
    <li id="scli"><span style="color: black">::&nbsp;confirm&nbsp;overwriting</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FOR&nbsp;/R&nbsp;%srcRootDir%&nbsp;%%i&nbsp;IN&nbsp;(.)&nbsp;DO&nbsp;XCOPY&nbsp;&quot;%%i&quot;&nbsp;&quot;%destDir%&quot;&nbsp;/-Y&nbsp;/V&nbsp;/F&nbsp;/I&nbsp;/K</span></li>
    <li id="scli"><span style="color: black">)&nbsp;ELSE&nbsp;(</span></li>
    <li id="scli"><span style="color: black">::&nbsp;no&nbsp;confirm</span></li>
    <li id="scli"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FOR&nbsp;/R&nbsp;%srcRootDir%&nbsp;%%i&nbsp;IN&nbsp;(.)&nbsp;DO&nbsp;XCOPY&nbsp;&quot;%%i&quot;&nbsp;&quot;%destDir%&quot;&nbsp;/Y&nbsp;/V&nbsp;/F&nbsp;/I&nbsp;/K</span></li>
    <li id="scli"><span style="color: black">)</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;================================================================</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;Finish!!!&nbsp;</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;Thank&nbsp;you&nbsp;for&nbsp;using&nbsp;copydir.bat&nbsp;written&nbsp;by&nbsp;Shosh!!!</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;Welcome&nbsp;to&nbsp;visit&nbsp;my&nbsp;website&nbsp;http://www.wscxy.com</span></li>
    <li id="scli"><span style="color: black">GOTO&nbsp;FunPause</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">:FunErrorUsing</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;!!!&nbsp;Error&nbsp;using&nbsp;copydir.bat&nbsp;!!!</span></li>
    <li id="scli"><span style="color: black">GOTO&nbsp;FunUsage</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">:FunUsage</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;USAGE:&nbsp;&nbsp;&nbsp;&nbsp;copydir&nbsp;[/C]&nbsp;[source&nbsp;root&nbsp;dir]&nbsp;[dest&nbsp;dir]</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[/C]&nbsp;Confirm&nbsp;if&nbsp;a&nbsp;file&nbsp;needs&nbsp;overwriting.&nbsp;if&nbsp;not&nbsp;set,&nbsp;it&nbsp;will&nbsp;overwrite&nbsp;without&nbsp;confirm.</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;If&nbsp;set&nbsp;both&nbsp;src&nbsp;root&nbsp;dir&nbsp;and&nbsp;dest&nbsp;dir&nbsp;to&nbsp;.,&nbsp;that&nbsp;means&nbsp;all&nbsp;the&nbsp;files&nbsp;in&nbsp;all&nbsp;levels&nbsp;of&nbsp;subfolders&nbsp;will&nbsp;be&nbsp;copied&nbsp;to&nbsp;the&nbsp;current&nbsp;folder.</span></li>
    <li id="scli"><span style="color: black">goto&nbsp;FunPause</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">:FunCancel</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;You've&nbsp;canceled&nbsp;executing.</span></li>
    <li id="scli"><span style="color: black">GOTO&nbsp;FunPause</span></li>
    <li id="scli"><span style="color: black">&nbsp;</span></li>
    <li id="scli"><span style="color: black">:FunPause</span></li>
    <li id="scli"><span style="color: black">ECHO&nbsp;================================================================</span></li>
    <li id="scli"><span style="color: black">SET&nbsp;/P&nbsp;a=Press&nbsp;ENTER&nbsp;key&nbsp;to&nbsp;continue...&nbsp;</span></li>
</ol>
</div>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=113</link>
			<title><![CDATA[[转]Sidebar Gadget开发教程 ]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Tue,20 Oct 2009 11:57:16 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=113</guid>
		<description><![CDATA[<div>
<p>翻译了两篇Sidebar Gadget的文章后，决定自己写一个教程，与准备投身于Sidebar Gadget开发的劳苦大众们分享一下经验。也当作自己个人学习Gadget开发的一些总结，使自己可以学习得深入一些。欢迎大家就这一系列文章提出批评斧正。本部分准备介绍一些基础知识。</p>
<p><strong>关于SideBar</strong></p>
<p>SideBar是Windows Vista特有的一个显示子系统（曾经宣布为Windows XP以及Windows Server 2003也开发Sidebar，但该项目现已取消），在中文系统中称之为&ldquo;边栏&rdquo;。其执行程序，我们可以在以下目录中找到[SystemInstalledDriver:]\program files\Windows Sidebar，此文件夹 结构大体如右图所示，各文件夹以及文件的具体作用如下：</p>
<ul>
    <li>Sidebar.exe：此文件即Sidebar.exe的主执行文件，如果你在Windows Vista当中未打开边栏，可以直接执行该文件即打开。</li>
    <li>Sbdrop.dll：Sidebar拖抻支持文件;</li>
    <li>settings.ini: Sidebar设置文件，可以设置默认启动Gadget等特性。</li>
    <li>wlstrvc.dll: Weather Gadget(即显示天气的小工具）所依赖的ActiveXControl，显示RSS信息的Gadget所依赖的ActiveX控件是置身在System32目录下msfeeds.dll文件;</li>
    <li>en-us: 英文相关的资源文件;</li>
    <li>zh-CN:简体中文相关的资源文件;</li>
    <li>Gadgets文件夹:该文件夹中包括多个子文件夹，每个子文件夹均是Windows Vista默认自带的Gadgets解压后的形式。</li>
    <li>Shared Gadget：存储在此文件夹中的Gadget可以供同一机器上的多用户共同使用。</li>
</ul>
<p>而用户自行安装的Gadget可以在[SystemInstalledDriver:]\users\[user name]\appdata\local\microsoft\windows sidebar\gadgets\中查找到。</p>
<p><strong>关于Gadget</strong></p>
<p>在中文系统中，Gadget被翻译为&ldquo;小工具&rdquo;，微软的Gadget基本上分为三种，即Live Gadget、Sidebar Gadget以及Slideshow Gadget：</p>
<ul>
    <li>Live Gadget：如果大家访问<a href="http://www.live.com/"><font color="#810081">http://www.live.com</font></a>，会发现其页面可以进行自定义，而自定义的小型页面模块，我们称之为Live Gadget;</li>
    <li>Slideshow Gadget：Windows Vista支持未来的笔记本电脑除了主显示屏外，还可以有一个外置的小型显示屏，类似于双屏手机中外置显示屏，在不开电脑电源的情况下，从这个扩展显示屏上获取自己想要的信息，而实现这个功能的模块称之为Slideshow Gadget;</li>
    <li>Sidebar Gadget:本教程中所指的Gadget是此种，依赖于Windows Sidebar所执行的Gadget。</li>
</ul>
<p>另外，这三种Gadget目前的开发环境、执行环境以及开发方式均不统一，不能统用。至于未来规划，开心也不是非常清楚。有知道的可以在此透露一下。</p>
<p>其实Gadget本身非常简单，如果感兴趣，可以访问<a title="http://go.microsoft.com/fwlink/?LinkId=55696" href="http://go.microsoft.com/fwlink/?LinkId=55696"><font color="#810081">http://go.microsoft.com/fwlink/?LinkId=55696</font></a>，并且随意下载一个SideBar Gadget。把其另存在桌面上，比如那个计算器Gadget(<a href="http://gallery.microsoft.com/liveitemdetail.aspx?li=d6152b70-2908-4176-b491-610c4f538bd4&amp;l=1"><font color="#0000ff">Calculator</font></a>)。其后缀名为.gadget。我们现在把后缀名改为.zip，在Windows XP系统上可以双击打开，就会看到其目录结构。</p>
<p>也就是说，Gadget本身是包含一堆HTML、JavaScript、CSS以及图片文件一个压缩包，其压缩格式可以采用ZIP格式，也可以采用CAB格式。采用CAB格式，可以进行数字签名，参阅我上一篇<a href="http://blog.joycode.com/joy/archive/2006/10/24/85594.aspx" target="_blank"><font color="#0000ff">译文</font></a>。在这个Gadget中使用Gadget.xml这个文件来描述此Gadget的通用信息，如名称、作者、版本、是否有设置文件、图标等等。此文件可以放置在根目录中，也可以放置在不同语言文件夹中，如en-us或者zh-cn当中。</p>
<p>系统自带的Gadget大部分都使用了一些特别开发的ActiveX控件。我们自己开发的Gadget如果是想使用Microsoft Gadget Gallery（即<a title="http://go.microsoft.com/fwlink/?LinkId=55696" href="http://go.microsoft.com/fwlink/?LinkId=55696"><font color="#810081">http://go.microsoft.com/fwlink/?LinkId=55696</font></a>）方式或者后缀名为.gadget方式分发，那么只能调用系统中已有的ActiveX控件，而不能创建自己的ActiveX控件。如果你想自己制作可执行的安装文件包，那么你就可以为所欲为了（流氓软件???呵呵)。</p>
<p>Javascript可以调用的ActiveX控件也非常多，比如使用Scripting.FileSystemObject访问文件系统，使用Microsoft.XmlDom分析XML文件，使用Microsoft.XMLHTTP调用Web Service等。所以Gadget可以做很多事情。</p>
<p>那么可以做什么事情呢？这就得依赖于我们的头脑不断闪现的灵感火花了。</p>
<p>由于近期在努力学习Sidebar Gadget开发技术，并且也与<a title="中国汽车网" href="http://www.chinacars.com/"><font color="#0000ff">中国汽车网</font></a>合作做了一个Sidebar Gadget，所以耽误了一些时间，但同时，也通过这个机会加深了学习印象。</p>
<p>很多朋友在学习新技术的时候，都喜欢做Hello World。我原来也是这种情况。其实我认为这种方式有百害而无一利，就类似于学英语开始背单词一样，背了十多年，还没有背到F开头的单词呢。因为Hello world就让你产生了一种虚伪的成就感，而稍微一深入进去，遇到一点挫折，就会有畏难情绪，再也坚持不下去了。最后产生的结果无非就是眼高手低，或者眼低手低。</p>
<p>所以本教程我想使用一个实际项目开始，这个项目就是为<a title="中国汽车网" href="http://www.chinacars.com/" target="_blank"><font color="#0000ff">ChinaCars.com</font></a>开发一个小型的Gadget，要完成的主要功能如下：</p>
<ol>
    <li>根据你选择的城市以及价格区间，以幻灯片形式来显示符合条件的车型图片;</li>
    <li>图片切换可以实现Powerpoint中的那种幻灯片切换效果;</li>
    <li>点击某个车型图片，可以显示该车型的详细信息。</li>
</ol>
<p>功能需求很简单，但使用HTML+Javascript+CSS完成它，可能就需要时间了。因为：</p>
<ul>
    <li>开发Gadget没有一个IDE，无非所见即所得;</li>
    <li>无法进行Debug，只能写Track信息来追踪;</li>
    <li>资料比较少，只能看Windows Vista自带的Gadget源代码，或者去看<a title="Windows Vista Sidebar Gadget SDK" href="http://microsoftgadgets.com/build" target="_blank"><font color="#0000ff">SDK</font></a>；</li>
    <li>用ASP.NET时间久了，Javascript与HTML知识忘光光了。</li>
</ul>
<p>另外一点，<a title="中国汽车网" href="http://www.chinacars.com/" target="_blank"><font color="#0000ff">中国汽车网</font></a>没有提供API怎么办？不会让我自己来去分析HTML吧？没有关系，我把这个接口暴露给大家，大家可以自己尝试一下。使用<a title="API" href="http://gadgets.chinacars.com/Chinacars.Gadgets.Web/carpricequery.aspx?StartPrice=0&amp;endprice=100&amp;city=bj&amp;recordnumber=10" target="_blank"><font color="#0000ff">接口1</font></a>，你可以得到一个车型信息列表;使用<a title="API" href="http://gadgets.chinacars.com/Chinacars.Gadgets.Web/carpricequery.aspx?StartPrice=0&amp;endprice=100&amp;city=bj&amp;recordnumber=10" target="_blank"><font color="#0000ff">接口2</font></a>，你可以得到一个车型详细信息的RSS。简单吧？具体参数的使用说明，自己多试几下就知道了。</p>
<p>那么建立远程HTTP连接呢？在.NET中我们还有HttpRequest来使用，在Javascript中，我们就只能使用Microsoft.XmlHTTP这个ActiveX对象了，不过也非常好用，而且像异步呀、状态信息呀都一个不少的实现了。分析XML也不必使用XmlDocument这个.NET类，你完全可以使用Microsoft.XmlDom这个ActiveX对象。</p>
<p>我的Gadget其实已经完成了，现在来考考大家了。虽然我平常工作比较忙，但仍然使用三个晚上的时间完成了这部分代码。那么我留出一周的时间，如果大家感兴趣，先自己试着开发一下。一周后，我会公布我的源代码给大家的。如果您在一周内完成了，欢迎打包成.gadget文件，通过<a href="http://www.wscxy.com/shosh/mailto:joycode@gmail.com" rel="邮件信息"><font color="#0000ff">邮件</font></a>发送给我，说不定会有神秘礼品呢。</p>
<p>另外，也号召一下各网站的开发高手，发挥你的创意，为你的网站增加Gadget。抢占完用户的桌面，霸占了用户的IE，现在到了抢占用户Sidebar的时候了！让客户接受你，你就要有好的创意。如果贵网站在国内按流量综合排名在前一百以上，或者是比较酷的网站，有应用Gadget的好创意的话，也可以与<a href="http://www.wscxy.com/shosh/mailto:joycode@gmail.com"><font color="#0000ff">我联系</font></a>。Microsoft将会选择一部分网站做相关的市场活动。</p>
<p>BTW: 如果您的公司在开发类似于Forums、Blog等相关Web通用系统的话，如果想应用Gadget，或者想迁移到ASP.NET，或者想与Microsoft作一系列的市场活动，也可以与我<a href="http://www.wscxy.com/shosh/mailto:joycode@gmail.com"><font color="#0000ff">联系</font></a>。(曾经给Discuz!发过一封邮件，但石沉大海)</p>
<p>BTW Again: 如果贵公司或者个人精通Gadget，Expression，AJAX，Card Space，也可以与我<a href="http://www.wscxy.com/shosh/mailto:joycode@gmail.com"><font color="#0000ff">联系</font></a>。我们需要合作伙伴，帮助我们的客户进行培训与实施，并且支付相关费用。</p>
<p>话说<a href="http://blog.joycode.com/joy/archive/2006/10/24/85611.aspx" target="_blank"><font color="#0000ff">从前</font></a>，书接<a href="http://blog.joycode.com/joy/archive/2006/11/01/86016.aspx" target="_blank"><font color="#0000ff">上回</font></a>。开心已经向大家提出了一个需求，并且给出解决技术难题的思路，不知道有多少位朋友已经开始尝试编写自己的第一个非&ldquo;Hello World&rdquo;的Sidebar Gadget了。那么今天开始，我们就开始逐步介绍开发Sidebar Gadget的具体方式。</p>
<p><strong>使用Gadget.xml来定义Sidebar Gadget</strong></p>
<p>就像计算机语言都会有一个入口函数一样，Sidebar Gadget在启动时也会有一个主入口，而这个主入口文件呢就是Gadget.xml。但该文件你可以存放在多个区域，即Gadget的根目录，或者Gadget的地区语言(如zh-cn, en-us等)目录。按照我的理解，Gadget应该先会找最适合地区语言目录下的Gadget.xml，其次再找根目录中gadget.xml，而一个典型的Gadget.xml文件结构如下所示（Vista自带的时钟Gadget的描述文件，文档中红色文字为开心的注释文字，而注释中的数字标识与附图中的数字标识一一对应）：</p>
<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br />
&lt;gadget&gt;<br />
&lt;name&gt;时钟&lt;/name&gt;&nbsp;<font color="#ff0000">定义Gadget名称(1)</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&lt;namespace&gt;microsoft.windows&lt;/namespace&gt;<font color="#ff0000"> 定义Gadget的命名空间，与JS交互</font><br />
&lt;version&gt;1.0.0.0&lt;/version&gt; <font color="#ff0000">版本信息(2)</font><br />
&lt;author name=&quot;Microsoft Corporation&quot;&gt; <font color="#ff0000">作者信息(3)</font><br />
&lt;info url=&quot;<a href="http://go.microsoft.com/fwlink/?LinkId=55696&quot;"><font color="#0000ff">http://go.microsoft.com/fwlink/?LinkId=55696&quot;</font></a> text=&quot;www.gallery.microsoft.com&quot;/&gt; <font color="#ff0000">作者网站的链接地址<a href="http://blog.joycode.com/images/blog.joycode.com/joy/1308/o_WindowsLiveWriter_SidebarGadget3_1301E_image018.png" atomicselection="true"><img border="0" align="right" src="http://blog.joycode.com/images/blog.joycode.com/joy/1308/o_WindowsLiveWriter_SidebarGadget3_1301E_image0_thumb14.png" width="506" height="353" style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" alt="" /></a>(4)</font><br />
&lt;logo src=&quot;logo.png&quot;/&gt;<font color="#ff0000">作者的Logo信息(5)</font><br />
&lt;/author&gt;<br />
&lt;copyright&gt;? 2006&lt;/copyright&gt; <font color="#ff0000">版权信息(6)</font><br />
&lt;description&gt;查看您所在时区或全球任何城市的时钟。&lt;/description&gt; <font color="#ff0000">功能描述信息(7)</font><br />
&lt;icons&gt;<br />
&lt;icon height=&quot;48&quot; width=&quot;48&quot; src=&quot;icon.png&quot;/&gt; <font color="#ff0000">显示在小工具待选箱时的图标(8)</font><br />
&lt;/icons&gt;<br />
&lt;hosts&gt;<br />
&lt;host name=&quot;sidebar&quot;&gt;<font color="#ff0000">仅支持Sidebar，未来如果大一统了，可能Live.com或者Slideshow都会使用统一的方式</font><br />
&lt;base type=&quot;html&quot; apiVersion=&quot;1.0.0&quot; src=&quot;clock.html&quot;/&gt;<font color="#ff0000">type仅支持html，未来有可能会支持WPF,WPF/E或者AJAX;src用以指明主界面的HTML源文件</font><br />
&lt;permissions&gt;full&lt;/permissions&gt;<font color="#ff0000">目前仅可以设置Full，请参阅</font><a href="http://blog.joycode.com/joy/archive/2006/10/24/85594.aspx" target="_blank"><font color="#ff0000">此文</font></a><br />
&lt;platform minPlatformVersion=&quot;1.0&quot;/&gt;<br />
&lt;defaultImage src=&quot;drag.png&quot;/&gt;<font color="#ff0000">在从小工具备选箱用鼠标拖到Sidebar时所显示的Logo</font><br />
&lt;/host&gt;<br />
&lt;/hosts&gt;<br />
&lt;/gadget&gt;</p>
<p><a href="http://blog.joycode.com/images/blog.joycode.com/joy/1308/o_WindowsLiveWriter_SidebarGadget3_1301E_image019.png" atomicselection="true"><img border="0" align="left" src="http://blog.joycode.com/images/blog.joycode.com/joy/1308/o_WindowsLiveWriter_SidebarGadget3_1301E_image0_thumb15.png" width="180" height="190" style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" alt="" /></a>&nbsp;通过上面的信息，Sidebar可以得到Gadget中的相关信息，但一个Gadget还不止如此，比如上面的这个时钟显示在Sidebar当中时，应该如 左图所示。在这个截图中，我们注意到有一个小扳手式的图标，使用它可以选择自己心爱的钟表外型或者进行其它的自定义设置，那么此部分是如何反应在源代码中的？</p>
<p>还有，有一些Gadget，比如自带的RSS Reader，当单击某文章标题时，会自动在左侧弹出来一个Flyout窗口，这个窗口的设置如何在源代码中反应呢？</p>
<p>还有，系统自带的那个CPU以及内存使用量的Gadget，类似于汽车的转速表，它又是如何得到这种实时的系统信息的呢？</p>
<p>还有，当把一个Gadget从Sidebar拖到桌面时，其页面大小会发生改变，这又是为什么呢？</p>
<p>还有，Gadget中有很多透明效果，比如那个表的周围就是透明的，呈一个圆形，或者其它类型，而不是我们常见网页的矩形，这又是为什么呢？</p>
<p>还有，Gadget中的服务器端与客户端交互实现局部刷新却又没有使用ASP.NET AJAX框架，这又是为什么呢？</p>
<p>呵呵，如果你感兴趣，欢迎继续阅读本教程，今天就先到这儿吧。</p>
<p>今天继续讲Sidebar Gadget的开发。此篇将是本教程的最后一篇，因为了解了Gadget的大体情况后，接下来就需要大家自己进行练习了。只有勤于练习，而不是安心看教程，你才会积累丰富的开发经验。而且有些细节其实只需要点一下即可，不需要再详述。</p>
<p>从两周前开始，我们面对两个Partner进行了Gadget开发的Workshop。并且每个Partner均讲述了真实的Requirement，进行Job training。目前来看，这种效果非常不错，建议各位也可以在工作中进行学习。</p>
<p>在上一节<a href="http://blog.joycode.com/joy/archive/2006/11/04/86110.aspx" target="_blank"><font color="#810081">教程</font></a>当中，我们在最后给出了几个问题。现在一一回答该问题。</p>
<ul>
    <li>Gadget当中如何含有设置界面？即那个类似于小板手似的图标？</li>
</ul>
<p><em>其实这个问题的答案很简单，只需要在主界面所关联的Javascript中加入一句：System.Gadget.settingsUI = &quot;<u>settings.htm&quot;</u>;即可，该语句中的<u>settings.htm</u>可以取代为其它名字.</em></p>
<ul>
    <li>如何使Gadget出现Flyout界面？</li>
</ul>
<p><em>这个问题如上所示，只需要加一句：System.Gadget.Flyout.file=&quot;<u>flyout.htm</u>&quot; 即可，同理，此句中的<u>flyout.htm</u>也可以换成其它的文件名。在需要显示Flyout界面时（比如某个超链接点击事件，或者某个图片控件的双击事件），调用System.Gadget.Flyout.show=true即可，不需要其它设置。当然，你可以在显示时进行一些其它的处理，那么可以调用它的事件函数即System.Gadget.Flyout.onShow(指向一个函数名），其对应的隐藏事件函数为System.Gadget.Flyout.onHide函数</em></p>
<ul>
    <li>如何得到系统信息？</li>
</ul>
<p><em>Sidebar为Javascript扩充了一些API，用于执行外部命令，或者得到系统信息，或者对于Gadget内部本身的调用（如上面的Flyout以及SettingsUI），关于这些API的详细信息，可以参阅：</em><a title="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sidebar/sidebar/reference/refs.asp" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sidebar/sidebar/reference/refs.asp" target="_blank"><em><font color="#0000ff">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sidebar/sidebar/reference/refs.asp</font></em></a><em>&nbsp;得到更加详细的信息。</em></p>
<ul>
    <li>如何在没有使用ASP.NET AJAX框架的基础上出现局部刷新效果？</li>
</ul>
<p><em>更加简单了，使用Microsoft XMLHTTP这个函数的异步调用方式，关于XMLHTTP的更加详细信息，可以参阅<a href="http://search.live.com/results.aspx?q=XMLHttp&amp;src=IE-SearchBox" target="_blank"><font color="#0000ff">相关信息</font></a>。其中有关于如何实现异步调用的。另外，在调用时，如果遇到IE缓存问题，可以使用setRequestHeader(&quot;If-Modified-Since&quot;,&quot;0&quot;)方式解决（感谢Symbio提供信息），而分析XML，可以使用Microsoft XMLDom来进行。</em></p>
<ul>
    <li>有些Gadget当置放在Sidebar上显示样式是一种，而拖到桌面上会有另外一种显示方式，这是如何实现的？</li>
</ul>
<p><em>这个更简单了，查看了下这些Gadget的源代码，可以知道，通过Gadget的System.Gadget.docked的属性可以得到其是否放置在Sidebar上（当为True时，是在Sidebar上），然后再调用JS来对于其CSS特性进行更改即可。</em></p>
<p><em>好了，Sidebar Gadget的教程到此结束。非常感谢大家。:)</em></p>
</div>
<p>&nbsp;</p>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=105</link>
			<title><![CDATA[正则表达式工具更新，支持使用替换函数]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Thu,06 Aug 2009 00:02:28 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=105</guid>
		<description><![CDATA[<h3 style="text-align: left"><a target="_blank" href="http://www.wscxy.com/shosh/shoWorks/RegExp/shoRegExpTool.htm"><span style="color: #0000ff">打开工具进行测试或使用 Have a try!</span></a></h3>
<p><strong>最新工具界面：</strong></p>
<p><img alt="" style="border-bottom: black 1px solid; border-left: black 1px solid; border-top: black 1px solid; border-right: black 1px solid" src="http://www.wscxy.com/shosh/shoWorks/RegExp/preview090808.jpg" /></p>
<p><strong>使用说明：</strong></p>
<p><img alt="" width="748" height="676" style="border-bottom: black 1px solid; border-left: black 1px solid; border-top: black 1px solid; border-right: black 1px solid" src="http://www.wscxy.com/shosh/shoWorks/RegExp/shoRegExpIntro.jpg" /></p>
<p>了解JavaScript字符串替换函数和正则表达式的朋友清楚，在JavaScript中，替换字符串一般使用下面的两种方法：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringObj.replace(RegExp, RepString);<br />
或<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringObj.replace(RegExp, RegFunction);<br />
其中：<br />
StringObj为代处理文本对象，也就是图中最上方多行文本框中的内容；<br />
RegExp是正则对象，对应于图中1和5的组合，这个待会会继续介绍；<br />
RegString是用来替换匹配到的字符串的字符串，对应图中的2；<br />
RegFunction是负责的替换方法，它使用函数作为replace的第二个参数，函数体正是对应图中3的部分（使用该方法的朋友需要了解JavaScript的使用和Replace的方法）；<br />
RegString和RegFunction对应于Replace的两种方法，可以通过图中的4按钮进行切换。</p>
<p>正则表达式对象的构造方方法为：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var exp = new RegExp(strPattern, strMode);<br />
其中：<br />
strPattern正是图中1的内容，用来指定该正则是用来查找什么样的内容的；<br />
strMode正是图中5的3个复选框的组合，用来指定匹配模式【是否忽略大小写、是否全局查找、是否多行查找，其中多行查找主要针对匹配指定开始位置（最前面使用^）或末尾位置（最后面使用$）的正则】</p>
<p>图中的例子是对代码（待处理文本，是Java代码）进行词法分析，使用替换函数的方法，结果将输出匹配出的Token的索引，并将其转化为大写。</p>
<p>如果需要了解更多，请查阅JavaScript中的Replace函数和正则表达式的使用。</p>
<p><strong>兴趣测试：</strong></p>
<p>1、在&ldquo;查询表达式&rdquo;中输入<span style="color: #000080"> <strong>\w+(?=\s*)</strong></span><strong> </strong>，并选中高亮匹配复选框，然后在最上面的文本输入区域输入一段英语。</p>
<p><strong>更新记录：</strong></p>
<p>Author: shosh<br />
Site: http://www.wscxy.com<br />
QQ:&nbsp; 124727276<br />
09/08/08.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、增加显示子匹配功能<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、高亮不可见但是可选中字符\r<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、修正一个很隐含的选中功能的BUG，选中区域有可能包含字符\n，但是不能把\n计算到长度中，否则下一次选择会偏移过多<br />
09/08/07.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、增加高亮匹配功能，使用3个区分，且有总开关控制<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、修正非全局模式下的匹配次数计算错误（match[1-n]为子匹配）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、增加替换函数输入区域的水平滚动功能，并有开关控制<br />
09/08/06.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、增强对替换函数的错误捕捉功能，并使前期检查忽略函数参数个数相关的错误<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、防止对替换函数的语法预检查时出现alert,prompt,comfirm等对话框<br />
09/08/05.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、允许输入Tab<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、允许使用函数替换， 并做了防错处理，会提示错误描述<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 已知BUG:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、循环查找的替换函数中的obj为选中的字符串，而非原来的字符串，pos也是相对与选中的字符串（往往是0），直接替换和预览替换结果不会有这个BUG。这个是循环（单个）查找原理所致，无法修正。<br />
09/07/08.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、修正HTML代码的正确预览的Bug，同时为修正该Bug，顺便让&ldquo;计算匹配次数&rdquo;下的分隔符使用黑色粗体（本来无法指定颜色），这样分隔符更加显眼<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、允许输入框中或替换后中出现的HTML转义字符按照转义前预览，如&amp;nbsp; 在预览是显示为&amp;nbsp;而不是' ' 或 '[ES]'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、添加单个替换功能<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4、允许用户选择预览方式<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5、添加更新说明，所以之前的更新记录不全<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不足：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、无法以特殊方法（如字体颜色、加粗等）显示预览中的替换内容（按照目前的设计，似乎无法实现）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、无法在使用单个替换功能后继续循环查找和单个替换，必须重新开始（如果不重新开始肯定会有bug，因为源改变后，匹配情况随之发生改变，所以基本上也没有解决办法的）<br />
09/07/07.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、已经可以让查询表达式输入框以及替换表达式和直接在代码中构造的字符串具有同等的效果（主要考虑某些特殊字符的问题，如\n\n\\等）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、已经有两种预览显示方式，其中不可见字符已经使用一定颜色的字符串代替<br />
09/07/03.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、初始版本，实现基本功能，但是对于特殊字符的处理尚未考虑</p>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=104</link>
			<title><![CDATA[java工程差异比较]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Wed,05 Aug 2009 17:28:55 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=104</guid>
		<description><![CDATA[<div>最近接到一个任务，需要比较出前后两个版本的Android工程Framework中类及API的变化情况。</div>
<div>我设计的步骤为：</div>
<ol>
    <li>找出新增的所有Java文件</li>
    <li>找出少掉的所有Java文件</li>
    <li>找出两个版本的工程都有但是有差异的所有Java文件（Rule based）</li>
    <li>使用JavaDoc分别为新增的所有Java文件和少掉的所有Java文件生成帮助文档</li>
    <li>对于有改动的Java文件，先对两个版本的工程使用一特定工具分别将所有相关Java文件中的类结构提取出来，分别保存到一文本文件中，然后使用Beyond Compare对生成的两个文本文件进行比较，即可很明显地看出变化。</li>
</ol>
<div>&nbsp;</div>
<div>要完成第5步，先要编写代码能够提取出类、接口和方法，于是就诞生了个工具：java文件类结构提取工具&mdash;&mdash;它把类或接口以及公共和静态方法提取出来，并保持它们之间的原有关系。完成这样的代码之后，再使用这部分代码，使用遍历目录文件的方式，将所有符合条件的文件（指java文件）中的类、接口和方法提取出来，都保存到同一个文本文件中。这两个工具都是使用javascript实现的。而第二个工具因为涉及到文件操作，所以最好先保存到本地，然后把扩展名改为hta（如果操作系统是windows的话）再运行。</div>
<p>产生的两个工具：<br />
&nbsp;</p>
<ul>
    <li><a target="_blank" href="http://www.wscxy.com/shosh/shoWorks/JavaStruct/shoJavaStruct.htm">Java类结构分析工具</a> 【<a target="_blank" href="http://www.wscxy.com/shosh/shoWorks/JavaStruct/output.txt">输出例子</a>】</li>
    <li>目录中Java文件分析工具<br />
    【<a target="_blank" href="http://www.wscxy.com/shosh/shoWorks/JavaStruct/AlalyzeJavasInFolder.hta">hta格式版，下载过去后修改分析目录再运行</a>（也可直接选择运行）】<br />
    【<a target="_blank" href="http://www.wscxy.com/shosh/shoWorks/JavaStruct/AlalyzeJavasInFolder.htm">HTML版（不过因为涉及文件操作权限问题，故运行会失败）</a>】</li>
</ul>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=96</link>
			<title><![CDATA[如何让程序开发又快又好]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Thu,12 Mar 2009 11:49:06 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=96</guid>
		<description><![CDATA[<p>注意代码的质量，尽量在设计的时候就能够站在整体的高度来找到一条简便可行的方向，在编写的时候注意检查改进，可以节约很多成本。下文转载自：&nbsp;<br />
<br />
文章出处：http://www.limodev.cn/blog&nbsp;作者联系方式：李先静&nbsp;&lt;xianjimli&nbsp;at&nbsp;hotmail&nbsp;dot&nbsp;com&gt;&nbsp;<br />
<br />
<font color="#4b0082">-----------------------------------</font><br />
<br />
&ldquo;快&rdquo;是指开发效率高，&ldquo;好&rdquo;是指软件质量高。呵呵，写得又快又好的人就是高手了。记得这是林锐博士下的定义，读他那篇著名的《C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>高质量编程》时，我还是个初学者，印象特别深。我现在仍然赞同他的观点，不过这里标题改为成为高手的秘诀，感觉就有点像标题党了，所以还是用比较通俗的说法吧。废话少说，请读者回顾一下这段时间的编程经验，回答下面两个问题：&nbsp;<br />
<br />
<font color="#ff0000">1</font><font color="#4b0082">.</font>快与好是什么关系？写得快就不能写得好？写得好就不能写得快？还是写得好才能写得快？是不是绕晕了？不过这确实是值得思考的问题。&nbsp;<br />
<br />
<font color="#ff0000">2</font><font color="#4b0082">.</font>我们的时间花在哪里了？记得刚来深圳时到华为面试，面试的人是我的学长。他问我，你一天能写多少行代码？我想了想说，<font color="#ff0000">100</font>行吧。他用看外行的眼光看着我说，能写<font color="#ff0000">100</font>行吗？我知道说错话了，赶快补充说，嗯，从整个项目来看可能没有吧。他才点了点头。一天只写<font color="#ff0000">100</font>行代码？初学者可能觉得不可思议，以同时应付<font color="#ff0000">10</font>个网友聊天的速度，写<font color="#ff0000">100</font>行代码不用三分钟。不过，经过这段时间的练习后，我们想大家已经明白，敲代码不是花时间最多的地方，那时间又花到哪里去了呢？&nbsp;<br />
<br />
<font color="#4b0082">-----------------------------------</font><br />
<br />
代码阅读法&nbsp;<br />
<br />
软件工程实践已经证明Code&nbsp;Review是提高代码质量最有效的手段之一，极限编程<font color="#800080"><b>(</b></font>XP<font color="#800080"><b>)</b></font>更是把Code&nbsp;Review推向极致，形成著名的结对编程工作方式，两个程序员在一台电脑前面工作，一个人编写程序，另一个Review输入每一行代码，写程序人的专注于目前细节上的工作，Review的人同时要从高层次考虑如何改进代码质量，两个人的角色会经常互换。&nbsp;<br />
<br />
可惜我即没有结对编程的经验，也没有在CMM3<font color="#800080"><b>(</b></font>及以上<font color="#800080"><b>)</b></font>团队中工作过。不过现在我要介绍比结对编程更敏捷更轻量级，但是同样有效的Review方法。这种方法不需要其他程序员配合，有你自己就够了。为了把这种方法与传统的Code&nbsp;Review区分开来，我把它称为代码阅读法吧。&nbsp;<br />
<br />
很多初学者包括一些有经验的程序员，在敲完代码的最后一个字符后，马上开始编译和运行，迫不急待的想看到自己的工作成果。快速反馈有助于满足自己的成就感，但是同时也会带来一些问题：&nbsp;<br />
<br />
让编译器帮你检查语法错误可以省些时间，但程序员往往太专注这些错误了，以为改完这些错误就万事大吉了。其实不然，很多错误编译器是发现不了的，像内存错误和线程死锁等等，这些错误可能逃过简单的测试而遗留在代码中，直到集成测试或者软件发布之后才暴露出来，那时就要花更大代价去修改它们了。&nbsp;<br />
<br />
修改完编译错误之后就是运行程序了，运行起来有错误，就轮到调试器上场了。花了不少时间去调试，发现无非是些低级错误，或许你会自责自己粗心大意，但是下次可能还是犯同样的错误。更严重的是这种debug&nbsp;<font color="#4b0082">&amp;</font>&nbsp;fix的方法，往往是头痛医头脚痛医脚，导致低质量的软件。&nbsp;<br />
<br />
让编译器帮你检查语法错误，让调试器帮你查BUG，这是天经地义的事，但这确实是又慢又烂的方法。就像你要到离家东边<font color="#ff0000">1000</font>米的地方开会，结果你往西边走，又是坐车又是搭飞机，花了一周时间，也绕着地球转了一周，终于到了会议室，你还大发感慨说，现代的交通工具真是发达啊。其实你往东走，走路也只要十多分钟就到了。不管你的调试技巧有多高，都不如一次性写好更高效。&nbsp;<br />
<br />
我以前也一样，想赶时间结果花了更多时间，在经过很多痛苦的经历之后，我开始学会放松自己，让自己慢下来。写完程序之后，我会花些时间去阅读它，一遍两遍甚至多遍之后，才开始编译它，只要有时间，在通过测试之后，我还会阅读它们，每读一遍都有不同的收获，有时候会发现一些错误，有时候会做些改进，有时候也有新的想法。&nbsp;<br />
<br />
下面是我在阅读自己代码时的一些方法：&nbsp;<br />
<br />
o检查常见错误。&nbsp;<br />
<br />
第一遍阅读时主要关注语法错误、代码排版和命名规则等等问题，只要看不顺眼就修改它们。读完之后，你的代码很少有低级错误，看起来也比较干净清爽。第二遍重点关注常见编程错误，比如内存泄露和可能的越界访问，变量没有初始化，函数忘记返回值等等，在后面的章节中，我会介绍这些常见错误，避免这些错误可以为你省大量的时间。如果有时间，在测试完成之后，还可以考虑是否有更好的实现方法，甚至尝试重新去实现它们。说了读者可能不相信，在学习编程的前几年，我经常重写整个模块，只我觉得能做得更好，能验证我的一些想法，或提高我的编程能力，即使连续几天加班到晚上十一点，我也要重写它们。&nbsp;<br />
<br />
o模拟计算机执行。&nbsp;<br />
<br />
常见错误是比较死的东西，按照检查列表一条一条的做就行了。有些逻辑通常不是这么直观的，这时可以自己模拟计算机去执行，假想你自己是计算机，读入这些代码时你会怎么处理。这种方法能有效的完善我们的思路，考虑不同的输入数据，各种边界值，这能帮助我们想到一些没有处理的情况，让程序的逻辑更严谨。&nbsp;<br />
<br />
o假想讲给朋友听。&nbsp;<br />
<br />
据说在Code&nbsp;Review时发现错误的，往往不是Review的人而是程序员自己。我也有很多这样的经历，在讲给别人听的时候，别人还没有听明白，自己已经发现里面存在的错误了。上大学时，我常常把写的或者学到的东西讲给隔壁寝室的一个同学听，他说他从我这里学到很多知识，其实我从讲的过程中，经常发现一些问题，对提高自己的能力大有帮助。可惜并不是随时都能找到好的听众，幸好我们有另外一个替代办法，记得刚开始写程序时看过一本书<font color="#800080"><b>(</b></font>忘记名字了<font color="#800080"><b>)</b></font>，作者说他在写程序时，常常把思路讲给他的布娃娃听。我没有布娃娃当听众，讲给鼠标听总是有点怪怪的，所以就假想旁边有个朋友，我把自己的思路讲给他听，同时也假想他来质疑我。这种方法很效，能够让自己的思路更清晰，据说一些大师也经常使用这种方法。&nbsp;<br />
<br />
这种代码阅读法会花你一些时间，但是可以省下更多调试时间，而且能够提高代码质量，可以说是名符其实的&ldquo;又快又好的&rdquo;&nbsp;秘诀之一。至于读几遍合适，要根据情况而定，个人觉得读两到三遍是最佳的投资。&nbsp;<br />
<br />
<font color="#4b0082">-----------------------------------</font><br />
<br />
避免常见错误&nbsp;<br />
<br />
在C语言中，内存错误是最为人诟病的。这些错误让项目延期或者被取消，引发无数的安全问题，甚至出现人命关天的灾难。抛开这些大道理不谈，它们确实浪费了我们大量时间，这些错误引发的是随机现象，即使有一些先进工具的帮助，为了找到重现的路径，花上几天时间也不足为怪。如果能够在编写代码的时候避免这些错误，开发效率至少提高一倍以上，质量可以提高几倍了。这里列举一些常见的内存错误，供新手参考。&nbsp;<br />
<br />
o&nbsp;内存泄露&nbsp;<br />
<br />
大家都知道，在堆上分配的内存，如果不再使用了，应该把它释放掉，以便后面其它地方可以重用。在C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>中，内存管理器不会帮你自动回收不再使用的内存。如果你忘了释放不再使用的内存，这些内存就不能被重用了，这就造成了所谓的内存泄露。&nbsp;<br />
<br />
把内存泄露列为首位，倒并不是因为它有多么严重的后果，而因为它是最为常见的一类错误。一两处内存泄露通常不至于让程序崩溃，也不会出现逻辑上的错误，加上进程退出时，系统会自动释放该进程所有相关的内存<font color="#800080"><b>(</b></font>共享内存除外<font color="#800080"><b>)</b></font>，所以内存泄露的后果相对来说还是比较温和的。但是，量变会导致质变，一旦内存泄露过多以致于耗尽内存，后续内存分配将会失败，程序可能因此而崩溃。&nbsp;<br />
<br />
现在PC机的内存够大了，加上进程有独立的内存空间，对于一些小程序来说，内存泄露已经不是太大的威胁。但对于大型软件，特别是长时间运行的软件，或者嵌入式系统来说，内存泄露仍然是致命的因素之一。&nbsp;<br />
<br />
不管在什么情况下，采取谨慎的态度，杜绝内存泄露的出现，都是可取的。相反，认为内存有的是，对内存泄露放任自流都不是负责的。尽管一些工具可以帮助我们检查内存泄露问题，我认为还是应该在编程时就仔细一点，及早排除这类错误，工具只是用作验证的手段。&nbsp;<br />
<br />
o&nbsp;内存越界访问&nbsp;<br />
<br />
内存越界访问有两种：一种是读越界，即读了不属于自己的数据，如果所读的内存地址是无效的，程度立刻就崩溃了。如果所读内存地址是有效的，在读的时候不会出问题，但由于读到的数据是随机的，它会产生不可预料的后果。另外一种是写越界，又叫缓冲区溢出，所写入的数据对别人来说是随机的，它也会产生不可预料的后果。&nbsp;<br />
<br />
内存越界访问造成的后果非常严重，是程序稳定性的致命威胁之一。更麻烦的是，它造成的后果是随机的，表现出来的症状和时机也是随机的，让BUG的现象和本质看似没有什么联系，这给BUG的定位带来极大的困难。&nbsp;<br />
<br />
一些工具可以够帮助检查内存越界访问的问题，但也不能太依赖于工具。内存越界访问通常是动态出现的，即依赖于测试数据，在极端的情况下才会出现，除非精心设计测试数据，工具也无能为力。工具本身也有一些限制，甚至在一些大型项目中，工具变得完全不可用。比较保险的方法还是在编程是就小心，特别是对于外部传入的参数要仔细检查。&nbsp;<br />
<br />
我们来看一个例子：&nbsp;<br />
<br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdlib<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>string<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font>&nbsp;str<font color="#800080"><b>[</b></font><font color="#ff0000">10</font><font color="#800080"><b>]</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;array<font color="#800080"><b>[</b></font><font color="#ff0000">10</font><font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#ff0000">0</font><font color="#4b0082">,</font><font color="#ff0000">1</font><font color="#4b0082">,</font><font color="#ff0000">2</font><font color="#4b0082">,</font><font color="#ff0000">3</font><font color="#4b0082">,</font><font color="#ff0000">4</font><font color="#4b0082">,</font><font color="#ff0000">5</font><font color="#4b0082">,</font><font color="#ff0000">6</font><font color="#4b0082">,</font><font color="#ff0000">7</font><font color="#4b0082">,</font><font color="#ff0000">8</font><font color="#4b0082">,</font><font color="#ff0000">9</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;data&nbsp;<font color="#4b0082">=</font>&nbsp;array<font color="#800080"><b>[</b></font><font color="#ff0000">10</font><font color="#800080"><b>]</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;array<font color="#800080"><b>[</b></font><font color="#ff0000">10</font><font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;data<font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font><font color="#800080"><b>(</b></font>argc&nbsp;<font color="#4b0082">==</font>&nbsp;<font color="#ff0000">2</font><font color="#800080"><b>)</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy<font color="#800080"><b>(</b></font>str<font color="#4b0082">,</font>&nbsp;argv<font color="#800080"><b>[</b></font><font color="#ff0000">1</font><font color="#800080"><b>])</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>}</b></font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
这个例子中有两个错误是新手常犯的：&nbsp;<br />
<br />
其一：<font color="#0000ff">int</font>&nbsp;array<font color="#800080"><b>[</b></font><font color="#ff0000">10</font><font color="#800080"><b>]</b></font>&nbsp;定义了<font color="#ff0000">10</font>个元素大小的数组，由于C语言中数组的索引是从<font color="#ff0000">0</font>开始的，所以只能访问array<font color="#800080"><b>[</b></font><font color="#ff0000">0</font><font color="#800080"><b>]</b></font>到array<font color="#800080"><b>[</b></font><font color="#ff0000">9</font><font color="#800080"><b>]</b></font>，访问array<font color="#800080"><b>[</b></font><font color="#ff0000">10</font><font color="#800080"><b>]</b></font>就造成了越界错误。&nbsp;<br />
<br />
其二：strcpy<font color="#800080"><b>(</b></font>str<font color="#4b0082">,</font>&nbsp;argv<font color="#800080"><b>[</b></font><font color="#ff0000">1</font><font color="#800080"><b>])</b></font><font color="#4b0082">;</font>这里是否存在越界错误依赖于外部输入的数据，这样的写法在正常下可能没有问题，但受到一点恶意攻击就完蛋了。除非你确定输入数据是在你控制内的，否则不要用strcpy、strcat和sprintf之类的函数，而要用strncpy、strncat和snprintf代替。&nbsp;<br />
<br />
o&nbsp;野指针。&nbsp;<br />
<br />
野指针是指那些你已经释放掉的内存指针。当你调用free<font color="#800080"><b>(</b></font>p<font color="#800080"><b>)</b></font>时，你真正清楚这个动作背后的内容吗？你会说p指向的内存被释放了。没错，p本身有变化吗？答案是p本身没有变化。它指向的内存仍然是有效的，你继续读写p指向的内存，没有人能拦得住你。&nbsp;<br />
<br />
释放掉的内存会被内存管理器重新分配，此时，野指针指向的内存已经被赋予新的意义。对野指针指向内存的访问，无论是有意还是无意的，都为此会付出巨大代价，因为它造成的后果，如同越界访问一样是不可预料的。&nbsp;<br />
<br />
释放内存后立即把对应指针置为空值，这是避免野指针常用的方法。这个方法简单有效，只是要注意，当然指针是从函数外层传入的时，在函数内把指针置为空值，对外层的指针没有影响。比如，你在析构函数里把<font color="#0000ff">this</font>指针置为空值，没有任何效果，这时应该在函数外层把指针置为空值。&nbsp;<br />
<br />
o&nbsp;访问空指针。&nbsp;<br />
<br />
空指针在C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>中占有特殊的地址，通常用来判断一个指针的有效性。空指针一般定义为<font color="#ff0000">0</font>。现代操作系统都会保留从<font color="#ff0000">0</font>开始的一块内存，至于这块内存有多大，视不同的操作系统而定。一旦程序试图访问这块内存，系统就会触发一个异常<font color="#4b0082">/</font>信号。&nbsp;<br />
<br />
操作系统为什么要保留一块内存，而不是仅仅保留一个字节的内存呢？原因是：一般内存管理都是按页进行管理的，无法单纯保留一个字节，至少要保留一个页面。保留一块内存也有额外的好处，可以检查诸如p<font color="#4b0082">=</font>NULL<font color="#4b0082">;</font>&nbsp;p<font color="#800080"><b>[</b></font><font color="#ff0000">1</font><font color="#800080"><b>]</b></font>之类的内存错误。&nbsp;<br />
<br />
在一些嵌入式系统<font color="#800080"><b>(</b></font>如arm7<font color="#800080"><b>)</b></font>中，从<font color="#ff0000">0</font>开始的一块内存是用来安装中断向量的，没有MMU的保护，直接访问这块内存好像不会引发异常。不过这块内存是代码段的，不是程序中有效的变量地址，所以用空指针来判断指针的有效性仍然可行。&nbsp;<br />
<br />
o&nbsp;引用未初始化的变量。&nbsp;<br />
<br />
未初始化变量的内容是随机的<font color="#800080"><b>(</b></font>有的编译器会在调试版本中把它们初始化为固定值，如0xcc<font color="#800080"><b>)</b></font>，使用这些数据会造成不可预料的后果，调试这样的BUG也是非常困难的。&nbsp;<br />
<br />
对于态度严谨的程度员来说，防止这类BUG非常容易。在声明变量时就对它进行初始化，是一个好的编程习惯。另外也要重视编译器的警告信息，发现有引用未初始化的变量，立即修改过来。&nbsp;<br />
<br />
在下面这个例子中，全局变量g_count是确定的，因为它在bss段中，自动初始化为<font color="#ff0000">0</font>了。临时变量a是没有初始化的，堆内存str是没有初始化的。但这个例子有点特殊，因为程序刚运行起来，很多东西是确定的，如果你想把它们当作随机数的种子是不行的，因为它们还不够随机。&nbsp;<br />
<br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdlib<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>string<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;g_count<font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;a<font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;str&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>(</b></font><font color="#0000ff">char</font><font color="#4b0082">*</font><font color="#800080"><b>)</b></font>malloc<font color="#800080"><b>(</b></font><font color="#ff0000">100</font><font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
<br />
o&nbsp;不清楚指针运算。&nbsp;<br />
<br />
对于一些新手来说，指针常常让他们犯糊涂。&nbsp;<br />
<br />
比如<font color="#0000ff">int</font>&nbsp;<font color="#4b0082">*</font>p&nbsp;<font color="#4b0082">=</font>&nbsp;&hellip;<font color="#4b0082">;</font>&nbsp;p<font color="#4b0082">+</font><font color="#ff0000">1</font>等于<font color="#800080"><b>(</b></font>size_t<font color="#800080"><b>)</b></font>p&nbsp;<font color="#4b0082">+</font>&nbsp;<font color="#ff0000">1</font>吗&nbsp;<br />
<br />
老手自然清楚，新手可能就搞不清了。事实上<font color="#4b0082">,</font>&nbsp;p<font color="#4b0082">+</font>n&nbsp;等于&nbsp;<font color="#800080"><b>(</b></font>size_t<font color="#800080"><b>)</b></font>p&nbsp;<font color="#4b0082">+</font>&nbsp;n&nbsp;<font color="#4b0082">*</font>&nbsp;<font color="#0000ff">sizeof</font><font color="#800080"><b>(</b></font><font color="#4b0082">*</font>p<font color="#800080"><b>)</b></font>&nbsp;<br />
<br />
指针是C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>中最有力的武器，功能非常强大，无论是变量指针还是函数指针，都应该非常熟练的掌握。只要有不确定的地方，马上写个小程序验证一下。对每一个细节了然于胸，在编程时会省下不少时间。&nbsp;<br />
<br />
o&nbsp;结构的成员顺序变化引发的错误。&nbsp;<br />
<br />
在初始化一个结构时，老手可能很少像新手那样老老实实的，一个成员一个成员的为结构初始化，而是采用快捷方式，如：&nbsp;<br />
<br />
<font color="#0000ff">struct</font>&nbsp;s<br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;&nbsp;&nbsp;l<font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">struct</font>&nbsp;s&nbsp;s1&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#ff0000">4</font><font color="#4b0082">,</font>&nbsp;<font color="#800000">&quot;abcd&quot;</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
以上这种方式是非常危险的，原因在于你对结构的内存布局作了假设。如果这个结构是第三方提供的，他很可能调整结构中成员的相对位置。而这样的调整往往不会在文档中说明，你自然很少去关注。如果调整的两个成员具有相同数据类型，编译时不会有任何警告，而程序的逻辑可能相距十万八千里了。&nbsp;<br />
<br />
正确的初始化方法应该是（当然，一个成员一个成员的初始化也行）：&nbsp;<br />
<br />
<font color="#0000ff">struct</font>&nbsp;s<br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;&nbsp;&nbsp;l<font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">struct</font>&nbsp;s&nbsp;s1&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#4b0082">.</font>l<font color="#4b0082">=</font><font color="#ff0000">4</font><font color="#4b0082">,</font>&nbsp;<font color="#4b0082">.</font>p&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800000">&quot;abcd&quot;</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
<font color="#800080"><b>(</b></font>有的编译器可能不支持新标准<font color="#800080"><b>)</b></font>&nbsp;<br />
<br />
o&nbsp;结构的大小变化引发的错误。&nbsp;<br />
<br />
我们看看下面这个例子：&nbsp;<br />
<br />
<font color="#0000ff">struct</font>&nbsp;base<br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;n<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">struct</font>&nbsp;s<br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">struct</font>&nbsp;base&nbsp;b<font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">int</font>&nbsp;m<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
在OOP中，我们可以认为第二个结构继承了第一结构，这有什么问题吗？当然没有，这是C语言中实现继承的基本手法。&nbsp;<br />
<br />
现在假设第一个结构是第三方提供的，第二个结构是你自己的。第三方提供的库是以DLL方式分发的，DLL最大好处在于可以独立替换。但随着软件的进化，问题可能就来了。&nbsp;<br />
<br />
当第三方在第一个结构中增加了一个新的成员<font color="#0000ff">int</font>&nbsp;k<font color="#4b0082">;</font>，编译好后把DLL给你，你直接把它给了客户了，让他们替换掉老版本。程序加载时不会有任何问题，在运行逻辑可能完全改变！原因是两个结构的内存布局重叠了。&nbsp;<br />
<br />
解决这类错误的唯一办法就是重新编译全部代码。由此看来，动态库并不见得可以动态替换，如果你想了解更多相关内容，建议你阅读《COM本质论》。&nbsp;<br />
<br />
o&nbsp;分配<font color="#4b0082">/</font>释放不配对。&nbsp;<br />
<br />
大家都知道malloc要和free配对使用，<font color="#0000ff">new</font>要和<font color="#0000ff">delete</font><font color="#4b0082">/</font><font color="#0000ff">delete</font><font color="#800080"><b>[]</b></font>配对使用，重载了类<font color="#0000ff">new</font>操作，应该同时重载类的<font color="#0000ff">delete</font><font color="#4b0082">/</font><font color="#0000ff">delete</font><font color="#800080"><b>[]</b></font>操作。这些都是书上反复强调过的，除非当时晕了头，一般不会犯这样的低级错误。&nbsp;<br />
<br />
而有时候我们却被蒙在鼓里，两个代码看起来都是调用的free函数，实际上却调用了不同的实现。比如在Win32下，调试版与发布版，单线程与多线程是不同的运行时库，不同的运行时库使用的是不同的内存管理器。一不小心链接错了库，那你就麻烦了。程序可能动则崩溃，原因在于在一个内存管理器中分配的内存，在另外一个内存管理器中释放时就会出现问题。&nbsp;<br />
<br />
o&nbsp;返回指向临时变量的指针&nbsp;<br />
<br />
大家都知道，栈里面的变量都是临时的。当前函数执行完成时，相关的临时变量和参数都被清除了。不能把指向这些临时变量的指针返回给调用者，这样的指针指向的数据是随机的，会给程序造成不可预料的后果。&nbsp;<br />
<br />
下面是个错误的例子：&nbsp;<br />
<br />
<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;get_str<font color="#800080"><b>(</b></font><font color="#0000ff">void</font><font color="#800080"><b>)</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font>&nbsp;str<font color="#800080"><b>[]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#800000">&quot;abcd&quot;</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;str<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p&nbsp;<font color="#4b0082">=</font>&nbsp;get_str<font color="#800080"><b>()</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;%s\n&quot;</font><font color="#4b0082">,</font>&nbsp;p<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
下面这个例子没有问题，大家知道为什么吗？&nbsp;<br />
<br />
<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;get_str<font color="#800080"><b>(</b></font><font color="#0000ff">void</font><font color="#800080"><b>)</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;str&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#800000">&quot;abcd&quot;</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;str<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p&nbsp;<font color="#4b0082">=</font>&nbsp;get_str<font color="#800080"><b>()</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;%s\n&quot;</font><font color="#4b0082">,</font>&nbsp;p<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
<br />
o&nbsp;试图修改常量&nbsp;<br />
<br />
在函数参数前加上<font color="#0000ff">const</font>修饰符，只是给编译器做类型检查用的，编译器禁止修改这样的变量。但这并不是强制的，你完全可以用强制类型转换绕过去，一般也不会出什么错。&nbsp;<br />
<br />
而全局常量和字符串，用强制类型转换绕过去，运行时仍然会出错。原因在于它们是放在<font color="#4b0082">.</font>rodata里面的，而<font color="#4b0082">.</font>rodata内存页面是不能修改的。试图对它们修改，会引发内存错误。&nbsp;<br />
<br />
下面这个程序在运行时会出错：&nbsp;<br />
<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800000">&quot;abcd&quot;</font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#4b0082">*</font>p&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800000">'1'</font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
<br />
o&nbsp;误解传值与传引用&nbsp;<br />
<br />
在C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>中，参数默认传递方式是传值的，即在参数入栈时被拷贝一份。在函数里修改这些参数，不会影响外面的调用者。如：&nbsp;<br />
<br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdlib<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdio<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
&nbsp;<br />
<font color="#0000ff">void</font>&nbsp;get_str<font color="#800080"><b>(</b></font><font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p<font color="#800080"><b>)</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;<font color="#4b0082">=</font>&nbsp;malloc<font color="#800080"><b>(</b></font><font color="#0000ff">sizeof</font><font color="#800080"><b>(</b></font><font color="#800000">&quot;abcd&quot;</font><font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;strcpy<font color="#800080"><b>(</b></font>p<font color="#4b0082">,</font>&nbsp;<font color="#800000">&quot;abcd&quot;</font><font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;p&nbsp;<font color="#4b0082">=</font>&nbsp;NULL<font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;get_str<font color="#800080"><b>(</b></font>p<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;p=%p\n&quot;</font><font color="#4b0082">,</font>&nbsp;p<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
在main函数里，p的值仍然是空值。当然在函数里修改指针指向的内容是可以的。&nbsp;<br />
<br />
o&nbsp;重名符号。&nbsp;<br />
<br />
无论是函数名还是变量名，如果在不同的作用范围内重名，自然没有问题。但如果两个符号的作用域有交集，如全局变量和局部变量，全局变量与全局变量之间，重名的现象一定要坚决避免。gcc有一些隐式规则来决定处理同名变量的方式，编译时可能没有任何警告和错误，但结果通常并非你所期望的。&nbsp;<br />
<br />
下面例子编译时就没有警告：&nbsp;<br />
<br />
t<font color="#4b0082">.</font>c<br />
&nbsp;<br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdlib<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdio<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;count&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;get_count<font color="#800080"><b>(</b></font><font color="#0000ff">void</font><font color="#800080"><b>)</b></font><br />
&nbsp;<br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;count<font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
&nbsp;<br />
main<font color="#4b0082">.</font>c<br />
&nbsp;<br />
<font color="#0000ff">#include</font>&nbsp;<font color="#4b0082">&lt;</font>stdio<font color="#4b0082">.</font>h<font color="#4b0082">&gt;</font><br />
&nbsp;<br />
<font color="#0000ff">extern</font>&nbsp;<font color="#0000ff">int</font>&nbsp;get_count<font color="#800080"><b>(</b></font><font color="#0000ff">void</font><font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;count<font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;count&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#ff0000">10</font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;get_count=%d\n&quot;</font><font color="#4b0082">,</font>&nbsp;get_count<font color="#800080"><b>())</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
&nbsp;<br />
<font color="#800080"><b>}</b></font><br />
如果把main<font color="#4b0082">.</font>c中的<font color="#0000ff">int</font>&nbsp;count<font color="#4b0082">;</font>修改为<font color="#0000ff">int</font>&nbsp;count&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font>，gcc就会编辑出错，说multiple&nbsp;definition&nbsp;of&nbsp;`count&rsquo;。它的隐式规则比较奇妙吧，所以还是不要依赖它为好。&nbsp;<br />
<br />
o&nbsp;栈溢出。&nbsp;<br />
<br />
我们在前面关于堆栈的一节讲过，在PC上，普通线程的栈空间也有十几M，通常够用了，定义大一点的临时变量不会有什么问题。&nbsp;<br />
<br />
而在一些嵌入式中，线程的栈空间可能只5K大小，甚至小到只有<font color="#ff0000">256</font>个字节。在这样的平台中，栈溢出是最常用的错误之一。在编程时应该清楚自己平台的限制，避免栈溢出的可能。&nbsp;<br />
<br />
o&nbsp;误用<font color="#0000ff">sizeof</font>。&nbsp;<br />
<br />
尽管C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>通常是按值传递参数，而数组则是例外，在传递数组参数时，数组退化为指针（即按引用传递），用<font color="#0000ff">sizeof</font>是无法取得数组的大小的。&nbsp;<br />
<br />
从下面这个例子可以看出：&nbsp;<br />
<br />
<font color="#0000ff">void</font>&nbsp;test<font color="#800080"><b>(</b></font><font color="#0000ff">char</font>&nbsp;str<font color="#800080"><b>[</b></font><font color="#ff0000">20</font><font color="#800080"><b>])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;%s:size=%d\n&quot;</font><font color="#4b0082">,</font>&nbsp;__func__<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">sizeof</font><font color="#800080"><b>(</b></font>str<font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font>&nbsp;&nbsp;<br />
&nbsp;<br />
<font color="#0000ff">int</font>&nbsp;main<font color="#800080"><b>(</b></font><font color="#0000ff">int</font>&nbsp;argc<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">char</font><font color="#4b0082">*</font>&nbsp;argv<font color="#800080"><b>[])</b></font><br />
<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">char</font>&nbsp;str<font color="#800080"><b>[</b></font><font color="#ff0000">20</font><font color="#800080"><b>]</b></font>&nbsp;&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#ff0000">0</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;test<font color="#800080"><b>(</b></font>str<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;%s:size=%d\n&quot;</font><font color="#4b0082">,</font>&nbsp;__func__<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">sizeof</font><font color="#800080"><b>(</b></font>str<font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
&nbsp;<br />
<font color="#800080"><b>[</b></font>root@localhost&nbsp;mm<font color="#800080"><b>]</b></font>#&nbsp;<font color="#4b0082">./</font>t<font color="#4b0082">.</font>exe<br />
test<font color="#4b0082">:</font>size<font color="#4b0082">=</font><font color="#ff0000">4</font><br />
main<font color="#4b0082">:</font>size<font color="#4b0082">=</font><font color="#ff0000">20</font><br />
<br />
o&nbsp;字节对齐。&nbsp;<br />
<br />
字节对齐主要目的是提高内存访问的效率。但在有的平台<font color="#800080"><b>(</b></font>如arm7<font color="#800080"><b>)</b></font>上，就不光是效率问题了，如果不对齐，得到的数据是错误的。&nbsp;<br />
<br />
所幸的是，大多数情况下，编译会保证全局变量和临时变量按正确的方式对齐。内存管理器会保证动态内存按正确的方式对齐。要注意的是，在不同类型的变量之间转换时要小心，如把<font color="#0000ff">char</font><font color="#4b0082">*</font>强制转换为<font color="#0000ff">int</font><font color="#4b0082">*</font>时，要格外小心。&nbsp;<br />
<br />
另外，字节对齐也会造成结构大小的变化，在程序内部用<font color="#0000ff">sizeof</font>来取得结构的大小，这就足够了。若数据要在不同的机器间传递时，在通信协议中要规定对齐的方式，避免对齐方式不一致引发的问题。&nbsp;<br />
<br />
o&nbsp;字节顺序。&nbsp;<br />
<br />
字节顺序历来是设计跨平台软件时头疼的问题。字节顺序是关于数据在物理内存中的布局的问题，最常见的字节顺序有两种：大端模式与小端模式。&nbsp;<br />
<br />
大端模式是高位字节数据存放在低地址处，低位字节数据存放在高地址处。&nbsp;<br />
<br />
小端模式指低位字节数据存放在内存低地址处，高位字节数据存放在内存高地址处；&nbsp;<br />
<br />
在普通软件中，字节顺序问题并不引人注目。而在开发与网络通信和数据交换有关的软件时，字节顺序问题就要特殊注意了。&nbsp;<br />
<br />
o&nbsp;多线程共享变量没有用valotile修饰。&nbsp;<br />
<br />
关键字valotile的作用是告诉编译器，不要把变量优化到寄存器里。在开发多线程并发的软件时，如果这些线程共享一些全局变量，这些全局变量最好用valotile修饰。这样可以避免因为编译器优化而引起的错误，这样的错误非常难查。&nbsp;<br />
<br />
o&nbsp;忘记函数的返回值&nbsp;<br />
<br />
函数需要返回值，如果你忘记<font color="#0000ff">return</font>语句，它仍然会返回一个值，因为在i386上，EAX用来保存返回值，如果没有明确返回，EAX最后的内容被返回，所以EAX的内容是随机的。&nbsp;<br />
<br />
<font color="#4b0082">-----------------------------------</font><br />
<br />
自动测试&nbsp;<br />
<br />
手工测试比没有测试强一点，但是它存在的问题让它很难在实践中应用：手工输入数据的过程单调乏味，很难长期坚持。每次都要重新输入数据，浪费大量时间。测试用例不能累积，测试往往不完整。用人脑判断输出的正误，浪费人力也存在误差。要写得好测试自然不能省，要写得快就需要更好的测试方法。&nbsp;<br />
<br />
更好的测试方法当然是自动测试了。幸运的是，刚进入这个行业我就接触了自动的测试&nbsp;<font color="#800080"><b>(</b></font>呵，读本文的初学者就更幸运了<font color="#800080"><b>)</b></font>，我的第一份正式工作是在测试组写测试程序。当时测试组也算是人才济济了，居然有几个北大毕业的，不过她们都不懂Linux，所以我被指派去为移植到Linux上的模块写测试程序。这些模块都有测试程序，但这些测试程序的功能太弱了，我的上司要求开发人员改进，但那些开发人员太自以为是了，根本不理我们，所以我们只好自己重写这些测试程序。模块很多，大概有<font color="#ff0000">50</font>多个模块，熟悉这些模块也需要不少时间，按每两个工作日写一个测试程序，上司给我<font color="#ff0000">5</font>个月时间。&nbsp;<br />
<br />
记得第一个模块是RDFParser，RDF<font color="#800080"><b>(</b></font>资源描述框架<font color="#800080"><b>)</b></font>是XML的一种应用，RDFParser实际上是一个XML解析器，并包装成RDF要求的接口。由于我对C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>还不太熟悉，对RDF更不熟悉了，花了两周时间才写出这个测试程序。运行起来有些不正常，我确信不是测试程序的问题，就去请开发人员帮忙来看一下。负责RDFParser的那个程序员是人大毕业，我没有见过第二个比他更自以为是的程序员了，他刚在我座位上坐下就很大声说，你们QA的人太蠢了！&nbsp;<br />
<br />
当时一听就愣了，不过我是新来的，见上司都没反应，自然就忍了。我列举了一些证据是模块里面的问题，他听也不听，只是不断重复的说，不可能是我程序的问题，你们QA的人太蠢了，总是浪费我的时间。过了一会儿，他终于闭上了嘴巴，又等了一会儿才说，等会儿重新发个版本给你吧。后来又请他过来四五次，结果每次都是他的问题。&nbsp;<br />
<br />
之后我再没有听到他说过你们QA的人太蠢了的话。为了避免让他抓到把柄来嘲笑测试组，我决定请他来查问题之前做更详细的测试。当时我写的测试程序和现在初学者写的测试程序没有两样，都是从教科书上学来的，先通过scanf从终端输入数据，调用被测函数，再把结果printf出来，这花了我太多时间。想到后面还有<font color="#ff0000">50</font>多个模块的测试程序要写，这样下去不行，一定得想个办法。&nbsp;<br />
<br />
后来我把输入的数据和期望的结果都写到一个INI文件中，测试程序从这个文件中读入数据，运行测试，再和预期结果比较，整个过程都自动化了。写了一个INI文件的解析器花了我一周时间，又重写了那个测试程序，整整花了我一个月时间完成RDFParser的测试程序。进度自然大落后了，还好上司知道后并没有责备我，让我慢慢做就好了。&nbsp;<br />
<br />
写第二个测试程序时把INI解析的代码拷贝过去，再加一些调用模块的代码就写好了，第三个也是如此。写了几个之后，我发现了INI解析有个BUG，结果每个测试程序我都要去修改，想到维护起来太麻烦了，就把INI解析器的接口规范化了，编译成一个独立共享库。又写了几个测试程序，我写烦了，原因是测试程序无非就是读入数据，调用被测函数，再检查结果，这个过程太无聊了。想到后面还要把这个过程重复几十遍，郁闷了几天之后，突然灵机一动，我决定写了一个代码产生器来产生这些代码。开始的代码产生器用C写的，用一个简单的规则来描述被测函数，通过这些规则来产生测试程序。我把这些东西和INI解析器放在一个独立的库中，把它叫作TesterFrameWork，经过几个测试程序的验证和完善，后来利用这个TesterFrameWork，只要一两个小时就能完成一个测试程序了。有次请开发人员那边一个高手帮我查一个问题，他看一会儿我的TesterFrameWork之后，盯着我说，你太聪明了。我笑了笑说，刚刚开始写C<font color="#4b0082">/</font>C<font color="#4b0082">++</font>程序。&nbsp;<br />
<br />
一年之后我知道了有个CPPUnit之后，为了赶时髦我把TesterFrameWork改名为CxxUnit，非典的时候放假无聊就把它重写了一遍放在cosoft上了<font color="#800080"><b>(</b></font>之后没有管过它，或许还在吧<font color="#800080"><b>)</b></font>。&nbsp;<br />
<br />
一个大系统很难自动测试，而一个独立的模块则是最佳的自动测试单元。自动测试和单元测试几乎成了等价的概念，很多人都以为自动测试就是利用CPPUnit这样的单元测试框架写个测试程序而已，这完全是错误的，就像有人以为有个设计文档的模板，照着填空就能填出好设计一样。&nbsp;<br />
<br />
我自己实现过单元测试框架，不是像有些人出于模仿去实现，而完全出于实际的需要，后来我也研究其它测试框架，应该说我对测试程序框架的认识比一般程序员要深刻。我认为测试程序框架可以减化一些测试程序的工作，但它与自动测试没有密切关系，用不用测试程序框架完全是个人喜好。用测试程序框架未必能写出好的测试程序，就像用C<font color="#4b0082">++</font>未必能写出好的面向对象的程序一样。&nbsp;<br />
<br />
虽然我顺利的完成了那个写测试程序的任务，但我一直被一个问题困扰：如何写测试用例，如何去检测结果？这是测试程序框架帮不上忙的。写测试用例还好说，通过边界值法，等价类法和路径覆盖法找到最常用的测试用例。检测结果呢？有人说很简单啊，判断返回值就好了。那我问一下dlist_insert返回OK，就真的OK了吗？如果一个函数根本没有返回值，那你怎么判断呢？&nbsp;<br />
<br />
测试程序框架是敏捷论者提倡的，在我看来它根本不够敏捷：你要去学习它，了解它的运行机制，要包含它的头文件，链接它的库，有比不用它更敏捷么？重要的是它根本帮不上什么有用的忙。前面的问题折磨了我一段时间，于是得出一个可能有点偏激的结论：测试程序框架都是愚蠢的，你真正需要的，它根本帮不了你<font color="#800080"><b>(</b></font>我知道这样说会得罪一些用测试程序框架的朋友，如果你想找我讨论的话，请看完本节的附带示例代码再说<font color="#800080"><b>)</b></font>。&nbsp;<br />
<br />
就在那个时候，我看到了孟岩老师翻译的《契约式设计<font color="#800080"><b>(</b></font>Design&nbsp;by&nbsp;Contract<font color="#800080"><b>)</b></font>》，读完之后豁然开朗。或许我还没有明白契约式设计的本质，但我确实知道了写自动测试程序的方法，下面我介绍一下：&nbsp;<br />
<br />
o&nbsp;在设计时，每个函数只完成单一的功能。单一功能的函数容易理解，也容易预测其行为。对测试来说，给定一些输入数据，就知道它的输出和影响，这样函数是最容易测试的。&nbsp;<br />
<br />
o&nbsp;在设计时，把函数分为查询和命令两类。查询函数只查询对象的状态，而不改变对象的状态。命令函数则只修改对象的状态，只返回其操作是否成功的标志，而不返回对象的状态。比如，dlist_length查询双向链表的长度，它不修改双向链表的任何状态。dlist_delete修改对象的状态<font color="#800080"><b>(</b></font>删除结点<font color="#800080"><b>)</b></font>，并返回其操作是否成功，而不返回当前长度或者删除的结点之类的状态。&nbsp;<br />
<br />
o&nbsp;在设计时，把查询分为基本查询和复合查询两类。基本查询函数只查询单一的状态，而复合查询可以同时查询多个状态。比如，window_get_width返回窗口的宽度，这是基本查询函数，widget_get_rect返回窗口的左上角坐标，宽度和高度，这是复合查询函数。&nbsp;<br />
<br />
o在实现时，检验输入数据，确认使用者正确的调用了函数。契约式设计规定了调用者和实现者双方的责任，调用者需要使用正确的参数，才能保证有正确的结果。政治家告诉我们，信任但要检查，所以作为实现者就需要检查输入参数是否违背了契约。那怎么检查呢？有人说，如果检查到无效参数就返回一个错误码。这当然可以，只是不太好，因为大多数人都没有检查返回值的习惯，如果每个地方都检查函数的返回值，也是件很繁琐的事，代码看起来也比较乱。通常我们只检查一些关键的地方，对于无效参数这样的错误，可能就无声无息的隐藏起来了，这样不好，因为隐藏得越深，发现的时间越晚，修改的代价越大。&nbsp;<br />
<br />
在C<font color="#4b0082">++</font>和JAVA里，如果参数不正确，通常是<font color="#0000ff">throw</font>一个无效参数之类的异常，C语言里面没有异常这个概念，我们需要其它办法才行。有人推荐用assert来检查，这是一个好办法，assert只在调试版本中有效<font color="#800080"><b>(</b></font>没有定义NDEBUG<font color="#800080"><b>)</b></font>，这样任何无效调用都在调试版本中暴露出来了。如果配合前面返回错误码的方法，在发布版本中也可能避免程序粗暴的死掉。使用方法如下：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>thiz&nbsp;<font color="#4b0082">!=</font>&nbsp;NULL<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font><font color="#800080"><b>(</b></font>thiz&nbsp;<font color="#4b0082">==</font>&nbsp;NULL<font color="#800080"><b>)</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font>&nbsp;DLIST_RET_INVALID_PARAMS<font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>}</b></font><br />
我一直使用这种方法，但是有个问题：无法用自动测试验证assert是否正常的触发了，当用错误的参数测试时，我期望assert被触发，但如果assert被触发了，自动程序测试就死掉了，自动测试程序死掉了，就无法继续验证下一个assert。这是一个悖论！&nbsp;<br />
<br />
后来我从glib里面学了一招，它检查时不用assert，只是打印出一个警告，代码也简明了，按它的方式，我们这样检查：&nbsp;<br />
<br />
return_val_if_fail<font color="#800080"><b>(</b></font>cursor&nbsp;<font color="#4b0082">!=</font>&nbsp;NULL<font color="#4b0082">,</font>&nbsp;DLIST_RET_INVALID_PARAMS<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
我们需要定义两个宏，一个用于无返回值的函数，一个用于有返回值的函数：&nbsp;<br />
<br />
<font color="#0000ff">#define</font>&nbsp;return_if_fail<font color="#800080"><b>(</b></font>p<font color="#800080"><b>)</b></font>&nbsp;<font color="#0000ff">if</font><font color="#800080"><b>(</b></font><font color="#4b0082">!</font><font color="#800080"><b>(</b></font>p<font color="#800080"><b>))</b></font>&nbsp;\<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>{</b></font>printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;%s:%d&nbsp;Warning:&nbsp;&quot;</font>#p<font color="#800000">&quot;&nbsp;failed.\n&quot;</font><font color="#4b0082">,</font>&nbsp;\<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__func__<font color="#4b0082">,</font>&nbsp;__LINE__<font color="#800080"><b>)</b></font><font color="#4b0082">;</font>&nbsp;<font color="#0000ff">return</font><font color="#4b0082">;</font><font color="#800080"><b>}</b></font><br />
<font color="#0000ff">#define</font>&nbsp;return_val_if_fail<font color="#800080"><b>(</b></font>p<font color="#4b0082">,</font>&nbsp;ret<font color="#800080"><b>)</b></font>&nbsp;<font color="#0000ff">if</font><font color="#800080"><b>(</b></font><font color="#4b0082">!</font><font color="#800080"><b>(</b></font>p<font color="#800080"><b>))</b></font>&nbsp;\<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>{</b></font>printf<font color="#800080"><b>(</b></font><font color="#800000">&quot;%s:%d&nbsp;Warning:&nbsp;&quot;</font>#p<font color="#800000">&quot;&nbsp;failed.\n&quot;</font><font color="#4b0082">,</font>\<br />
__func__<font color="#4b0082">,</font>&nbsp;__LINE__<font color="#800080"><b>)</b></font><font color="#4b0082">;</font>&nbsp;<font color="#0000ff">return</font>&nbsp;<font color="#800080"><b>(</b></font>ret<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><font color="#800080"><b>}</b></font><br />
这样一来，遇到无效参数时，可以看到一个警告信息，同时又不会影响自动测试。&nbsp;<br />
<br />
o在测试时，用查询来验证命令。命令一般都有返回值，但只检查返回值是不够的。比如dlist_delete返回OK，它真的OK了吗？我们信任它，但还是要检查。怎么检查？很简单，用查询函数来检查对象的状态是不是预期的。&nbsp;<br />
<br />
对于dlist_delete，我们预期：&nbsp;<br />
<br />
<font color="#ff0000">1</font><font color="#4b0082">.</font>输入无效参数，期望返回DLIST_RET_INVALID_PARAMS。&nbsp;<font color="#ff0000">2</font><font color="#4b0082">.</font>输入正确参数，期望：&nbsp;函数返回DLIST_RET_OK&nbsp;双向链表的长度减一。&nbsp;删除的位置的下一个元素被移到删除的位置。在测试程序中检查时，因为任何不符合期望的结果都是BUG，所以我们用assert检查。这样有问题马上暴露出来了，定位错误比较容易，通常都不需要调试器。我们这样来检查：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>dlist_length<font color="#800080"><b>(</b></font>dlist<font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">==</font>&nbsp;<font color="#800080"><b>(</b></font>n<font color="#4b0082">-</font>i<font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>dlist_delete<font color="#800080"><b>(</b></font>dlist<font color="#4b0082">,</font>&nbsp;<font color="#ff0000">0</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">==</font>&nbsp;DLIST_RET_OK<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>dlist_length<font color="#800080"><b>(</b></font>dlist<font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">==</font>&nbsp;<font color="#800080"><b>(</b></font>n<font color="#4b0082">-</font>i<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font><font color="#800080"><b>((</b></font>i&nbsp;<font color="#4b0082">+</font>&nbsp;<font color="#ff0000">1</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">&lt;</font>&nbsp;n<font color="#800080"><b>)</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>dlist_get_by_index<font color="#800080"><b>(</b></font>dlist<font color="#4b0082">,</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">,</font>&nbsp;<font color="#800080"><b>(</b></font><font color="#0000ff">void</font><font color="#4b0082">**</font><font color="#800080"><b>)</b></font><font color="#4b0082">&amp;</font>data<font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">==</font>&nbsp;DLIST_RET_OK<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>((</b></font><font color="#0000ff">int</font><font color="#800080"><b>)</b></font>data&nbsp;<font color="#4b0082">==</font>&nbsp;<font color="#800080"><b>(</b></font>i<font color="#4b0082">+</font><font color="#ff0000">1</font><font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800080"><b>}</b></font><br />
<br />
o在测试时，用基本查询去验证复合查询。基本查询和复合查询返回的应该一致。比如：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Rect&nbsp;rect&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>{</b></font><font color="#ff0000">0</font><font color="#800080"><b>}</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;widget_get_rect<font color="#800080"><b>(</b></font>widget<font color="#4b0082">,</font>&nbsp;<font color="#4b0082">&amp;</font>rect<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>widget_get_width<font color="#800080"><b>(</b></font>widget<font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">==</font>&nbsp;rect<font color="#4b0082">.</font>width<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;assert<font color="#800080"><b>(</b></font>widget_get_height<font color="#800080"><b>(</b></font>widget<font color="#800080"><b>)</b></font><font color="#4b0082">==</font>&nbsp;rect<font color="#4b0082">.</font>height<font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
<br />
o在测试时，预期结果依赖其执行上下文，我们要按逻辑组织测试用例。前面调用的函数可能改变了对象的状态，为了简化测试，在每组测试用例开始时，都重置对象到初始状态。&nbsp;<br />
<br />
o在测试时，第一次只写基本的测试用例，以后逐渐累积，每次发现新的BUG就把相应的测试用例加进去。每次修改了代码就运行一遍自动测试，保证修改没有引起其它副作用。&nbsp;<br />
<br />
按着上面的原则，应付正常模块的测试没有问题了，但是下面的情况仍然比较棘手：&nbsp;<br />
<br />
o&nbsp;带有GUI的应用程序。有GUI的程序会给自动的输入数据和检查结果带来困难，有些工具可以部分解决这个问题，特别是针对Win32下的GUI，我很少在Windows下写程序，所以对这方面了解不多。不过最好的办法还是用MVC模型等分离界面和实现，因为界面通常相对比较简单，可以手工测试，而实现的逻辑比较复杂，这部分可以自动测试。后面我们会专门讲解分离界面和实现的方法。&nbsp;<br />
<br />
o&nbsp;有随机数据输入。如果有些输入数据是内部随机产生的，那你根本无法预测它的输出结果和影响。比如游戏随机的步骤和无线网络信号的变化。对于我们可以控制的随机数据，可以提供额外的函数去获取这些数据。对于无法控制的随机输入数据，可以把它们隔离开，在自动测试中，使用固定的数据。&nbsp;<br />
<br />
o&nbsp;多线程运行的程序。多线程的程序也很难自动测试，比如向链表中插入一个元素，当你检查的时候，根本无法知道链表的长度是否增加，也无法知道刚才插入的位置是否是你插入的元素，因为这个时候，可能有另外一个线程已经把它删除了，或者又加入了新的数据。不过在单线程的自动测试通过之后，多线程的问题会大大减少，剩下的问题我们可以通过其它方式加以避免。&nbsp;<br />
<br />
写自动测试程序会花你一些时间，但这个投资能带来最大的回报：减少后面调试时的浪费，提高代码的质量，更重要的是你可以安稳的睡个觉了。&nbsp;<br />
<br />
Save&nbsp;your&nbsp;work&nbsp;<br />
<br />
&ldquo;Ernst和Young所在的小组决定使用正规的开发理论&mdash;他们常用削减法，分阶段进行开发并具有中途交付能力。他们的步骤包括细致的分析和设计&mdash;正如本章描写的基本原则一样。而其他竞争者径直开始了编码，在开始几个小时里，Ernst和Young小组落后了。但到中午时Ernst和Young小组却是遥遥领先了，而到了这一天的最后，他们却失败了。导致失败的原因不是因为他们的正规方法，而是他们偶然错误的把工作文件覆盖了，最终他们比午餐时所做的估计少交付了一些功能，他们是被没有使用有效的源程序版本控制这个典型的错误给打败了。&rdquo;&nbsp;<br />
<br />
&ndash;摘自《快速软件开发》&nbsp;<br />
<br />
<br />
前段时间看探索频道的《荒野求生秘技<font color="#800080"><b>(</b></font>Man&nbsp;<font color="#4b0082">&amp;</font>&nbsp;wild<font color="#800080"><b>)</b></font>》，我很喜欢这个节目也喜欢那个英国佬，甚至连重播都不会放过。他展示在沙漠、丛林、冰河和雪山等各种环境的求生秘技，他吃蜘蛛、白蚁、蝎子和蜥蜴，边吃边说这东西很恶心，但是里面含有非常的维生素，蛋白质和糖份，能够Save&nbsp;your&nbsp;life，所以要吃下去。&nbsp;<br />
<br />
在Man&nbsp;<font color="#4b0082">&amp;</font>&nbsp;Code的世界里，环境好多了，不用面临危险，寻找水源和食物根本不需要什么秘诀。这里我们不需要求生秘技去Save&nbsp;your&nbsp;life，但我们需要一些习惯去Save&nbsp;your&nbsp;work。我说过作为一名高效的程序员，不是因为他打字比别人快，而是因为他省下了别人浪费的时间，有什么比成果被毁，从头再来更浪费时间呢？下面我介绍一些习惯，它们简单有效，根本算不上什么秘技，但它们能够Save&nbsp;your&nbsp;work，让你的工作稳步前进。&nbsp;<br />
<br />
o&nbsp;随时存盘&nbsp;<br />
<br />
每次停电时，我都会听到有人惊呼，完了，我的代码没有保存！补回半小时或一个小时的工作不难，在一个好的工作环境里，这种情况一年也就会遇到几次，浪费的时间完全可以忽略不计。但是那种感觉很难受，会影响你的工作情绪，无缘无故的让你重做你的工作，和因为要改进去重做完全是两回事。在我以前工作过的一个公司，有段时间经常跳闸，每周都要停好几次，怎么也找不到原因，后来请人来查，据说是线路太长，静电引起的跳闸。经过那段时间的折磨，我养成了一个习惯：写代码的时候，平均<font color="#ff0000">30</font>秒钟存盘一次。现在遇到停电，别人惊呼的时候，我开始闭目养神了。&nbsp;<br />
<br />
o&nbsp;使用版本控制系统&nbsp;<br />
<br />
和一些老程序员聊天时<font color="#800080"><b>(</b></font>呵，其实我也老了<font color="#800080"><b>)</b></font>，他们经常问起我们项目有没有使用版本控制系统，我说当然有了，大二的时候就我用Sourcesafe来管理用powerbuilder写的代码了，后来的工作中一直在使用不同的版本控制系统。接着他们开始讲述他们惨痛的经历&hellip;这些经历小则让他们项目延期，大则导致整个项目失败。&nbsp;<br />
<br />
版本控制系统有很多功能，但对我个人来说，它最重要的功能是备份代码。每完成一个小功能，我都会把它提交<font color="#800080"><b>(</b></font>checkin<font color="#800080"><b>)</b></font>进去，如果我不小心删除了本地文件，或者某个做尝试的修改失败了，我可以恢复代码到前一个版本。不同团队有不同的规则，有的团队是不允许这样checkin的，他们只允许checkin经过严格测试的代码。如果是那样，你可以在本地建立自己的版本控制系统，初学者在学习时也可以这样做。现在有很多免费的版本控制系统可用，像CVS、SVN和GIT等等，我个人习惯用CVS，SVN是CVS的改进版，将来肯定会替代CVS的，所以推荐大家使用它。&nbsp;<br />
<br />
o&nbsp;定期备份&nbsp;<br />
<br />
温伯格在《Quality&nbsp;Software&nbsp;Management<font color="#4b0082">:</font>&nbsp;System&nbsp;Thinking》讲了一个有趣的故事，他以前去研究一些失败的案例，发现这些项目的失败都是因为欠佳的运气引起的：比如遭受到洪水、地震、火灾和流行感冒等灾害，项目主管们把自己描述成外部问题的受害者。他又对另外一些成功的项目进行研究，发现其中有些项目同样经历这些自然灾害，但是他们成功的完成了任务。区别只是在于成功项目的主管，采用积极预防措施，定期备份代码，把它们放到不同的地点。&nbsp;<br />
<br />
以前在学校的时候，我有两台电脑，一台赛扬和一台<font color="#ff0000">486</font>。我经常在上面重装系统，一会儿装Linux，一会儿装NT，一会儿又装Netware。虽然我经常把代码备份到不同的分区上，结果还不小心把所有分区全干掉了，让我痛心不已。那只是写的一些小程序，重写一遍问题也不大，但是对于专业程序员或一个软件团队来说，重写整个代码就不能接受了，所以需要更可靠的备份机制。&nbsp;<br />
<br />
使用源代码管理系统还不能保证代码的安全，比如服务器硬盘损坏和办公室发生火灾等都是可能发生。团队里一定要有人负责定期备份源代码管理系统系统上的资料，作为初学者也应该有这种意识。另外，我发现有些朋友把重要的资料放在邮箱里，现在的邮箱容量很大，因为提供商会定期备份，非常安全，这倒是一个不错的主意。&nbsp;<br />
<br />
o&nbsp;状态不好就做点别的&nbsp;<br />
<br />
女同胞有定期状态不佳的时候，男同胞也不是每天状态都很好。感冒了、丢东西了、或者家人争吵了，都会影响你的状态。状态不好的时候做事，往往是进一步退两步，甚至犯下严重的错误。有次我得了重感冒，居然在服务器的根目录下运行rm&nbsp;<font color="#4b0082">*</font>&nbsp;<font color="#4b0082">-</font>rf<font color="#800080"><b>(</b></font>删除全部文件<font color="#800080"><b>)</b></font>，由于删除的时间太长，才让我发现删错地方了，吓得我出了一身冷汗，还好那台服务器不是运行着源代码管理系统，但还是浪费了我两天时间去重建服务器上的环境。&nbsp;<br />
<br />
状态不好的时候编程也会犯一些低级错误，让你花费更多时间去调试。总要言之，状态不好的去做重要的事有害无益，这时你不防去做点别做的，比如看看其它模块的代码之类的，甚至完全放松去休息都比犯下严重的错误强。&nbsp;<br />
&nbsp;</p>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=63</link>
			<title><![CDATA[强大的位运算]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Mon,20 Oct 2008 17:35:41 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=63</guid>
		<description><![CDATA[<p>文章组织：<br />
<font color="#ff0000">1</font>、基本操作符<br />
<font color="#ff0000">2</font>、需要注意的问题<br />
<font color="#ff0000">3</font>、一些小应用<br />
<font color="#ff0000">4</font>、针对具体题目的应用<br />
<font color="#ff0000">1</font><font color="#4b0082">&gt;</font>&nbsp;搜索类<br />
<font color="#ff0000">2</font><font color="#4b0082">&gt;</font>&nbsp;字符串类<br />
<font color="#ff0000">3</font><font color="#4b0082">&gt;</font>&nbsp;其他类&nbsp;</p>
<p><br />
基本操作符<br />
与&nbsp;<font color="#4b0082">&amp;</font><br />
或&nbsp;<font color="#4b0082">|</font><br />
异或&nbsp;<font color="#4b0082">^</font><br />
左右移位&nbsp;<font color="#4b0082">&lt;&lt;</font>&nbsp;<font color="#4b0082">/</font>&nbsp;<font color="#4b0082">&gt;&gt;</font><br />
取反&nbsp;<font color="#4b0082">~</font><br />
<br />
需要注意的问题：<br />
<font color="#ff0000">1</font>、优先级，这是个非常严重的问题，在进行位运算的时候优先级太容易被忽略掉了<br />
尤其要注意的：<br />
移位运算符<font color="#4b0082">,</font>&nbsp;单目的取反运算符<font color="#4b0082">~</font>的优先级比比较运算符高。但是，<font color="#4b0082">&amp;,</font>&nbsp;<font color="#4b0082">|,</font>&nbsp;<font color="#4b0082">^</font>的优先级是比比较运算符低的！，这点一定要注意<br />
如<font color="#ff0000">6</font>&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">6</font>&nbsp;<font color="#4b0082">&gt;</font>&nbsp;<font color="#ff0000">4</font>的结果是<font color="#ff0000">0</font>，&nbsp;而不是&nbsp;<font color="#0000ff">true</font><font color="#4b0082">;</font>&nbsp;<font color="#800080"><b>(</b></font><font color="#ff0000">6</font>&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">6</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">&gt;</font>&nbsp;<font color="#ff0000">4</font>的结果才是<font color="#0000ff">true</font>，所以要注意勤加括号<br />
<br />
<font color="#ff0000">2</font>、速度<br />
位运算的速度是非常快的，你甚至可以忽略他的耗时，但是毕竟操作肯定是有耗损的。<br />
所以，应该尽量使用<br />
<font color="#4b0082">^=</font>，&nbsp;<font color="#4b0082">|=</font>&nbsp;，<font color="#4b0082">&amp;=</font>&nbsp;之类的操作，比如说a&nbsp;<font color="#4b0082">^=</font>&nbsp;b，&nbsp;速度比&nbsp;a&nbsp;<font color="#4b0082">=</font>&nbsp;a&nbsp;<font color="#4b0082">^</font>&nbsp;b快，因为前者是直接在a上进行操作，而&nbsp;a&nbsp;<font color="#4b0082">=</font>&nbsp;a&nbsp;<font color="#4b0082">^</font>&nbsp;b的第二个a，是一个a&nbsp;的副本，可见在操作中程序对a复制了一次，运算的结果又对原来的a做了一次赋值<br />
<br />
<font color="#ff0000">3</font>、范围（要当心移位运算时发生范围溢出）<br />
<br />
常用操作：<br />
<font color="#ff0000">1</font>、交换两个元素的值：a&nbsp;<font color="#4b0082">^=</font>&nbsp;b&nbsp;<font color="#4b0082">^=</font>&nbsp;a&nbsp;<font color="#4b0082">^=</font>&nbsp;b，不用借助第三个变量<br />
<br />
<font color="#ff0000">2</font><font color="#4b0082">.....</font>一下子也想不起来了，以后慢慢加<br />
<br />
优势：<br />
速度快，<br />
节省空间，又导致了速度快<br />
<br />
POJ的题目上：<br />
<br />
大类<font color="#ff0000">1</font>：搜索<br />
此处不讲题目，只讲位运算是怎样在这些题中实现和应用的。由于搜索题往往是基于对状态的操作，位运算往往特别有效，优化之后的效果可以有目共睹。<br />
<br />
例<font color="#ff0000">1</font>、POJ&nbsp;<font color="#ff0000">1324</font><br />
根据题目，确定了对状态的表示之后（记录当前状态的蛇头x<font color="#4b0082">,</font>&nbsp;y值与剩下部分的运动状态），一般容易想到剩下部分的运动状态用一个数组<font color="#800080"><b>(</b></font>比如x<font color="#800080"><b>[</b></font>n<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#800080"><b>]</b></font><font color="#4b0082">,</font>&nbsp;n为蛇节点数，n<font color="#800080"><b>[</b></font><font color="#ff0000">0</font><font color="#800080"><b>]</b></font>为第二个节点的运动趋势<font color="#800080"><b>)</b></font>去表示，且一个数组元素的值为<font color="#ff0000">0</font>，<font color="#ff0000">1</font>，<font color="#ff0000">2</font>，<font color="#ff0000">3</font>，即四个方向，蛇每次移动，这个方向数组需要更新一次，更新是很简单的，除了n<font color="#800080"><b>[</b></font><font color="#ff0000">0</font><font color="#800080"><b>]</b></font>更新之外，剩下的&nbsp;n<font color="#800080"><b>[</b></font>i<font color="#800080"><b>]</b></font>等于上一轮的n<font color="#800080"><b>[</b></font>i<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#800080"><b>]</b></font>（i<font color="#4b0082">&gt;</font><font color="#ff0000">1</font><font color="#800080"><b>)</b></font>；如果用数组，就必须用一个循环去更新它，这样会导致程序速度不是很理想，所以可以想到用位运算去模拟，简言之，就是把原来的一个数组压缩的一个变量上去存储，原来任何一个数组元素的值范围<font color="#ff0000">0</font><font color="#4b0082">~</font><font color="#ff0000">3</font>，&nbsp;用二进制表示就是&nbsp;<font color="#ff0000">00</font>&nbsp;<font color="#4b0082">~</font>&nbsp;<font color="#ff0000">11</font>，最多占用<font color="#ff0000">2</font>位，这样，我们就可以通过移位运算，和或运算去实现所以操作。<br />
<br />
基本技巧<font color="#4b0082">:</font>&nbsp;如果给你个一个方向序列&nbsp;a0<font color="#4b0082">,</font>&nbsp;a1<font color="#4b0082">,</font>&nbsp;a2<font color="#4b0082">,</font>&nbsp;a3<font color="#4b0082">,</font>&nbsp;<font color="#4b0082">....</font>&nbsp;a<font color="#800080"><b>(</b></font>n<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#800080"><b>)</b></font><font color="#4b0082">,</font>放到变量b中，且以最低位表示an，可以用如下循环<br />
b&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font><br />
<font color="#0000ff">for</font><font color="#800080"><b>(</b></font>i<font color="#4b0082">=</font><font color="#ff0000">0</font><font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">&lt;</font>n<font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">++</font><font color="#800080"><b>)</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>(</b></font>b<font color="#4b0082">&lt;&lt;</font><font color="#ff0000">2</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">|</font>&nbsp;a<font color="#800080"><b>[</b></font>i<font color="#800080"><b>]</b></font><font color="#4b0082">;</font><br />
即，每次把已经处理好的位段向上移两位，这样，在低位就会自动补齐两个<font color="#ff0000">0</font>，用一个&nbsp;<font color="#4b0082">|</font>&nbsp;操作，就吧新的值给放进变量中了。<br />
<br />
如果要从b中复原，则可使用&nbsp;<font color="#4b0082">&gt;&gt;</font>&nbsp;的办法<br />
<br />
<font color="#0000ff">for</font><font color="#800080"><b>(</b></font>i<font color="#4b0082">=</font><font color="#ff0000">0</font><font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">&lt;</font>n<font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">++</font><font color="#800080"><b>)</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<font color="#800080"><b>[</b></font>n<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#4b0082">-</font>i<font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#800080"><b>(</b></font>b&nbsp;<font color="#4b0082">&gt;&gt;</font>&nbsp;<font color="#800080"><b>(</b></font>i<font color="#4b0082">*</font><font color="#ff0000">2</font><font color="#800080"><b>))</b></font>&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font>；&nbsp;<br />
移位会将低位元素除掉，而&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font>则是把移到低位的元素取出。<br />
<br />
更高效的方法是<font color="#800080"><b>(</b></font>两种方法的前提都是不改变b的值<font color="#800080"><b>)</b></font><br />
<br />
t&nbsp;<font color="#4b0082">=</font>&nbsp;b<font color="#4b0082">;</font><br />
<font color="#0000ff">for</font><font color="#800080"><b>(</b></font>i<font color="#4b0082">=</font><font color="#ff0000">0</font><font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">&lt;</font>n<font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">++</font><font color="#800080"><b>){</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;a<font color="#800080"><b>[</b></font>n<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#4b0082">-</font>i<font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;t&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;<font color="#4b0082">&gt;&gt;=</font>&nbsp;<font color="#ff0000">2</font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
高效的原因如帖子开头所述。<br />
<br />
在表示状态的位段操作中，最好将变量设为<font color="#0000ff">unsigned</font>&nbsp;<font color="#0000ff">int</font>&nbsp;<font color="#800080"><b>(</b></font><font color="#0000ff">short</font><font color="#800080"><b>)</b></font>型，因为有符号型<font color="#800080"><b>(</b></font>负数的最高位（符号位）为<font color="#ff0000">1</font><font color="#800080"><b>)</b></font>的&nbsp;<font color="#4b0082">&gt;&gt;</font>操作加在负数上时会在右边引入<font color="#ff0000">1</font>而不是<font color="#ff0000">0</font>，&nbsp;这基本上不会是你想要的操作。<br />
<br />
例<font color="#ff0000">2</font>、POJ&nbsp;<font color="#ff0000">3460</font>&nbsp;Booksort<br />
这题可以在对书进行交换的时候应用位运算，也许你认为用数组去模拟更为直观，但是看看下面的实现，也许你就不那么认为了。<br />
书最大编号<font color="#ff0000">15</font>，<br />
这样就开一个<font color="#ff0000">64</font>位整形，每<font color="#ff0000">4</font>位表示一本书<br />
首先预处理，计算出两张表<br />
extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font>&nbsp;和&nbsp;clear<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font>分别表示把书架上第i到j本书取出或清空，显然在i到j一段，位上全是<font color="#ff0000">1</font>，而其他部分是<font color="#ff0000">0</font>，而clear<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font>就是extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font>的取反<br />
<br />
计算方法如下：<br />
<br />
<font color="#0000ff">typedef</font>&nbsp;<font color="#0000ff">unsigned</font>&nbsp;<font color="#0000ff">long</font>&nbsp;<font color="#0000ff">long</font>&nbsp;longint<font color="#4b0082">;</font><br />
<font color="#0000ff">const</font>&nbsp;longint&nbsp;base&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#ff0000">15</font><font color="#4b0082">;</font><font color="#008000">//这是必须注意的，普通的常数15是整形，在以下的操作中会越界</font><br />
<br />
<font color="#0000ff">for</font>&nbsp;<font color="#800080"><b>(</b></font>i&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#ff0000">0</font><font color="#4b0082">;</font>&nbsp;i&nbsp;<font color="#4b0082">&lt;</font>&nbsp;<font color="#ff0000">15</font><font color="#4b0082">;</font>&nbsp;i<font color="#4b0082">++</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>i<font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;base&nbsp;<font color="#4b0082">&lt;&lt;</font>&nbsp;<font color="#800080"><b>(</b></font>i&nbsp;<font color="#4b0082">*</font>&nbsp;<font color="#ff0000">4</font><font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;clear<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>i<font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#4b0082">~</font>extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>i<font color="#800080"><b>]</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;<font color="#0000ff">for</font>&nbsp;<font color="#800080"><b>(</b></font>j&nbsp;<font color="#4b0082">=</font>&nbsp;i&nbsp;<font color="#4b0082">+</font>&nbsp;<font color="#ff0000">1</font><font color="#4b0082">;</font>&nbsp;j&nbsp;<font color="#4b0082">&lt;</font>&nbsp;<font color="#ff0000">15</font><font color="#4b0082">;</font>&nbsp;j<font color="#4b0082">++</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#800080"><b>{</b></font><br />
&nbsp;&nbsp;&nbsp;&nbsp;extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#4b0082">-</font><font color="#ff0000">1</font><font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">|</font>&nbsp;<font color="#800080"><b>(</b></font>base&nbsp;<font color="#4b0082">&lt;&lt;</font>&nbsp;<font color="#800080"><b>(</b></font>j&nbsp;<font color="#4b0082">*</font>&nbsp;<font color="#ff0000">4</font><font color="#800080"><b>))</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;clear<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font>&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#4b0082">~</font>extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font><font color="#4b0082">;</font><br />
&nbsp;&nbsp;&nbsp;<font color="#800080"><b>}</b></font><br />
<font color="#800080"><b>}</b></font><br />
计算出这些以后，交换书就变得异常简单<br />
<br />
<font color="#0000ff">inline</font>&nbsp;<font color="#0000ff">void</font>&nbsp;transposition<font color="#800080"><b>(</b></font>longint&nbsp;<font color="#4b0082">&amp;</font>cur<font color="#4b0082">,</font>&nbsp;longint&nbsp;<font color="#4b0082">&amp;</font>next<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">int</font>&nbsp;<font color="#4b0082">&amp;</font>i<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">int</font>&nbsp;<font color="#4b0082">&amp;</font>k<font color="#4b0082">,</font>&nbsp;<font color="#0000ff">int</font>&nbsp;<font color="#4b0082">&amp;</font>j<font color="#800080"><b>)</b></font>&nbsp;<font color="#800080"><b>{</b></font><font color="#008000">//i,k段与k+1,c段置换</font><br />
next&nbsp;<font color="#4b0082">=</font>&nbsp;cur&nbsp;<font color="#4b0082">&amp;</font>&nbsp;clear<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>j<font color="#800080"><b>]</b></font><font color="#4b0082">;</font><br />
next&nbsp;<font color="#4b0082">|=</font>&nbsp;<font color="#800080"><b>(</b></font>cur&nbsp;<font color="#4b0082">&amp;</font>&nbsp;extract<font color="#800080"><b>[</b></font>i<font color="#800080"><b>][</b></font>k<font color="#800080"><b>])</b></font>&nbsp;<font color="#4b0082">&lt;&lt;</font>&nbsp;<font color="#800080"><b>((</b></font>j&nbsp;<font color="#4b0082">-</font>&nbsp;k<font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">&lt;&lt;</font>&nbsp;<font color="#ff0000">2</font><font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
next&nbsp;<font color="#4b0082">|=</font>&nbsp;<font color="#800080"><b>(</b></font>cur&nbsp;<font color="#4b0082">&amp;</font>&nbsp;extract<font color="#800080"><b>[</b></font>k<font color="#4b0082">+</font><font color="#ff0000">1</font><font color="#800080"><b>][</b></font>j<font color="#800080"><b>])</b></font>&nbsp;<font color="#4b0082">&gt;&gt;</font>&nbsp;<font color="#800080"><b>((</b></font>k&nbsp;<font color="#4b0082">-</font>&nbsp;i&nbsp;<font color="#4b0082">+</font>&nbsp;<font color="#ff0000">1</font><font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">&lt;&lt;</font>&nbsp;<font color="#ff0000">2</font><font color="#800080"><b>)</b></font><font color="#4b0082">;</font><br />
<font color="#800080"><b>}</b></font><br />
<br />
先把i到j全部清空后的值赋给next<font color="#4b0082">,</font>把&nbsp;i<font color="#4b0082">,</font>&nbsp;k段的书取出，移到高位（差值为<font color="#800080"><b>(</b></font>j&nbsp;<font color="#4b0082">-</font>&nbsp;k<font color="#800080"><b>)</b></font>&nbsp;<font color="#4b0082">*</font>&nbsp;<font color="#ff0000">4</font>），同理，再把k<font color="#4b0082">+</font>i到j段的值取出移到低位。<br />
如此清楚明了，而如果用数组的话，<font color="#ff0000">10</font><font color="#4b0082">+</font>行的语句是少不了的，而且容易搞错。<br />
<br />
例<font color="#ff0000">3</font>：HOJ&nbsp;八数码问题<br />
http<font color="#4b0082">:</font><font color="#008000">//acm.hnu.cn:8080/online/?action=problem&amp;type=show&amp;id=10466</font><br />
这题用位运算我倒是没有达到更快，空间稍微节省了些。<br />
另外，这题的测试数据很强的说，赞一个。<br />
<br />
用<font color="#ff0000">64</font>位的整形去表示整个状态，其中每<font color="#ff0000">4</font>位表示一个数码（<font color="#ff0000">0</font><font color="#4b0082">~</font><font color="#ff0000">8</font>），如果是用<font color="#0000ff">char</font>数组，则用<font color="#ff0000">9</font>个，用了<font color="#ff0000">72</font>位。<br />
取出某一位和清空某一位的掩码事先要计算好<br />
这样做比用一个整形数如&nbsp;<font color="#ff0000">123480567</font>&nbsp;之类的去表示更有优势，因为显然取出某一位的速度非常快，不需要&nbsp;<font color="#4b0082">%</font>&nbsp;<font color="#ff0000">10</font><font color="#4b0082">,</font>&nbsp;<font color="#4b0082">/</font><font color="#ff0000">10</font>之类耗时的操作，如果这样实现的话就不要用stl的map了，我无聊地试了次，相当之慢。还是老老实实康托展开的好。不过和开<font color="#0000ff">char</font>数组的速度差不多的说（虽然说赋值时间大了，但毕竟别人是数组，呵呵，要是有每<font color="#ff0000">4</font>位做一个单位的数组就好了&mdash;&mdash;不要跟我说用<font color="#0000ff">struct</font>里面定义的位段啊，那相当的慢）。<br />
<br />
最近还做了一个POJ&nbsp;<font color="#ff0000">2286</font>，可以用位运算，但貌似有些麻烦，没用，结果被一个用<font color="#0000ff">pascal</font>的小子超在前面，哪天状态好了要把这题改用位运算去做，就不信刷不到&nbsp;0ms<font color="#4b0082">.</font><br />
<br />
更新中<font color="#4b0082">...</font><br />
<br />
大类二：字符串的hash与查找<br />
<br />
大家都知道Rabin<font color="#4b0082">-</font>Karp算法吧，其实Rabin<font color="#4b0082">-</font>Karp实现后慢的一个原因是太多的模运算了，实际上，我们可以通过位运算隐式地取模<br />
<br />
原链接如下：http<font color="#4b0082">:</font><font color="#008000">//www-igm.univ-mlv.fr/~lecroq/string/node5.html#SECTION0050</font><br />
<br />
它开了一个<font color="#0000ff">int</font>型，每次用移位代替乘法，又由于整形是有范围的，但移位超过了范围，效果就相当于做了一次&nbsp;mod&nbsp;INT_MAX的操作。这样改进后速度提高了一倍。<br />
<br />
POJ&nbsp;<font color="#ff0000">2513</font>&nbsp;Colored&nbsp;Sticks就可以考虑使用此种方法的hash，他的冲突也是非常小的。当然有更高效的的字符串位运算hash算法，由于某些原因，我就不在这说了。<br />
<br />
<font color="#008000">//待续</font><br />
<br />
大类三：</p>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=37</link>
			<title><![CDATA[对(a % 4 == 0 &amp;&amp; b > 2) ? 0 : 1的优化]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Fri,25 Jul 2008 10:26:05 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=37</guid>
		<description><![CDATA[<ol id="shoCodeMain714ID" style="border-right: gray 1px solid; padding-right: 2px; border-top: gray 1px solid; padding-left: 2px; padding-bottom: 2px; margin: 0px; border-left: gray 1px solid; color: #2f4f4f; word-break: break-all; padding-top: 2px; border-bottom: gray 1px solid; font-family: Courier New; list-style-type: decimal; background-color: #dcf5dc">
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black">将语句</span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black"><font color="#0000ff">int</font>&nbsp;m&nbsp;<font color="#4b0082">=</font>&nbsp;<font color="#4b0082"><b>(</b></font>a&nbsp;<font color="#4b0082">%</font>&nbsp;<font color="#ff0000">4</font>&nbsp;<font color="#4b0082">==</font>&nbsp;<font color="#ff0000">0</font>&nbsp;<font color="#4b0082">&amp;&amp;</font>&nbsp;b&nbsp;<font color="#4b0082">&gt;</font>&nbsp;<font color="#ff0000">2</font><font color="#4b0082"><b>)</b></font>&nbsp;<font color="#4b0082">?</font>&nbsp;<font color="#ff0000">0</font>&nbsp;<font color="#4b0082">:</font>&nbsp;<font color="#ff0000">1</font><font color="#4b0082">;</font></span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black">优化为</span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black"><font color="#0000ff">int</font>&nbsp;m&nbsp;<font color="#4b0082">=</font>&nbsp;a&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font>&nbsp;<font color="#4b0082">||</font>&nbsp;b&nbsp;<font color="#4b0082">&lt;</font>&nbsp;<font color="#ff0000">3</font><font color="#4b0082">;</font></span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black">作者想出这个来也算不容易。</span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black">&nbsp;</span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black">原来的语句当条件为true时为<font color="#ff0000">0</font>，false时为<font color="#ff0000">1</font>，所以反一下，就等价于：</span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black"><font color="#0000ff">int</font>&nbsp;m&nbsp;<font color="#4b0082">=</font>&nbsp;a&nbsp;<font color="#4b0082">%</font>&nbsp;<font color="#ff0000">4</font>&nbsp;<font color="#4b0082">!=</font>&nbsp;<font color="#ff0000">0</font>&nbsp;<font color="#4b0082">||</font>&nbsp;b&nbsp;<font color="#4b0082">&lt;</font>&nbsp;<font color="#ff0000">3</font><font color="#4b0082">;</font></span></li>
    <li style="padding-left: 6px; margin: 0px 0px 0px 50px; border-left: silver 2px ridge; line-height: 18px; background-color: #f5fffa"><span style="color: black">所以关键的问题是要能够想到a&nbsp;<font color="#4b0082">%</font>&nbsp;<font color="#ff0000">4</font>&nbsp;<font color="#4b0082">!=</font>&nbsp;<font color="#ff0000">0</font>&nbsp;与&nbsp;a&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font>等价。这个比<font color="#ff0000">1</font>&nbsp;<font color="#4b0082">==</font>&nbsp;a&nbsp;<font color="#4b0082">%</font>&nbsp;<font color="#ff0000">2</font>与a&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">1</font>等价要难想到些。&nbsp;</span></li>
</ol>
<p>不过这只能够在C/C++里做做，js可不能够这么做，因为在js中，a&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font>&nbsp;<font color="#4b0082">||</font>&nbsp;b&nbsp;<font color="#4b0082">&lt;</font>&nbsp;<font color="#ff0000">3</font>的返回值很有可能不是0或1，而是a&nbsp;<font color="#4b0082">&amp;</font>&nbsp;<font color="#ff0000">3</font>的结果。</p>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=26</link>
			<title><![CDATA[iframe的滚动条问题]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Thu,10 Jul 2008 18:04:54 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=26</guid>
		<description><![CDATA[<p>今天给自己的blog家上了以前自己开发的播放器，不过发现在ie下，出现了本不该出现的横向滚动条。经过一番努力，最后被定位到是因为blog页面申明了DOCTYPE的缘故。</p>
<p>于是乎到网上搜索该解决之道，还真被找到了。</p>
<p>下面是解决该问题的多种方法：</p>
<p>&nbsp;</p>
<ol class="shoCodeMain" id="shoCodeMain46ID" style="HEIGHT: 100%">
    <li id="scli"><span style="COLOR: black">iframe&nbsp;问题2008-01-22&nbsp;16:37******&nbsp;&nbsp;&nbsp;显示&nbsp;iframe&nbsp;内容</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">XHTML&nbsp;1.0&nbsp;Transitional&nbsp;标准不能显示</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&lt;!DOCTYPE&nbsp;html&nbsp;PUBLIC&nbsp;&quot;-//W3C//DTD&nbsp;XHTML&nbsp;1.0&nbsp;Transitional//EN&quot;&nbsp;&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span> </li>
    <li id="scli"><span style="COLOR: black">&lt;html&nbsp;xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">父页面：修改为</span> </li>
    <li id="scli"><span style="COLOR: black">HTML&nbsp;4.01&nbsp;Transitional&nbsp;标准</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&lt;!DOCTYPE&nbsp;HTML&nbsp;PUBLIC&nbsp;&quot;-//W3C//DTD&nbsp;HTML&nbsp;4.01&nbsp;Transitional//EN&quot;&nbsp;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">子页面不要表头</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">******&nbsp;去掉&nbsp;iframe&nbsp;横向滚动条或竖条</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">1.&nbsp;在主页面加&nbsp;iframe&nbsp;scrolling=&quot;yes&quot;&nbsp;或&nbsp;&quot;auto&quot;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">2.&nbsp;css&nbsp;文件</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">body&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff"></font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;overflow-x&nbsp;</font><font color="#ff0000">:</font><font color="#800000">&nbsp;hidden</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;&nbsp;&nbsp;去掉横条</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;overflow-y&nbsp;</font><font color="#ff0000">:</font><font color="#800000">&nbsp;hidden</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;&nbsp;&nbsp;去掉竖条</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff"></font><font color="#4b0082"><b>}</b></font></span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">父页面和子页面链接入&nbsp;css&nbsp;文件</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">3.&nbsp;去掉子页面里的</span> </li>
    <li id="scli"><span style="COLOR: black">&lt;!doctype&nbsp;html&nbsp;public&nbsp;&quot;-//w3c//dtd&nbsp;xhtml&nbsp;1.0&nbsp;transitional//en&quot;&nbsp;&quot;http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd&quot;&gt;</span> </li>
    <li id="scli"><span style="COLOR: black">(即不要表头)</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">4.&nbsp;两个都去掉</span> </li>
    <li id="scli"><span style="COLOR: black">&lt;iframe&nbsp;scrolling=&quot;no&quot;&gt;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">**********************************************</span> </li>
    <li id="scli"><span style="COLOR: black">资料：</span> </li>
    <li id="scli"><span style="COLOR: black">http://fangbubu.javaeye.com/blog/155091</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">GOOGLE到一些有用的资料：&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">[DIV+CSS]XHTML下的滚动条问题&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">1.xhtml下滚动条的颜色问题？&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">在原来的html的时候，我们可以这样定义整个页面的滚动条&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">body<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-3dlight-color</font><font color="#ff0000">:</font><font color="#800000">#D4D0C8</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;最外左&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-highlight-color</font><font color="#ff0000">:</font><font color="#800000">#fff</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;左二&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-face-color</font><font color="#ff0000">:</font><font color="#800000">#E4E4E4</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;面子&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-arrow-color</font><font color="#ff0000">:</font><font color="#800000">#666</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;箭头&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-shadow-color</font><font color="#ff0000">:</font><font color="#800000">#808080</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;右二&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-darkshadow-color</font><font color="#ff0000">:</font><font color="#800000">#D7DCE0</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;右一&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-base-color</font><font color="#ff0000">:</font><font color="#800000">#D7DCE0</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;基色&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-track-color</font><font color="#ff0000">:</font><font color="#800000">#</font><font color="#ff0000">;</font><font color="#0000ff"><font color="#008000">/*-&nbsp;滑道&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff"></font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">但是同样的代码，我们应用在&nbsp;xhtml下就不起作用了，我相信好多好朋友也遇到过同样的问题&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">那么怎么才能在xhtml下应用滚动条样式呢？看下列代码&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-3dlight-color</font><font color="#ff0000">:</font><font color="#800000">#D4D0C8</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;最外左&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-highlight-color</font><font color="#ff0000">:</font><font color="#800000">#fff</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;左二&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-face-color</font><font color="#ff0000">:</font><font color="#800000">#E4E4E4</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;面子&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-arrow-color</font><font color="#ff0000">:</font><font color="#800000">#666</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;箭头&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-shadow-color</font><font color="#ff0000">:</font><font color="#800000">#808080</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;右二&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-darkshadow-color</font><font color="#ff0000">:</font><font color="#800000">#D7DCE0</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;右一&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-base-color</font><font color="#ff0000">:</font><font color="#800000">#D7DCE0</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;<font color="#008000">/*-&nbsp;基色&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff">scrollbar-track-color</font><font color="#ff0000">:</font><font color="#800000">#</font><font color="#ff0000">;</font><font color="#0000ff"><font color="#008000">/*-&nbsp;滑道&nbsp;-*/</font>&nbsp;</font></span> </li>
    <li id="scli"><span style="COLOR: black"><font color="#0000ff"></font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">这段代码和上一段唯一的不同就是在css定义的元素上，一个是body一个是html。我们再测试一下，把html页面的&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&quot;body&quot;修改成&quot;html&quot;测试一下，发现依然可以实现效果。那到底是为什么呢？&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">在html和xhtml都通过，因为*就是定义页面上的任何标签当然也包括了&ldquo;html&rdquo;这个标签。&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">(ps:其实与其说是html与xhtml的区别到不如说是有无XHTML&nbsp;1.0&nbsp;transitional&nbsp;doctype的区别，但是如果你把页面的&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">XHTML&nbsp;1.0&nbsp;transitional&nbsp;doctype去掉的话，那么这个页面就没有doctype，默认的显示方式就是html4.01,不过&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">你要把XHTML&nbsp;1.0&nbsp;transitional&nbsp;doctype修改成HTML&nbsp;4.01&nbsp;doctype同样页面定义body也不会有效果的，虽然&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">这个页面的标准是html&nbsp;4.01)&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">2.xhtml下frame页面横向滚动条的问题？&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">在用ie6浏览有框架的xhtml页面的时候，默认会水平和垂直滚动条会一起出现，这是ie6的一个&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">bug，在firefox上是正常的，出现的原因是其对XHTML&nbsp;1.0&nbsp;transitional&nbsp;doctype的解释缺陷.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">对于这个bug一般有3种解决方案，&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">方法1:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">代码：&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow-y</font><font color="#ff0000">:</font><font color="#800000">&nbsp;scroll</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">原理：强制显示ie的垂直滚动条，而忽略水平滚动条&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">优点：完全解决了这个问题,&nbsp;允许你保持完整的XHTML&nbsp;doctype.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">缺点：即使页面不需要垂直滚动条的时候也会出现垂直滚动条。&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">方法2:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">代码：&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow-x</font><font color="#ff0000">:</font><font color="#800000">&nbsp;hidden</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;overflow-y</font><font color="#ff0000">:</font><font color="#800000">&nbsp;auto</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">原理：隐藏横向滚动，垂直滚动根据内容自适应&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">优点：在视觉上解决了这个问题.在不必要的时候,&nbsp;未强制垂直滚动条出现.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">缺点：只是隐藏了水平滚动条，如果页面真正需要水平滚动条的时候，&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">屏幕以外的内容会因为用户无法水平滚动，而看不到。&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">方法3:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">代码：&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">body&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;margin-right</font><font color="#ff0000">:</font><font color="#800000">&nbsp;-15px</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;margin-bottom</font><font color="#ff0000">:</font><font color="#800000">&nbsp;-15px</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">原理：这会在margin的水平和垂直方向上添加一个负值,&nbsp;IE添加了该精确数值后,&nbsp;便会去除对滚动条的需求假象.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">优点：在视觉上解决了这个问题.，垂直滚动根据内容自适应&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">缺点：由于&quot;人为创建&quot;了15px的外边距(margin),&nbsp;所以无法使用该填充过的屏幕区域.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">以上摘自:http://hi.baidu.com/sandmax/blog/item/43fd0e4668dbc6096b63e59f.html&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">附：强制的滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">问题中的&quot;修复&quot;该bug的技术,&nbsp;同样可以用于其它目的.&nbsp;利用CSS,&nbsp;你可以有效地在Mozilla&nbsp;Firefox和Internet&nbsp;Explorer中显示或者隐藏垂直及水平滚动条.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">强制显示滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow</font><font color="#ff0000">:</font><font color="#800000">&nbsp;scroll</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">强制隐藏滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow</font><font color="#ff0000">:</font><font color="#800000">&nbsp;hidden</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">隐藏IE的水平滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow-x</font><font color="#ff0000">:</font><font color="#800000">&nbsp;hidden</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">隐藏IE的垂直滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow-y</font><font color="#ff0000">:</font><font color="#800000">&nbsp;hidden</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">强制显示IE的水平滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow-x</font><font color="#ff0000">:</font><font color="#800000">&nbsp;scroll</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">强制显示IE的垂直滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow-y</font><font color="#ff0000">:</font><font color="#800000">&nbsp;scroll</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">强制显示Mozilla的水平滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow</font><font color="#ff0000">:</font><font color="#800000">-moz-scrollbars-horizontal</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">注意:&nbsp;仅仅强制显示水平滚动条.&nbsp;也就是说,&nbsp;即使需要显示垂直滚动条时,&nbsp;垂直滚动条也不会出现.&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">强制显示Mozilla的垂直滚动条:&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">html&nbsp;<font color="#4b0082"><b>{</b></font><font color="#0000ff">&nbsp;overflow</font><font color="#ff0000">:</font><font color="#800000">-moz-scrollbars-vertical</font><font color="#ff0000">;</font><font color="#0000ff">&nbsp;</font><font color="#4b0082"><b>}</b></font>&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">注意:&nbsp;仅仅强制显示垂直滚动条.&nbsp;也就是说,&nbsp;即使需要显示水平滚动条时,&nbsp;水平滚动条也不会出现.&nbsp;&nbsp;</span> </li>
    <li id="scli"><span style="COLOR: black">&nbsp;</span> </li>
</ol>]]></description>
		</item>
		
			<item>
			<link>http://www.wscxy.com/shosh/article.asp?id=21</link>
			<title><![CDATA[测试引用通告]]></title>
			<author>shosh.zhu@qisda.com(shosh)</author>
			<category><![CDATA[程序开发]]></category>
			<pubDate>Fri,27 Jun 2008 18:23:42 +0800</pubDate>
			<guid>http://www.wscxy.com/shosh/default.asp?id=21</guid>
		<description><![CDATA[测试引用通告]]></description>
		</item>
		
</channel>
</rss>
