﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-兔子的技术博客</title><link>http://www.cppblog.com/flyinghare/</link><description>兔子</description><language>zh-cn</language><lastBuildDate>Fri, 03 Apr 2026 18:19:39 GMT</lastBuildDate><pubDate>Fri, 03 Apr 2026 18:19:39 GMT</pubDate><ttl>60</ttl><item><title>批处理比较数值大小 lss，equ和gtr的用法</title><link>http://www.cppblog.com/flyinghare/archive/2013/10/16/203775.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Wed, 16 Oct 2013 11:46:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/10/16/203775.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203775.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/10/16/203775.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203775.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203775.html</trackback:ping><description><![CDATA[<div style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">批处理比较数值大小 lss，equ和gtr的用法<p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px; line-height: 20px;"><span style="word-wrap: break-word;"><a href="http://panfutian.blog.163.com/blog/#m=0&amp;t=1&amp;c=fks_084067084086088070084083081095085082084071092095084067" rel="nofollow" target="_blank" style="word-wrap: break-word; text-decoration: none; color: #19599b;">&#9733;电脑综合&#9733;</a>&nbsp;<span style="word-wrap: break-word;">2010-04-17 14:18:39</span>&nbsp;<span style="word-wrap: break-word;">阅读<span style="word-wrap: break-word;">196</span></span>&nbsp;<span style="word-wrap: break-word;">评论<span style="word-wrap: break-word;">0</span></span>&nbsp;</span><span style="word-wrap: break-word;">&nbsp;&nbsp; 字号：<span style="word-wrap: break-word;"><u style="word-wrap: break-word;">大</u></span><span style="word-wrap: break-word;"><strong style="word-wrap: break-word;">中</strong></span><span style="word-wrap: break-word;"><u style="word-wrap: break-word;">小</u></span></span><span style="word-wrap: break-word;">&nbsp;<a rel="nofollow" style="word-wrap: break-word; color: #19599b;">订阅</a></span></p><div style="word-wrap: break-word;"><div style="word-wrap: break-word;"><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">&nbsp;&nbsp;&nbsp;&nbsp; EQU - 等于<br style="word-wrap: break-word;" />NEQ - 不等于<br style="word-wrap: break-word;" />LSS - 小于<br style="word-wrap: break-word;" />LEQ - 小于或等于<br style="word-wrap: break-word;" />GTR - 大于<br style="word-wrap: break-word;" />GEQ - 大于或等于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">比较大小.bat的源程序如下：<br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" />@echo off<br style="word-wrap: break-word;" />set /p 第一个数=请输入第一个数- c% F. C2 k: ~# R<br style="word-wrap: break-word;" />set /p 第二个数=请输入第二个数<br style="word-wrap: break-word;" />if %第二个数% lss %第一个数% goto hero7 |! U; ~8 ?5 ?7 p9 g6 v. Y3 w" K0 v<br style="word-wrap: break-word;" />if %第二个数% equ %第一个数% goto her<br style="word-wrap: break-word;" />if %第二个数% gtr %第一个数% goto he9 @! i8 q&amp; c; j; Z/ Q% ]<br style="word-wrap: break-word;" />pause2 W) H7 w/ R$ @&nbsp;&nbsp; g8 P<br style="word-wrap: break-word;" />exit<br style="word-wrap: break-word;" />:hero&amp; b8 K1 _5 C' U0 A/ l% D<br style="word-wrap: break-word;" />echo 第一个数比第二个数大！<br style="word-wrap: break-word;" />pause# A6 \8 X9 P) t- B9 Z- g2 e1 a<br style="word-wrap: break-word;" />%0<br style="word-wrap: break-word;" />:her' t) K1 j. h# L<br style="word-wrap: break-word;" />echo 第一个数等于第二个数！<br style="word-wrap: break-word;" />pause<br style="word-wrap: break-word;" />%0<br style="word-wrap: break-word;" />:he- o$ e* U# ]" }4 |! V% ^" c<br style="word-wrap: break-word;" />echo 第一个数比第二个数小！<br style="word-wrap: break-word;" />pause<br style="word-wrap: break-word;" />%07 \! s- e$ [0 E6 @<br style="word-wrap: break-word;" />: T+ d6 Y# o0 [" H4 P% C<br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" />比较大小另 版.bat 的源程序如下：<br style="word-wrap: break-word;" />5 B. b6 H8 i/ D* L<br style="word-wrap: break-word;" />@echo off; R% @1 ~% g' W<br style="word-wrap: break-word;" />set /p 第一个数=请输入第一个数<br style="word-wrap: break-word;" />set /p 第二个数=请输入第二个数<br style="word-wrap: break-word;" />if %第二个数% lss %第一个数% goto hero<br style="word-wrap: break-word;" />if %第二个数% equ %第一个数% goto her' N( d7 j&nbsp;&nbsp; i$ r8 e" A<br style="word-wrap: break-word;" />if %第二个数% gtr %第一个数% goto he" h2 ~4 P2 m' V<br style="word-wrap: break-word;" />:hero0 h( k, ?) \( C" t, \<br style="word-wrap: break-word;" />echo 第一个数比第二个数大！5 a4 i$ L7 p% M; e% ]! T<br style="word-wrap: break-word;" />pause<br style="word-wrap: break-word;" />goto end<br style="word-wrap: break-word;" />:her&amp; ~2 r' Q7 X! g: j0 I&amp; x<br style="word-wrap: break-word;" />echo 第一个数等于第二个数！<br style="word-wrap: break-word;" />pause$ k4 |( v4 B: _$ `" ~<br style="word-wrap: break-word;" />goto end<br style="word-wrap: break-word;" />:he&nbsp;&nbsp; ^3 U/ K* S" W- D7 o: t<br style="word-wrap: break-word;" />echo 第一个数比第二个数小！<br style="word-wrap: break-word;" />pause<br style="word-wrap: break-word;" />goto end<br style="word-wrap: break-word;" />:end. t; R( v+ H# l4 C0 l( f( _. q# i<br style="word-wrap: break-word;" />exit<br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" /><br style="word-wrap: break-word;" /><strong style="word-wrap: break-word;"><span style="word-wrap: break-word;">命令行下如何用批处理比较数据大小？</span></strong></p><div style="word-wrap: break-word;"><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;"><strong style="word-wrap: break-word;"><br style="word-wrap: break-word;" />set var1=3<br style="word-wrap: break-word;" />set var2=2<br style="word-wrap: break-word;" />if %var1% GTR %var2% goto ...<br style="word-wrap: break-word;" /></strong><br style="word-wrap: break-word;" /><strong style="word-wrap: break-word;">if /?:</strong><br style="word-wrap: break-word;" />执行批处理程序中的条件处理。<br style="word-wrap: break-word;" />IF [NOT] ERRORLEVEL number command<br style="word-wrap: break-word;" />IF [NOT] string1==string2 command<br style="word-wrap: break-word;" />IF [NOT] EXIST filename command<br style="word-wrap: break-word;" />NOT &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; 指定只有条件为 false 的情况下，Windows 才<br style="word-wrap: break-word;" />应该执行该命令。<br style="word-wrap: break-word;" />ERRORLEVEL number 如果最后运行的程序返回一个等于或大于<br style="word-wrap: break-word;" />指定数字的退出编码，指定条件为 true。<br style="word-wrap: break-word;" />string1==string2&nbsp;&nbsp; 如果指定的文字字符串匹配，指定条件为 true。<br style="word-wrap: break-word;" />EXIST filename 如果指定的文件名存在，指定条件为 true。<br style="word-wrap: break-word;" />command &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 如果符合条件，指定要执行的命令。如果指定的<br style="word-wrap: break-word;" />条件为 FALSE，命令后可跟一个执行 ELSE&nbsp;<br style="word-wrap: break-word;" />关键字后的命令的 ELSE 命令。<br style="word-wrap: break-word;" />ELSE 子句必须在 IF 之后出现在同一行上。例如:<br style="word-wrap: break-word;" />IF EXIST filename. (<br style="word-wrap: break-word;" />del filename.<br style="word-wrap: break-word;" />) ELSE (<br style="word-wrap: break-word;" />echo filename. missing.<br style="word-wrap: break-word;" />)<br style="word-wrap: break-word;" />因为 del 命令需要用一个新行终止，以下子句不会有效:<br style="word-wrap: break-word;" />IF EXIST filename. del filename. ELSE echo filename. missing<br style="word-wrap: break-word;" />由于 ELSE 命令必须与 IF 命令的尾端在同一行上，以下子句也<br style="word-wrap: break-word;" />不会有效:<br style="word-wrap: break-word;" />IF EXIST filename. del filename.<br style="word-wrap: break-word;" />ELSE echo filename. missing<br style="word-wrap: break-word;" />如果都放在同一行上，以下子句有效:<br style="word-wrap: break-word;" />IF EXIST filename. (del filename.) ELSE echo filename. missing<br style="word-wrap: break-word;" />如果命令扩展被启用，IF 会如下改变:<br style="word-wrap: break-word;" />IF [/I] string1 compare-op string2 command<br style="word-wrap: break-word;" />IF CMDEXTVERSION number command<br style="word-wrap: break-word;" />IF DEFINED variable command<br style="word-wrap: break-word;" />其中， compare-op 可以是:<br style="word-wrap: break-word;" />EQU - 等于<br style="word-wrap: break-word;" />NEQ - 不等于<br style="word-wrap: break-word;" />LSS - 小于<br style="word-wrap: break-word;" />LEQ - 小于或等于<br style="word-wrap: break-word;" />GTR - 大于<br style="word-wrap: break-word;" />GEQ - 大于或等于<br style="word-wrap: break-word;" />而 /I 开关(如果指定)说明要进行的字符串比较不分大小写。<br style="word-wrap: break-word;" />/I 开关可以用于 IF 的 string1==string2 的形式上。这些<br style="word-wrap: break-word;" />比较都是通用的；原因是，如果 string1 和 string2 都是<br style="word-wrap: break-word;" />由数字组成的，字符串会被转换成数字，进行数字比较。<br style="word-wrap: break-word;" />CMDEXTVERSION 条件的作用跟 ERRORLEVEL 的一样，除了它<br style="word-wrap: break-word;" />是在跟与命令扩展有关联的内部版本号比较。第一个版本<br style="word-wrap: break-word;" />是 1。每次对命令扩展有相当大的增强时，版本号会增加一个。<br style="word-wrap: break-word;" />命令扩展被停用时，CMDEXTVERSION 条件不是真的。<br style="word-wrap: break-word;" />如果已定义环境变量，DEFINED 条件的作用跟 EXISTS 的一样，<br style="word-wrap: break-word;" />除了它取得一个环境变量，返回的结果是 true。<br style="word-wrap: break-word;" />如果没有名为 ERRORLEVEL 的环境变量，%ERRORLEVEL%<br style="word-wrap: break-word;" />会扩充为 ERROLEVEL 当前数值的字符串表达式；否则，您会得到<br style="word-wrap: break-word;" />其数值。运行程序后，以下语句说明 ERRORLEVEL 的用法:<br style="word-wrap: break-word;" />goto answer%ERRORLEVEL%<br style="word-wrap: break-word;" />:answer0<br style="word-wrap: break-word;" />echo Program had return code 0<br style="word-wrap: break-word;" />:answer1<br style="word-wrap: break-word;" />echo Program had return code 1<br style="word-wrap: break-word;" />您也可以使用以上的数字比较:<br style="word-wrap: break-word;" />IF %ERRORLEVEL% LEQ 1 goto okay<br style="word-wrap: break-word;" />如果没有名为 CMDCMDLINE 的环境变量，%CMDCMDLINE%<br style="word-wrap: break-word;" />将在 CMD.EXE 进行任何处理前扩充为传递给 CMD.EXE 的原始<br style="word-wrap: break-word;" />命令行；否则，您会得到其数值。<br style="word-wrap: break-word;" />如果没有名为 CMDEXTVERSION 的环境变量，<br style="word-wrap: break-word;" />%CMDEXTVERSION% 会扩充为 CMDEXTVERSION 当前数值的<br style="word-wrap: break-word;" />字串符表达式；否则，您会得到其数值。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;"><strong style="word-wrap: break-word;">IF</strong>&nbsp;(DOS命令)</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　执行<a href="http://cache.baidu.com/view/80110.htm" rel="nofollow" target="_blank" style="word-wrap: break-word; text-decoration: none; color: #19599b;">批处理</a>程序中的条件处理。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;[NOT] ERRORLEVEL number command</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;[NOT] string1==string2 command</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;[NOT] EXIST filename command</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　NOT 指定只有条件为 false 的情况下， Windows XP 才</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　应该执行该命令。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　ERRORLEVEL number 如果最后运行的程序返回一个等于或大于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　指定数字的退出编码，指定条件为 true。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　string1==string2 如果指定的文字字符串匹配，指定条件为 true。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　EXIST filename 如果指定的文件名存在，指定条件为 true。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　command 如果符合条件，指定要执行的命令。如果指定的</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　条件为 FALSE，命令后可跟一个执行 ELSE</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　关键字后的命令的 ELSE 命令。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　ELSE 子句必须在&nbsp;<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;之后出现在同一行上。例如:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;EXIST filename. (</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　del filename.</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　) ELSE (</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　echo filename. missing.</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　)</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　因为 del 命令需要用一个新行终止，以下子句不会有效:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;EXIST filename. del filename. ELSE echo filename. missing</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　由于 ELSE 命令必须与&nbsp;<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;命令的尾端在同一行上，以下子句也</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　不会有效:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;EXIST filename. del filename.</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　ELSE echo filename. missing</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　如果都放在同一行上，以下子句有效:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;EXIST filename. (del filename.) ELSE echo filename. missing</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　如果命令扩展名被启用，<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;会如下改变:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;string1 compare-op string2 command</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;CMDEXTVERSION number command</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;DEFINED variable command</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　其中，比较运算符可以是:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　EQU - 等于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　NEQ - 不等于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　LSS - 小于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　LEQ - 小于或等于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<a name="baidusnap2" rel="nofollow" style="word-wrap: break-word; color: rgb(25, 89, 155);"></a><strong style="word-wrap: break-word; background-color: #99ff99; color: black;">GTR</strong>&nbsp;- 大于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　GEQ - 大于或等于</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　及 /I 开关；如果该开关被指定，则说明要进行的字符串比较不分</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　大小写。/I 开关可以用于&nbsp;<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;的 string1==string2 的形式上。这些</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　比较都是通用的；原因是，如果 string1 和 string2 都是由数字</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　组成的，字符串会被转换成数字，进行数字比较。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　CMDEXTVERSION 条件的作用跟 ERRORLEVEL 的一样，除了它</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　是在跟与命令扩展名有关联的内部版本号比较。第一个版本</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　是 1。每次对命令扩展名有相当大的增强时，版本号会增加一个。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　命令扩展名被停用时，CMDEXTVERSION 条件不是真的。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　如果已定义环境变量，DEFINED 条件的作用跟 EXISTS 的一样，</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　除了它取得一个环境变量，返回的结果是 true。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　如果没有名为 ERRORLEVEL 的环境变量，%ERRORLEVEL%</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　会扩充为 ERROLEVEL 当前数值的字符串表达式；否则，您会得到</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　其数值。运行程序后，以下语句说明 ERRORLEVEL 的用法:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　goto answer%ERRORLEVEL%</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　:answer0</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　echo Program had return code 0</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　:answer1</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　echo Program had return code 1</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　您也可以使用以上的数字比较:</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　<strong style="word-wrap: break-word; background-color: #ffff66; color: black;">IF</strong>&nbsp;%ERRORLEVEL% LEQ 1 goto okay</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　如果没有名为 CMDCMDLINE 的环境变量，%CMDCMDLINE%</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　将在 CMD.EXE 进行任何处理前扩充为传递给 CMD.EXE 的原始</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　命令行；否则，您会得到其数值。</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　如果没有名为 CMDEXTVERSION 的环境变量，</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　%CMDEXTVERSION% 会扩充为 CMDEXTVERSION 当前数值的</p><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">　　字串符表达式；否则，您会得到其数值。</p></div></div><p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">if中gtr的特殊应用(时间&amp;字母对比命令)</p></div></div><div style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">2009年05月06日 星期三 16:49</div><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">if中gtr的特殊应用作者：youxi01</span><br style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;" /><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">转载请注明</span><br style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;" /><br style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;" /><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">一、直接对日期大小进行比较。</span><br style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;" /><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">比如，我要查找当前目录下，在2005-5-30以后的文件，则可以这样写：</span><div style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;"><span style="word-wrap: break-word;">复制内容到剪贴板</span>&nbsp;代码:<p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">@echo off<br style="word-wrap: break-word;" />for %%i in (*) do if %%~ti gtr 2005-05-30 echo %%~nxi<br style="word-wrap: break-word;" />pause&gt;nul</p></div><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">二、对字母直接进行比较。</span><div style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;"><span style="word-wrap: break-word;">复制内容到剪贴板</span>&nbsp;代码:<p style="word-wrap: break-word; margin-right: 0px; margin-left: 0px; padding: 0px;">@echo off<br style="word-wrap: break-word;" />call :echo c o<br style="word-wrap: break-word;" />echo.<br style="word-wrap: break-word;" />call :echo d k<br style="word-wrap: break-word;" />pause&gt;nul<br style="word-wrap: break-word;" />:echo startw endw<br style="word-wrap: break-word;" />echo %1 到 %2 之间的字母有：<br style="word-wrap: break-word;" />for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (<br style="word-wrap: break-word;" />if %%i geq %1 if %%i leq %2 set /p=%%i &lt;nul)</p></div><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">三、更奇妙的是，汉字和英文字也可以比较&#8220;大小&#8221;---找出字符串中的汉字</span><br style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;" /><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">测试代码：&nbsp;</span><span style="word-wrap: break-word; color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">复制内容到剪贴板</span><span style="color: #666666; font-family: 宋体, Arial; font-size: 12px; line-height: 26px; background-color: #ffffff;">&nbsp;代码:</span>@echo off<br style="word-wrap: break-word;" />setlocal enabledelayedexpansion<br style="word-wrap: break-word;" />set "str=我bat是home好.cn人"<br style="word-wrap: break-word;" />call :test "%str%"<br style="word-wrap: break-word;" />echo 提取出的汉字有：%cstr%<br style="word-wrap: break-word;" />pause&gt;nul<br style="word-wrap: break-word;" />:test<br style="word-wrap: break-word;" />set "var=%~1"<br style="word-wrap: break-word;" />for /l %%i in (0 1 20) do (<br style="word-wrap: break-word;" />set "var_=!var:~%%i,1!"<br style="word-wrap: break-word;" />if "!var_!"=="" goto :eof<br style="word-wrap: break-word;" />if !var_! gtr Z set cstr=!cstr!!var_!<br /><br /><br />转自：<a href="http://blog.chinaunix.net/uid-78707-id-3473907.html">http://blog.chinaunix.net/uid-78707-id-3473907.html</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203775.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-10-16 19:46 <a href="http://www.cppblog.com/flyinghare/archive/2013/10/16/203775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++操作mysql数据库文章资料汇总</title><link>http://www.cppblog.com/flyinghare/archive/2013/10/11/203664.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Fri, 11 Oct 2013 09:56:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/10/11/203664.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203664.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/10/11/203664.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203664.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203664.html</trackback:ping><description><![CDATA[<table border="0" cellspacing="1" cellpadding="1" align="center" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; width: 680px;"><tbody><tr><td><table border="0" cellspacing="0" cellpadding="5" style="width: 676px;"><tbody><tr><td><strong>usidc5</strong></td><td align="right">2010-07-19 00:19</td></tr><tr bgcolor="#ffffff"><td colspan="2"><h1>C++操作mysql数据库文章资料汇总</h1><span style="font-family: tahoma; font-size: 14px; color: #222222; line-height: 23px;"><p style="margin: 15px 0pt; padding: 0px;">VC的MySQL编程<br />在你的程式中使用数据库是个不做的注意。如果已经有可用的MySQL服务 器，在VC中可以按照如下方法实现与数据库的连接。</p><p style="margin: 15px 0pt; padding: 0px;">1、 找來MySQL(Win32)安裝目录下的include文件夾， 將其添加到VC头文件目录列表中；</p><p style="margin: 15px 0pt; padding: 0px;">（VC6 -&gt; Options -&gt; Directories -&gt; 加入此目录）</p><p style="margin: 15px 0pt; padding: 0px;">（VC2005 -&gt; 工具 -&gt;&nbsp;选项 -&gt; 项目和解決方案 -&gt; VC++目录 -&gt; 显示以下内容的目录 -&gt; 包含文件 -&gt; 加入此目录）</p><p style="margin: 15px 0pt; padding: 0px;">2、找到MySQL(Win32)安裝目 录下的lib文件夹， 將其添加到VC库文件目录列表中；</p><p style="margin: 15px 0pt; padding: 0px;">（VC6 -&gt; Options -&gt; Directories -&gt; 加入此目录）</p><p style="margin: 15px 0pt; padding: 0px;">（VC2005 -&gt; 工具 -&gt; 选项 -&gt; 项目和解决方案 -&gt; VC++目录 -&gt; 显示以下内容的目录 -&gt; 库文件 -&gt; 加入此目录，注意是lib/debug或lib/opt）</p><p style="margin: 15px 0pt; padding: 0px;">3、新建一个工程，参考如下代码；</p><p style="margin: 15px 0pt; padding: 0px;">// mysql.cpp : Defines the entry point for the console application.<br />//</p><p style="margin: 15px 0pt; padding: 0px;">#include "stdafx.h"<br />#include &lt;stdio.h&gt;<br />#include &lt;winsock.h&gt;<br />#include &lt;mysql.h&gt;<br />#include &lt;windows.h&gt;</p><p style="margin: 15px 0pt; padding: 0px;">#pragma comment(lib, "libmysql.lib")</p><p style="margin: 15px 0pt; padding: 0px;"><br />int main(int argc, char* argv[])<br />...{<br />unsigned short Port = 3306;<br />char *IPAddress = "192.168.31.56";<br />char *UserName = "root";<br />char *Password = "";<br />char *DBName = "SAS_1_2_0";</p><p style="margin: 15px 0pt; padding: 0px;">printf("Start... ");<br /><br />MYSQL *ssock;<br />//char execsql[500];</p><p style="margin: 15px 0pt; padding: 0px;">ssock = (MYSQL *)malloc(sizeof(MYSQL));<br /><br />// 在某些版本中，不需要该初始化工作，可观看mysql.H以及readme<br />mysql_init(ssock);<br />if(ssock == NULL)<br />...{<br />printf("EROR: MySQL ssock init error. ");<br />return FALSE;<br />}</p><p style="margin: 15px 0pt; padding: 0px;">//连接指定数据库<br />ssock = mysql_real_connect(ssock, IPAddress, UserName, Password, NULL, Port, NULL, 0);<br />if(!ssock)<br />...{<br />printf("conn fail... ");</p><p style="margin: 15px 0pt; padding: 0px;">//memcpy(eee, mysql_error(ssock), 20);<br />//fprintf(stderr, "Failed to connect to database: Error: %s ", mysql_error(ssock));</p><p style="margin: 15px 0pt; padding: 0px;">//printf("%c ", eee);<br />unsigned int mtint = mysql_errno(ssock);<br />//printf("%d ");<br />return FALSE;<br />}</p><p style="margin: 15px 0pt; padding: 0px;">if(mysql_select_db(ssock, DBName) != 0)<br />...{<br />printf("select db error. ");<br />return FALSE;<br />}</p><p style="margin: 15px 0pt; padding: 0px;">printf("version=%d ", mysql_get_server_version(ssock));<br />//exec my execsql string<br />//sprintf(execsql,"create table girls (name char(10),age int)");<br />//mysql_real_query(ssock,execsql,strlen(execsql));<br />mysql_close(ssock);</p><p style="margin: 15px 0pt; padding: 0px;">printf("End... ");<br />return TRUE;<br />}<br />4、编译连接，运行即可。</p><p style="margin: 15px 0pt; padding: 0px;">&nbsp;</p></span></td></tr></tbody></table></td></tr></tbody></table><p style="margin: 0px; padding: 0px; color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><table border="0" cellspacing="1" cellpadding="1" align="center" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; width: 680px;"><tbody><tr><td><table border="0" cellspacing="0" cellpadding="5" style="width: 676px;"><tbody><tr><td><strong>usidc5</strong></td><td align="right">2010-07-19 00:21</td></tr><tr bgcolor="#ffffff"><td colspan="2">这里归纳了C API可使用的函数，并在下一节详细介绍了它们。<br /><br />函数<br />描述<br /><br />mysql_affected_rows()<br />返 回上次UPDATE、DELETE或INSERT查询更改／删除／插入的行数。<br /><br />mysql_autocommit()<br />切换 autocommit模式，ON/OFF<br /><br />mysql_change_user()<br />更改打开连接上的用户和数据库。<br /><br />mysql_charset_name()<br />返 回用于连接的默认字符集的名称。<br /><br />mysql_close()<br />关闭服务器连接。<br /><br />mysql_commit()<br />提 交事务。<br /><br />mysql_connect()<br />连接到MySQL服务器。该函数已不再被重视，使用 mysql_real_connect()取代。<br /><br />mysql_create_db()<br />创建数据库。该函数已不再被重视，使用 SQL语句CREATE DATABASE取而代之。<br /><br />mysql_data_seek()<br />在查询结果集中查找属性行编号。<br /><br />mysql_debug()<br />用 给定的字符串执行DBUG_PUSH。<br /><br />mysql_drop_db()<br />撤销数据库。该函数已不再被重视，使用SQL语句DROP DATABASE取而代之。<br /><br />mysql_dump_debug_info()<br />让服务器将调试信息写入日志。<br /><br />mysql_eof()<br />确 定是否读取了结果集的最后一行。该函数已不再被重视，可以使用mysql_errno()或mysql_error()取而代之。<br /><br />mysql_errno()<br />返 回上次调用的MySQL函数的错误编号。<br /><br />mysql_error()<br />返回上次调用的MySQL函数的错误消息。<br /><br />mysql_escape_string()<br />为 了用在SQL语句中，对特殊字符进行转义处理。<br /><br />mysql_fetch_field()<br />返回下一个表字段的类型。<br /><br />mysql_fetch_field_direct()<br />给 定字段编号，返回表字段的类型。<br /><br />mysql_fetch_fields()<br />返回所有字段结构的数组。<br /><br />mysql_fetch_lengths()<br />返 回当前行中所有列的长度。<br /><br />mysql_fetch_row()<br />从结果集中获取下一行<br /><br />mysql_field_seek()<br />将 列光标置于指定的列。<br /><br />mysql_field_count()<br />返回上次执行语句的结果列的数目。<br /><br />mysql_field_tell()<br />返 回上次mysql_fetch_field()所使用字段光标的位置。<br /><br />mysql_free_result()<br />释放结果集使用的 内存。<br />mysql_get_client_info()<br />以字符串形式返回客户端版本信息。<br /><br />mysql_get_client_version()<br />以 整数形式返回客户端版本信息。<br /><br />mysql_get_host_info()<br />返回描述连接的字符串。<br /><br />mysql_get_server_version()<br />以 整数形式返回服务器的版本号。<br /><br />mysql_get_proto_info()<br />返回连接所使用的协议版本。<br /><br />mysql_get_server_info()<br />返 回服务器的版本号。<br /><br />mysql_info()<br />返回关于最近所执行查询的信息。<br /><br />mysql_init()<br />获 取或初始化MYSQL结构。<br /><br />mysql_insert_id()<br />返回上一个查询为AUTO_INCREMENT列生成的ID。<br /><br />mysql_kill()<br />杀 死给定的线程。<br /><br />mysql_library_end()<br />最终确定MySQL C API库。<br /><br />mysql_library_init()<br />初 始化MySQL C API库。<br /><br />mysql_list_dbs()<br />返回与简单正则表达式匹配的数据库名称。<br /><br />mysql_list_fields()<br />返 回与简单正则表达式匹配的字段名称。<br /><br />mysql_list_processes()<br />返回当前服务器线程的列表。<br /><br />mysql_list_tables()<br />返 回与简单正则表达式匹配的表名。<br /><br />mysql_more_results()<br />检查是否还存在其他结果。<br /><br />mysql_next_result()<br />在 多语句执行过程中返回/初始化下一个结果。<br /><br />mysql_num_fields()<br />返回结果集中的列数。<br /><br />mysql_num_rows()<br />返 回结果集中的行数。<br /><br />mysql_options()<br />为mysql_connect()设置连接选项。<br /><br />mysql_ping()<br />检 查与服务器的连接是否工作，如有必要重新连接。<br /><br />mysql_query()<br />执行指定为&#8220;以Null终结的字符串&#8221;的SQL查询。<br /><br />mysql_real_connect()<br />连 接到MySQL服务器。<br /><br />mysql_real_escape_string()<br />考虑到连接的当前字符集，为了在SQL语句中使 用，对字符串中的特殊字符进行转义处理。<br /><br />mysql_real_query()<br />执行指定为计数字符串的SQL查询。<br /><br />mysql_refresh()<br />刷 新或复位表和高速缓冲。<br /><br />mysql_reload()<br />通知服务器再次加载授权表。<br />mysql_rollback()<br />回 滚事务。<br /><br />mysql_row_seek()<br />使用从mysql_row_tell()返回的值，查找结果集中的行偏移。<br /><br />mysql_row_tell()<br />返 回行光标位置。<br /><br />mysql_select_db()<br />选择数据库。<br /><br />mysql_server_end()<br />最 终确定嵌入式服务器库。<br /><br />mysql_server_init()<br />初始化嵌入式服务器库。<br /><br />mysql_set_server_option()<br />为 连接设置选项（如多语句）。<br /><br />mysql_sqlstate()<br />返回关于上一个错误的SQLSTATE错误代码。<br /><br />mysql_shutdown()<br />关 闭数据库服务器。<br /><br />mysql_stat()<br />以字符串形式返回服务器状态。<br /><br />mysql_store_result()<br />检 索完整的结果集至客户端。<br /><br />mysql_thread_id()<br />返回当前线程ID。<br /><br />mysql_thread_safe()<br />如 果客户端已编译为线程安全的，返回1。<br /><br />mysql_use_result()<br />初始化逐行的结果集检索。<br /><br />mysql_warning_count()<br />返 回上一个SQL语句的告警数。<br />&nbsp;<br /></td></tr></tbody></table></td></tr></tbody></table><p style="margin: 0px; padding: 0px; color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><table border="0" cellspacing="0" cellpadding="5" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; width: 694px;"><tbody><tr><td><strong>usidc5</strong></td><td align="right">2010-07-19 00:22</td></tr><tr bgcolor="#ffffff"><td colspan="2"><span style="font-size: small;"><span style="font-family: tahoma;"><span style="color: #222222;"><div>与MySQL交互时， 应用程序应使用该一般性原则：</div><div></div><div>1. 通过调用mysql_library_init()，初始化MySQL库。库可以是mysqlclient C客户端库，或mysqld嵌入式服务器库，具体情况取决于应用程序是否与&#8220;-libmysqlclient&#8221;或&#8220;-libmysqld&#8221;标志链接。</div><div></div><div>2. 通过调用mysql_init()初始化连接处理程序，并通过调用mysql_real_connect()连接到服务器。</div><div></div><div>3. 发出SQL语句并处理其结果。（在下面的讨论中，详细介绍了使用它的方法）。</div><div></div><div>4. 通过调用mysql_close()，关闭与MySQL服务器的连接。</div><div></div><div>5. 通过调用mysql_library_end()，结束MySQL库的使用。</div><div></div><div>调用 mysql_library_init()和mysql_library_end()的目的在于，为MySQL库提供恰当的初始化和结束处理。对于与客户 端库链接的应用程序，它们提供了改进的内存管理功能。如果不调用mysql_library_end()，内存块仍将保持分配状态（这不会增加应用程序使 用的内存量，但某些内存泄漏检测器将抗议它）。对于与嵌入式服务器链接的应用程序，这些调用会启动并停止服务器。</div><div></div><div>mysql_library_init() 和mysql_library_end()实际上是#define符号，这类符号使得它们等效于mysql_server_init()和 mysql_server_end()，但其名称更清楚地指明，无论应用程序使用的是mysqlclient或mysqld库，启动或结束MySQL库 时，应调用它们。对于早期的MySQL版本，可调用mysql_server_init()和mysql_server_end()取而代之。</div><div></div><div>如 果愿意，可省略对mysql_library_init()的调用，这是因为，必要时，mysql_init()会自动调用它。</div><div></div><div>要 想连接到服务器，可调用mysql_init()来初始化连接处理程序，然后用该处理程序（以及其他信息，如主机名、用户名和密码）调用 mysql_real_connect()。建立连接后，在低于5.0.3版的API中，mysql_real_connect()会将再连接标志 （MYSQL结构的一部分）设置为1，或在较新的版本中，将其设置为0。对于该标志，值&#8220;1&#8221;指明，如果因连接丢失而无法执行语句，放弃之前，会尝试再次 连接到服务器。从MySQL 5.0.13开始，可以在mysql_options()上使用MYSQL_OPT_RECONNECT选项，以控制再连接行为。完成连接后，调用 mysql_close()中止它。</div><div></div><div>当连接处于活动状态时，客户端或许会使用 mysql_query()或mysql_real_query()向服务器发出SQL查询。两者的差别在于，mysql_query()预期的查询为指 定的、由Null终结的字符串，而mysql_real_query()预期的是计数字符串。如果字符串包含二进制数据（其中可能包含Null字节），就 必须使用mysql_real_query()。</div><div></div><div>对于每个非SELECT查询（例如INSERT、 UPDATE、DELETE），通过调用mysql_affected_rows()，可发现有多少行已被改变（影响）。</div><div></div><div>对 于SELECT查询，能够检索作为结果集的行。注意，某些语句因其返回行，类似与SELECT。包括SHOW、DESCRIBE和EXPLAIN。应按照 对待SELECT语句的方式处理它们。</div><div></div><div>客户端处理结果集的方式有两种。一种方式是，通过调用 mysql_store_result()，一次性地检索整个结果集。该函数能从服务器获得查询返回的所有行，并将它们保存在客户端。第二种方式是针对客 户端的，通过调用mysql_use_result()，对&#8220;按行&#8221;结果集检索进行初始化处理。该函数能初始化检索结果，但不能从服务器获得任何实际行。</div><div></div><div>在 这两种情况下，均能通过调用mysql_fetch_row()访问行。通过 mysql_store_result()，mysql_fetch_row()能够访问以前从服务器获得的行。通过 mysql_use_result()，mysql_fetch_row()能够实际地检索来自服务器的行。通过调用 mysql_fetch_lengths()，能获得关于各行中数据大小的信息。</div><div></div><div>完成结果集操作 后，请调用mysql_free_result()释放结果集使用的内存。</div><div></div><div>这两种检索机制是互补 的。客户端程序应选择最能满足其要求的方法。实际上，客户端最常使用的是mysql_store_result()。</div><div></div><div>mysql_store_result() 的1个优点在于，由于将行全部提取到了客户端上，你不仅能连续访问行，还能使用mysql_data_seek()或mysql_row_seek()在 结果集中向前或向后移动，以更改结果集内当前行的位置。通过调用mysql_num_rows()，还能发现有多少行。另一方面，对于大的结果 集，mysql_store_result()所需的内存可能会很大，你很可能遇到内存溢出状况。</div><div></div><div>mysql_use_result() 的1个优点在于，客户端所需的用于结果集的内存较少，原因在于，一次它仅维护一行（由于分配开销较低，mysql_use_result()能更快）。它 的缺点在于，你必须快速处理每一行以避免妨碍服务器，你不能随机访问结果集中的行（只能连续访问行），你不知道结果集中有多少行，直至全部检索了它们为 止。不仅如此，即使在检索过程中你判定已找到所寻找的信息，也必须检索所有的行。</div><div></div><div>通过API，客户 端能够恰当地对查询作出响应（仅在必要时检索行），而无需知道查询是否是SELECT查询。可以在每次mysql_query()或 mysql_real_query()后，通过调用mysql_store_result()完成该操作。如果结果集调用成功，查询为SELECT，而且 能够读取行。如果结果集调用失败，可调用mysql_field_count()来判断结果是否的确是所预期的。如果 mysql_field_count()返回0，查询不返回数据（表明它是INSERT、UPDATE、DELETE等），而且不返回行。如果 mysql_field_count()是非0值，查询应返回行，但没有返回行。这表明查询是失败了的SELECT。关于如何实现该操作的示例，请参见关 于mysql_field_count()的介绍。</div><div></div><div>无论是 mysql_store_result()还是mysql_use_result()，均允许你获取关于构成结果集的字段的信息（字段数目，它们的名称和 类型等）。通过重复调用mysql_fetch_field()，可以按顺序访问行内的字段信息，或者，通过调用 mysql_fetch_field_direct()，能够在行内按字段编号访问字段信息。通过调用mysql_field_seek()，可以改变当 前字段的光标位置。对字段光标的设置将影响后续的mysql_fetch_field()调用。此外，你也能通过调用 mysql_fetch_fields()，一次性地获得关于字段的所有信息。</div><div></div><div>为了检测和通报错 误，MySQL提供了使用mysql_errno()和mysql_error()函数访问错误信息的机制。它们能返回关于最近调用的函数的错误代码或错 误消息，最近调用的函数可能成功也可能失败，这样，你就能判断错误是在何时出现的，以及错误是什么。</div></span></span></span></td></tr></tbody></table>转自：<a href="http://blog.csdn.net/ghost1236/article/details/5746905">http://blog.csdn.net/ghost1236/article/details/5746905</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203664.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-10-11 17:56 <a href="http://www.cppblog.com/flyinghare/archive/2013/10/11/203664.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lua静态库的编译</title><link>http://www.cppblog.com/flyinghare/archive/2013/09/29/203495.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Sun, 29 Sep 2013 12:54:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/09/29/203495.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203495.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/09/29/203495.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203495.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203495.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: lua静态库的编译使用lua除了可以直接使用DLL之外，再有一个方法就是直接使用lua的静态lib，在这里我们将介绍使用静态lib的方法。1.编译静态lib我们这里使用的是lua-5.1.4.CN.7z版本，我们新建一个lib工程，注意不勾选&#8220;Pre-Compiled&nbsp;header&#8221;支持，然后将源码文件里src下目录文件全部拷贝到新建的工程目录下，除了print....&nbsp;&nbsp;<a href='http://www.cppblog.com/flyinghare/archive/2013/09/29/203495.html'>阅读全文</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203495.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-09-29 20:54 <a href="http://www.cppblog.com/flyinghare/archive/2013/09/29/203495.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Metatable In Lua 浅尝辄止</title><link>http://www.cppblog.com/flyinghare/archive/2013/09/29/203493.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Sun, 29 Sep 2013 10:39:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/09/29/203493.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203493.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/09/29/203493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203493.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203493.html</trackback:ping><description><![CDATA[<p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;"><strong>什么是Metatable</strong>&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Lua中Metatable这个概念, 国内将他翻译为元表. 元表为重定义Lua中任意一个对象(值)的默认行为提供了一种公开入口. 如同许多OO语言的操作符重载或方法重载. Metatable能够为我们带来非常灵活的编程方式.&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;具体的说, Lua中每种类型的值都有都有他的默认操作方式, 如, 数字可以做加减乘除等操作, 字符串可以做连接操作, 函数可以做调用操作, 表可以做表项的取值赋值操作. 他们都遵循这些操作的默认逻辑执行, 而这些操作可以通过Metatable来改变. 如, 你可以定义2个表如何相加等.&nbsp;<br /><br /></p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;"></p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;看一个最简单的例子, 重定义了2个表的加法操作. 这个例子中将c的__add域改写后将a的Metatable设置为c, 当执行到加法的操作时, Lua首先会检查a是否有Metatable并且Metatable中是否存在__add域, 如果有则调用, 否则将检查b的条件(和a相同), 如果都没有则调用默认加法运算, 而table没有定义默认加法运算, 则会报错.</p><div style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 895.71875px; word-break: break-all; background-color: #eeeeee;">--定义2个表<br />a&nbsp;=&nbsp;{5,&nbsp;6}<br />b&nbsp;=&nbsp;{7,&nbsp;8}<br />--用c来做Metatable<br />c&nbsp;=&nbsp;{}<br />--重定义加法操作<br />c.__add&nbsp;=&nbsp;function(op1,&nbsp;op2)<br />&nbsp;&nbsp;&nbsp;for&nbsp;_,&nbsp;item&nbsp;in&nbsp;ipairs(op2)&nbsp;do<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;table.insert(op1,&nbsp;item)<br />&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;return&nbsp;op1<br />end<br />--将a的Metatable设置为c<br />setmetatable(a,&nbsp;c)<br />--d现在的样子是{5,6,7,8}<br />d&nbsp;=&nbsp;a&nbsp;+&nbsp;b</div><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;">有了个感性的认识后, 我们看看Metatable的具体特性.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Metatable并不神秘, 他只是一个普通的table, 在table这个数据结构当中, Lua定义了许多重定义这些操作的入口. 他们均以双下划线开头为table的域, 如上面例子的__add. 当你为一个值设置了Metatable, 并在Metatable中设置了重写了相应的操作域, 在这个值执行这个操作的时候就会触发重写的自定义操作. 当然每个操作都有每个操作的方法格式签名, 如__add会将加号两边的两个操作数做为参数传入并且要求一个返回值. 有人把这样的行为比作事件, 当xx行为触发会激活事件自定义操作.</p><fieldset style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;"><legend>Metatable中定义的操作</legend>add, sub, mul, div, mod, pow, unm, concat, len, eq, lt, le, tostring, gc, index, newindex, call...</fieldset><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #eeeedd;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Lua中任何一个值都有Metatable, 不同的值可以有不同的Metatable也可以共享同样的Metatable, 但在Lua本身提供的功能中, 不允许你改变除了table类型值外的任何其他类型值的Metatable, 除非使用C扩展或其他库. setmetatable和getmetatable是唯一一组操作table类型的Metatable的方法.<br /><br /><br /><strong>Metatable与面向对象</strong><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Lua是个面向过程的语言, 但通过Metatable可以模拟出面向对象的样子. 其关键就在于__index这个域. 他提供了表的索引值入口. 这很像重写C#中的索引器, 当表要索引一个值时如table[key], Lua会首先在table本身中查找key的值, 如果没有并且这个table存在一个带有__index属性的Metatable, 则Lua会按照__index所定义的函数逻辑查找. 仔细想想, 这不正为面向对象中的核心思想继承, 提供了实现方式么. Lua中实现面向对象的方式非常多, 但无论哪种都离不开__index.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个例子中我使用了Programming In Lua中的实现OO的方式, 建立了Bird(鸟)对象, 拥有会飞的属性, 其他鸟对象基于此原型, Ostrich(鸵鸟)是鸟的一种但不会飞. 结果很明显, Bird和Ostrich分别有独立的状态.<br /><br /></p><div style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 895.71875px; word-break: break-all; background-color: #eeeeee;">local&nbsp;Bird&nbsp;=&nbsp;{CanFly&nbsp;=&nbsp;true}<br /><br />function&nbsp;Bird:New()<br />&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;b&nbsp;=&nbsp;{}<br />&nbsp;&nbsp;&nbsp;&nbsp;setmetatable(b,&nbsp;self)<br />&nbsp;&nbsp;&nbsp;&nbsp;self.__index&nbsp;=&nbsp;self<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;b<br />end<br /><br />local&nbsp;Ostrich&nbsp;=&nbsp;Bird:New()&nbsp;--Bird.CanFly&nbsp;is&nbsp;true,&nbsp;Ostrich.CanFly&nbsp;is&nbsp;true<br />Ostrich.CanFly&nbsp;=&nbsp;false&nbsp;--Bird.CanFly&nbsp;is&nbsp;true,&nbsp;Ostrich.CanFly&nbsp;is&nbsp;false</div><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;">__newindex与__index相对应, 在对table的key做更新时触发. 可以使用rawset和rawget对table的key操作来跳过这些事件的触发.&nbsp;</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><strong style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;">调用与截获</strong><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Java与C#中需要费不少周折来实现动态代理和AOP, 类似这样的功能在Lua中确很简单, 虽然被限制了很多, 但你依然能够感受到Lua的灵活. 这就是__call操作, 当值被调用时触发.&nbsp;</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里我将table类型的a做了一个函数方式的调用a(), 会触发__call. 另一个应用示例可以参见我的另一篇文章</span><a href="http://www.cnblogs.com/simonw/archive/2006/12/20/597986.html" style="color: #770000; text-decoration: none; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;">Lua中实现类似C#的事件机制<br /></a><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><div style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 895.71875px; word-break: break-all; background-color: #eeeeee;">a&nbsp;=&nbsp;{}<br />function&nbsp;a:Func()<br />&nbsp;&nbsp;&nbsp;print("simonw")<br />end<br />c&nbsp;=&nbsp;{}<br />c.__call&nbsp;=&nbsp;function(t,&nbsp;)<br />&nbsp;&nbsp;&nbsp;print("Start")<br />&nbsp;&nbsp;&nbsp;t.Func()<br />&nbsp;&nbsp;&nbsp;print("End")<br />end<br />setmetatable(a,&nbsp;c)<br />a()<br />--[[<br />Start<br />simonw<br />End<br />]]</div><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; background-color: #eeeedd;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里的示例都是以最简单的方式展现, 以便能更清晰的描述核心, 更多的资料以及具体应用请参考Programming In Lua和Lua参考手册.</span><br />转自：<a href="http://www.cnblogs.com/simonw/archive/2007/01/17/622032.html">http://www.cnblogs.com/simonw/archive/2007/01/17/622032.html</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-09-29 18:39 <a href="http://www.cppblog.com/flyinghare/archive/2013/09/29/203493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自己编译lua5.2.1</title><link>http://www.cppblog.com/flyinghare/archive/2013/09/29/203491.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Sun, 29 Sep 2013 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/09/29/203491.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203491.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/09/29/203491.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203491.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203491.html</trackback:ping><description><![CDATA[<p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;">官方发布<span style="padding: 0px; margin: 0px;">库还是5.1.4的，而且由于失误导致必须带着2个dll文件。最新的</span>源代码是5.2.1的，我们自己编译吧，目标是静态库，免得带着 dll 满世界跑。</p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;">下载源代码：<a href="http://www.lua.org/ftp/lua-5.2.1.tar.gz" rel="nofollow" style="padding: 0px; margin: 0px; color: #4466bb; outline: 0px;">http://www.lua.org/ftp/lua-5.2.1.tar.gz</a></p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;">解压备用。<span style="padding: 0px; margin: 0px;"><s style="padding: 0px; margin: 0px;">这里说句题外话，lauxlib.h 和&nbsp;lauxlib.c 我认为也应该是官方的失误，本意应该是 luaxlib.h 和 luaxlib.c 吧？</s></span></p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;">新建一个 static library 工程，把解压得到的目录下的src子目录中的所有.h和.c文件拷贝到新工程目录下。</p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;">工程中删除自动生成的 main.c 文件，添加进<span style="padding: 0px; margin: 0px; color: #e53333;">除lua.c、luac.c和</span><span style="padding: 0px; margin: 0px; color: #e53333;">lua.hpp</span><span style="padding: 0px; margin: 0px; color: #e53333;">外</span>的所有.h和.c文件。</p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;"><span style="padding: 0px; margin: 0px;">编译，得到&nbsp;</span><span style="padding: 0px; margin: 0px;">libLua.a&nbsp;</span><span style="padding: 0px; margin: 0px;">即是库。注意，如果你没有重设过输出目录，这个 liblua.a 文件应该在你的源代码目录里。</span></p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;"><span style="padding: 0px; margin: 0px;">然后把&nbsp;<span style="padding: 0px; margin: 0px;">libLua.a 放到编译器的 Lib</span>&nbsp;目录下，把&nbsp;<span style="padding: 0px; margin: 0px; line-height: 21px;">&nbsp;lauxlib.h、lua.h、luaconf.h、lualib.h 放到编译器的 include 目录下（C++用户再添加个&nbsp;lua.hpp），最好新建个 lua</span>&nbsp;子目录存放头文件更清晰。</span></p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;"><br style="padding: 0px; margin: 0px;" />其实最关键就是除开不必要的文件，实际上：<br style="padding: 0px; margin: 0px;" />编译 lua（lua.exe，解析器） 时删除luac.c，加入lua.c。<br style="padding: 0px; margin: 0px;" />编译 luac（luac.exe，字节码编译器）时删除lua.c，加入luac.c。<br style="padding: 0px; margin: 0px;" />编译 lib和dll（liblua.a和lua.dll，库）时把lua.c和luac.c都删除。</p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;"><br style="padding: 0px; margin: 0px;" /></p><p style="padding: 0px; margin: 12px 0px; line-height: 25px; letter-spacing: 1px; color: #333333; font-family: 微软雅黑, Verdana, sans-serif, 宋体; background-color: #ffffff;">另外要注意：lua 5.2.1 创建一个指向Lua解释器的指针的函数&nbsp;<span style="padding: 0px; margin: 0px;">lua_open 修改</span>为 luaL_newstate。<br style="padding: 0px; margin: 0px;" />即把工程从lua5.1库转到5.2库时，在<span style="padding: 0px; margin: 0px;">调用&nbsp;</span>lua_open() 的地方都<span style="padding: 0px; margin: 0px;">需要修改</span>为 luaL_newstate()。</p><br />转自：<a href="http://my.oschina.net/u/580100/blog/108468">http://my.oschina.net/u/580100/blog/108468</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-09-29 17:43 <a href="http://www.cppblog.com/flyinghare/archive/2013/09/29/203491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++编写Windows服务程序  </title><link>http://www.cppblog.com/flyinghare/archive/2013/09/26/203443.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Thu, 26 Sep 2013 07:24:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/09/26/203443.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203443.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/09/26/203443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203443.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203443.html</trackback:ping><description><![CDATA[<span style="color: #666666; font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 23px; text-indent: 28px; background-color: #ffffff;">环境&nbsp;VC6.0<br /><br /></span><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;"windows.h"<br /><br />SERVICE_STATUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务状态</span><span style="color: #008000; "><br /></span><br />SERVICE_STATUS_HANDLE&nbsp;&nbsp;&nbsp;gSvcStatusHandle;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务状态句柄</span><span style="color: #008000; "><br /></span><br />HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ghSvcStopEvent&nbsp;=&nbsp;NULL;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务停止句柄</span><span style="color: #008000; "><br /></span><br /><span style="color: #0000FF; ">#define</span>&nbsp;SERVER_NAME&nbsp;&nbsp;&nbsp;&nbsp;TEXT("my_server")&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务名</span><br /><br />VOID&nbsp;WINAPI&nbsp;<span style="color: #333333; font-family: verdana, sans-serif; line-height: 19px;">Server_main</span>(&nbsp;DWORD,&nbsp;LPTSTR&nbsp;*);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务入口点</span><span style="color: #008000; "><br /></span><br /><span style="color: #0000FF; ">void</span>&nbsp;ServerReportEvent(LPTSTR&nbsp;szName,LPTSTR&nbsp;szFunction);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">写Windows日志</span><span style="color: #008000; "><br /></span><br />VOID&nbsp;ReportSvcStatus(&nbsp;DWORD,&nbsp;DWORD,&nbsp;DWORD&nbsp;);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务状态和SCM交互</span><span style="color: #008000; "><br /></span><br />VOID&nbsp;WINAPI&nbsp;SvcCtrlHandler(&nbsp;DWORD&nbsp;);&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">SCM回调函数</span><span style="color: #008000; "><br /></span><br />VOID&nbsp;ServerProgram(DWORD,&nbsp;LPTSTR&nbsp;*);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">服务主程序</span><span style="color: #008000; "><br /></span><br /><span style="color: #0000FF; ">void</span>&nbsp;main()<br /><br />{&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;SERVICE_TABLE_ENTRY&nbsp;DispatchTable[]&nbsp;=<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;SERVER_NAME,&nbsp;(LPSERVICE_MAIN_FUNCTION)Server_main&nbsp;},<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;NULL,&nbsp;NULL&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(!StartServiceCtrlDispatcher(DispatchTable))<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServerReportEvent(SERVER_NAME,TEXT("StartServiceCtrlDispatcher"));<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />}<br /><br /><span style="color: #0000FF; ">static</span>&nbsp;VOID&nbsp;WINAPI&nbsp;Server_main(DWORD&nbsp;dwArgc,&nbsp;LPTSTR&nbsp;*lpszArgv&nbsp;)<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Register&nbsp;the&nbsp;handler&nbsp;function&nbsp;for&nbsp;the&nbsp;service</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatusHandle&nbsp;=&nbsp;RegisterServiceCtrlHandler(&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SERVER_NAME,&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SvcCtrlHandler);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(&nbsp;!gSvcStatusHandle&nbsp;)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServerReportEvent(SERVER_NAME,TEXT("RegisterServiceCtrlHandler"));&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;These&nbsp;SERVICE_STATUS&nbsp;members&nbsp;remain&nbsp;as&nbsp;set&nbsp;here</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwServiceType&nbsp;=&nbsp;SERVICE_WIN32_OWN_PROCESS;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">只有一个单独的服务</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwServiceSpecificExitCode&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Report&nbsp;initial&nbsp;status&nbsp;to&nbsp;the&nbsp;SCM</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;ReportSvcStatus(&nbsp;SERVICE_START_PENDING,&nbsp;NO_ERROR,&nbsp;3000&nbsp;);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Perform&nbsp;service-specific&nbsp;initialization&nbsp;and&nbsp;work.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;ghSvcStopEvent&nbsp;=&nbsp;CreateEvent(<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;default&nbsp;security&nbsp;attributes</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TRUE,&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;manual&nbsp;reset&nbsp;event</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FALSE,&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;not&nbsp;signaled</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL);&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;no&nbsp;name</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(&nbsp;ghSvcStopEvent&nbsp;==&nbsp;NULL)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReportSvcStatus(&nbsp;SERVICE_STOPPED,&nbsp;NO_ERROR,&nbsp;0&nbsp;);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Report&nbsp;running&nbsp;status&nbsp;when&nbsp;initialization&nbsp;is&nbsp;complete.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;ReportSvcStatus(&nbsp;SERVICE_RUNNING,&nbsp;NO_ERROR,&nbsp;0&nbsp;);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;TO_DO:&nbsp;Perform&nbsp;work&nbsp;until&nbsp;service&nbsp;stops.&nbsp;</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;ServerProgram(dwArgc,&nbsp;lpszArgv);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">你需要的操作在此添加代码</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(1)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Check&nbsp;whether&nbsp;to&nbsp;stop&nbsp;the&nbsp;service.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(ghSvcStopEvent,&nbsp;INFINITE);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReportSvcStatus(&nbsp;SERVICE_STOPPED,&nbsp;NO_ERROR,&nbsp;0&nbsp;);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br /><br />}<br /><br /><span style="color: #0000FF; ">void</span>&nbsp;ServerReportEvent(LPTSTR&nbsp;szName,LPTSTR&nbsp;szFunction)&nbsp;<br /><br />{&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hEventSource;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;LPCTSTR&nbsp;lpszStrings[2];<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;len&nbsp;=&nbsp;<span style="color: #0000FF; ">sizeof</span>(szFunction);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;TCHAR&nbsp;*Buffer&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;TCHAR[len];<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;hEventSource&nbsp;=&nbsp;RegisterEventSource(NULL,&nbsp;szName);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(&nbsp;NULL&nbsp;!=&nbsp;hEventSource&nbsp;)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">StringCchPrintf(Buffer,&nbsp;80,&nbsp;TEXT("%s&nbsp;failed&nbsp;with&nbsp;%d"),&nbsp;szFunction,&nbsp;GetLastError());</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(Buffer,szFunction);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpszStrings[0]&nbsp;=&nbsp;szName;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpszStrings[1]&nbsp;=&nbsp;Buffer;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReportEvent(hEventSource,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;event&nbsp;log&nbsp;handle</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EVENTLOG_ERROR_TYPE,&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;event&nbsp;type</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;event&nbsp;category</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SVC_ERROR,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;event&nbsp;identifier</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;no&nbsp;security&nbsp;identifier</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;size&nbsp;of&nbsp;lpszStrings&nbsp;array</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;no&nbsp;binary&nbsp;data</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpszStrings,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;array&nbsp;of&nbsp;strings</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;no&nbsp;binary&nbsp;data&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DeregisterEventSource(hEventSource);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />}<br /><br />VOID&nbsp;ReportSvcStatus(&nbsp;DWORD&nbsp;dwCurrentState,<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwWin32ExitCode,<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwWaitHint)<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;DWORD&nbsp;dwCheckPoint&nbsp;=&nbsp;1;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Fill&nbsp;in&nbsp;the&nbsp;SERVICE_STATUS&nbsp;structure.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwCurrentState&nbsp;=&nbsp;dwCurrentState;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwWin32ExitCode&nbsp;=&nbsp;dwWin32ExitCode;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwWaitHint&nbsp;=&nbsp;dwWaitHint;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(dwCurrentState&nbsp;==&nbsp;SERVICE_START_PENDING)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwControlsAccepted&nbsp;=&nbsp;0;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;gSvcStatus.dwControlsAccepted&nbsp;=&nbsp;SERVICE_ACCEPT_STOP;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(&nbsp;(dwCurrentState&nbsp;==&nbsp;SERVICE_RUNNING)&nbsp;||<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(dwCurrentState&nbsp;==&nbsp;SERVICE_STOPPED)&nbsp;)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gSvcStatus.dwCheckPoint&nbsp;=&nbsp;0;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;gSvcStatus.dwCheckPoint&nbsp;=&nbsp;dwCheckPoint++;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Report&nbsp;the&nbsp;status&nbsp;of&nbsp;the&nbsp;service&nbsp;to&nbsp;the&nbsp;SCM.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;SetServiceStatus(&nbsp;gSvcStatusHandle,&nbsp;&amp;gSvcStatus&nbsp;);<br /><br />}<br /><br />VOID&nbsp;WINAPI&nbsp;SvcCtrlHandler(&nbsp;DWORD&nbsp;dwCtrl&nbsp;)<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Handle&nbsp;the&nbsp;requested&nbsp;control&nbsp;code.&nbsp;</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;<span style="color: #0000FF; ">switch</span>(dwCtrl)&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">case</span>&nbsp;SERVICE_CONTROL_STOP:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReportSvcStatus(SERVICE_STOP_PENDING,&nbsp;NO_ERROR,&nbsp;0);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Signal&nbsp;the&nbsp;service&nbsp;to&nbsp;stop.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetEvent(ghSvcStopEvent);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">case</span>&nbsp;SERVICE_CONTROL_INTERROGATE:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Fall&nbsp;through&nbsp;to&nbsp;send&nbsp;current&nbsp;status.</span><span style="color: #008000; "><br /></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">default</span>:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;ReportSvcStatus(gSvcStatus.dwCurrentState,&nbsp;NO_ERROR,&nbsp;0);<br /><br />}</div>转自：<a href="http://3140618.blog.163.com/blog/static/745179720109286165959/">http://3140618.blog.163.com/blog/static/745179720109286165959/</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-09-26 15:24 <a href="http://www.cppblog.com/flyinghare/archive/2013/09/26/203443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>失效迭代器（Invalidating Iterators）</title><link>http://www.cppblog.com/flyinghare/archive/2013/09/24/203415.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Tue, 24 Sep 2013 13:12:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/09/24/203415.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/203415.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/09/24/203415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/203415.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/203415.html</trackback:ping><description><![CDATA[<div id="article_content" style="margin: 20px 0px 0px; line-height: 26px; font-family: Arial; color: #333333; background-color: #ffffff;"><div style="font-family: Arial, Verdana, sans-serif; font-size: 12px; word-break: break-word; word-wrap: break-word; margin: 5px; overflow-y: auto;">当一个容器变化时，指向该容器中元素的迭代器可能失效。这使得在迭代器变化期间改变容器容易出现问题。在这方面，不同的容器提供不同的保障：<br />vectors: 引起内存重新分配的插入运算使所有迭代器失效，插入也使得插入位置及其后位置的迭代器失效，删除运算使得删除位置及其后位置的迭代器失效.<br />vector的push_back操作 可能没事，但是一旦引发内存重分配，所有迭代器都会失效；<br />vector的insert操作 插入点之后的所有迭代器失效；但一旦引发内存重分配，所有迭代器都会失效；<br />vector的erase操作 插入点之后的所有迭代器失效；<br />vector的reserve操作 所有迭代器失效（因为它导致内存重分配）；<br /><br />list/map: 插入不会使得任何迭代器失效；删除运算使指向删除位置的迭代器失效，但是不会失效其他迭代器.<br />deque的insert操作 所有迭代器失效；<br />deque的erase操作 所有迭代器失效；<br /><br />1. 对于<span style="color: #ff0000;">关联容器(如map, set, multimap,multiset)，</span>删除当前的iterator，仅仅会使当前的iterator失效，只要在erase时，递增当前iterator即可。这是因为map之类的容器，使用了红黑树来实现，插入、删除一个结点不会对其他结点造成影响。erase迭代器只是被删元素的迭代器失效，但是返回值为void，所以要采用<span style="color: #ff0000;">erase(iter++)</span>的方式删除迭代器。<br />for (iter = cont.begin(); it != cont.end();)<br />{<br />&nbsp; &nbsp;(*iter)-&gt;doSomething();<br />&nbsp; &nbsp;if (shouldDelete(*iter))<br />&nbsp; &nbsp; &nbsp; cont.erase(iter++);<br />&nbsp; &nbsp;else<br />&nbsp; &nbsp; &nbsp; ++iter;<br />}<br /><br />2. 对于<span style="color: #ff0000;">序列式容器(如vector,deque)</span>，删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存，删除一个元素导致后面所有的元素会向前移动一个位置。所以不能使用erase(iter++)的方式，还好erase方法可以返回下一个有效的iterator。<br />for (iter = cont.begin(); iter != cont.end();)<br />{<br />&nbsp; &nbsp;(*it)-&gt;doSomething();<br />&nbsp; &nbsp;if (shouldDelete(*iter))<br />&nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #ff0000;">iter = cont.erase(iter);&nbsp;</span><br />&nbsp; &nbsp;else<br />&nbsp; &nbsp; &nbsp; ++iter;<br />}<br />3. 对于<span style="color: #ff0000;">list</span>来说，它使用了不连续分配的内存，并且它的erase方法也会返回下一个有效的iterator，因此<span style="color: #ff0000;">上面两种方法都可以使用。</span><br /><br />删除数组中某个元素后连续重复的元素，例如 1，1，2，3，3，1，1，1，4，0 ---&gt; 1， 2，3，1，4，0。给出问题的一个正确的实现：<br /><div bg_cpp"="" style="width: 677.15625px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">iostream</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;&nbsp;<br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">vector</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;&nbsp;<br /></span><span style="color: #0000FF; ">using</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">namespace</span><span style="color: #000000; ">&nbsp;std;&nbsp;&nbsp;<br />&nbsp;&nbsp;<br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;main(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;argc,&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;argv[])&nbsp;&nbsp;<br />{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;a[]&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;{</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">};&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;size&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(a)</span><span style="color: #000000; ">/</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(a[</span><span style="color: #000000; ">0</span><span style="color: #000000; ">]);&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;vector</span><span style="color: #000000; ">&lt;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;vec(a,&nbsp;a</span><span style="color: #000000; ">+</span><span style="color: #000000; ">size);&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;vector</span><span style="color: #000000; ">&lt;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">::iterator&nbsp;iter&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;vec.begin();&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;previous&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">++</span><span style="color: #000000; ">iter;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(;&nbsp;iter&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;vec.end();)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;previous)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iter&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;vec.erase(iter);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;previous&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">++</span><span style="color: #000000; ">iter;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">(iter&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;vec.begin();&nbsp;iter&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;vec.end();&nbsp;</span><span style="color: #000000; ">++</span><span style="color: #000000; ">iter)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000; ">&lt;&lt;</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter&nbsp;</span><span style="color: #000000; ">&lt;&lt;</span><span style="color: #000000; ">&nbsp;endl;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;&nbsp;<br />} &nbsp;</span></div></div>PS. 不过实际上这个问题，用vector来实现不是很适合，因为每次删除一个元素，都会引起vector的一个resize操作。resize的时间复杂度是O(n)，整个的resize操作要花费O(n^2)。最好是选择list最为容器，list最适合那些需要在容器中间做插入、删除的例子。</div><div></div></div><br />转自：<a href="http://blog.csdn.net/heyutao007/article/details/6937236">http://blog.csdn.net/heyutao007/article/details/6937236</a><img src ="http://www.cppblog.com/flyinghare/aggbug/203415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-09-24 21:12 <a href="http://www.cppblog.com/flyinghare/archive/2013/09/24/203415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>几个软件研发团队管理的小问题</title><link>http://www.cppblog.com/flyinghare/archive/2013/08/22/202699.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Thu, 22 Aug 2013 06:21:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/08/22/202699.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/202699.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/08/22/202699.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/202699.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/202699.html</trackback:ping><description><![CDATA[<h1><a id="cb_post_title_url" href="http://www.cnblogs.com/wanghui9072229/archive/2011/03/18/1988477.html" style="margin: 0px; padding: 0px; color: #075db3; text-decoration: none;">几个软件研发团队管理的小问题</a></h1><div style="margin: 0px; clear: both; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 18px; background-color: #fefef2;"></div><div style="margin: 5px 0px 0px; padding: 5px 2px 5px 5px; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;"><div id="cnblogs_post_body" style="margin: 0px; word-break: normal !important;"><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">最近在与一位总经理交流的时候，他谈到他们公司的软件研发管理，说：&#8220;我们公司最大的问题是项目不能按时完成，总要一拖再拖。&#8221;他问我有什么办法能改变这个境况。从这样一个问题开始，在随后的交谈中，又引出他一连串在软件研发管理中的遇到的问题，包括：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 现有代码质量不高，新来的开发人员接手时宁愿重写，也不愿意看别人留下的&#8220;烂&#8221;代码，怎么办？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 重构会造成回退，怎样避免？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 有些开发人员水平相对不高，如何保证他们的代码质量？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 软件研发到底需不需要文档？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 要求提交代码前做Code Review，而开发人员不做，或敷衍了事，怎么办？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 当有开发人员在开发过程中遇到难题，工作无法继续，因而拖延进度，怎么解决？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">. 如何提高开发人员的主观能动性？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">其实，每个软件研发团队的管理者都面临着或曾经面临过这些问题，也都有着自己的管理&#8220;套路&#8221;来应对这些问题。我把我的&#8220;套路&#8221;再此絮叨絮叨。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">1. 项目不能按时完成，总要一拖再拖，怎么改变？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">找解决办法前，当然要先知道问题为什么会出现。这位总经理说：&#8220;总会不断地有需求要改变和新需求提出来，使原来的开发计划不得不延长。&#8221;原来如此。知道根源，当然解决办法也就有了，那就是&#8220;敏捷&#8221;。敏捷开发因其迭代（Iterative）和增量（Incremental）的思想与实践，正好适合&#8220;需求经常变化和增加&#8221;的项目和产品。在我讲述了敏捷的一些概念，特别是Scrum的框架后，总经理也表示了对&#8220;敏捷&#8221;的认同。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">其实仔细想想，这里面还有一个非常普遍的问题。对于产品的交付时间或项目的完成时间，往往由高级管理层根据市场情况决策和确定。在很多软件企业中，这些决策者在决策时往往忽略了一个重要的参数，那就是团队的生产率（Velocity）。生产率需要量化，而不是&#8220;拍脑门子&#8221;感觉出来的。敏捷开发中有关于如何估算生产率的方法。所以使用敏捷，在估算产品交付时间或项目完成时间时，是相对较准确的。Scrum创始人之一的Jeff Sutherland说，他在一个风险投资团队做敏捷教练时，团队中的资深合伙人会向所有的待投资企业问同一个问题：&#8220;你们是否清楚团队的生产率？&#8221;而这些企业都很难做出明确的答复。软件企业要想给产品定一个较实际的交付日期，就首先要弄清楚自己的软件生产率。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">2. 现有代码质量不高，新来的开发人员接手时宁愿重写，也不愿意看别人留下的&#8220;烂&#8221;代码，怎么办？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">这可能是很多软件开发工程师都有过的体验，在接手别人的代码时，看不懂、无法加新功能，读代码读的头疼。这说明什么？排除接手人个人水平的因素，这说明旧代码可读性、可扩展性比较差。怎么办？这时，也许重构是一种两全其美的办法。接手人重构代码，既能改善旧代码的可读性和可扩展性，又不至于因重写代码带来的时间上的风险。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">从接手人心理的角度看，重构还有一个好的副作用，就是代码重构之后，接手人觉得那些原来的&#8220;烂&#8221;代码被修改成为自己引以自豪的新成就。《Scrum敏捷软件开发》的作者Mike Cohn写到过：&#8220;我的女儿们画了一幅特别令人赞叹的杰作后，她们会将它从学校带回家，并想把它展示在一个明显的位置，也就是冰箱上面。有一天，在工作中，我用C++代码实现了某个特别有用的策略模式的程序。因为我认定冰箱门适合展示我们引以为豪的任何东西，所以我就将它放上去了。如果我们一直对自己工作的质量特别自豪，可以骄傲地将它和孩子的艺术品一样展示在冰箱上，那不是很好吗？&#8221;所以这个积极的促进作用，将使得接手人感觉修改的代码是自己的了，而且期望能够找到更多的可以重构的东西。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">3. 重构会造成回退，怎样避免？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">重构确实很容易造成回退（Regression）。这时，重构会起到与其初衷相反的作用。所以我们应该尽可能多地增加单元测试。有些老产品，旧代码，可能没有或者没有那么多的单元测试。但我们至少要在重构前，增加对要重构部分代码的单元测试。基于重构目的的单元测试，应该遵循以下的原则（见《重构》第4章：构筑测试体系）：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 编写未臻完善的测试并实际运行，好过对完美测试的无尽等待。测试应该是一种风险驱动行为，所以不要去测试那些仅仅读写一个值域的访问函数，应为它们太简单了，不大可能出错。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 考虑可能出错的边界条件，把测试火力集中在哪儿。扮演&#8220;程序公敌&#8221;，纵容你心智中比较促狭的那一部分，积极思考如何破坏代码。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 当事情被公认应该会出错时，别忘了检查是否有异常如期被抛出。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 不要因为&#8220;测试无法捕捉所有Bug&#8221;，就不撰写测试代码，因为测试的确可以捕捉到大多数Bug。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- &#8220;花合理时间抓出大多数Bug&#8221;要好过&#8220;穷尽一生抓出所有Bug&#8221;。因为当测试数量达到一定程度之后，测试效益就会呈现递减态势，而非持续递增。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">说到《重构》这本书，其实在每个重构方法中都有&#8220;作法（Mechanics）&#8221;一段，在重构的实践中按照上面所述的步骤进行是比较稳妥的，同时也能避免很多不经意间制造的回退出现。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">4. 要求提交代码前做Code Review，而开发人员不做，或敷衍了事，怎么办？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">如果每个开发人员都是积极主动的，Code Review的作用能落到实处。但如果不是呢？团队管理者需要一些手段促使其有效地进行Code Review。首先，我们采用的Code Review有2种形式，一是Over-the-shoulder，也就是2个人座在一起，一个人讲，另一个人审查。二是用工具Code Collaborator来进行。无论哪种形式，在提交代码时，必须注明关于审查的信息，比如：审查者（Reviewer）的名字或审查号（Review ID，Code Collaborator自动生成），每天由一名专职人员来检查Checklist中的每一条，看是否有人漏写这些信息，如果发现会提醒提交的人补上。另外，某段提交的代码出问题，提交者和审查者都要一起来解决出现的问题，以最大限度避免审查过程敷衍了事。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">博主Inovy在某个评论说的很形象：&#8220;木（没）有赏罚的制度，就是带到厕所的报纸，看完就可以用来擦屁股了。&#8221;没有奖惩制度作保证，当然上面的要求没有什么效力。所以，当有人经常不审查就提交，或审查时不负责任，它的绩效评定就会因此低一点，而绩效的评分是跟每年工资涨落挂钩的。说白了，可能某个人会因为多次被查出没有做Code Review就提交代码，而到年底加薪时比别人少涨500块钱。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">5. 软件研发到底需不需要文档？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">软件研发需要文档的起原可能有2种，一是比较原始的，需要文档是为了当开发人员离职后，企业需要接手的人能根据文档了解他所接手的代码或模块的设计。二是较高层次的，企业遵从ISO9001质量管理体系或CMMI。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">对于第一种，根源可能来自于两个方面：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 原开发人员设计编码水平不高，其代码可读性较差。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 设计思想和代码只有一个人了解，此人一旦离职，无人知道其细节。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">在编码前写一些简单的设计文档，有助于理清思路，尤其是辅以一些UML图，在交流时也是有好处的。但同时，我们也应该提高开发人员的编码水平增加其代码的可读性，比如增强其变量命名的可读性、用一些被大家所了解的设计模式来替代按自己某些独特思路编写的代码、增加和改进注释等等，以减少不必要的文档。另外推行代码的集体所有权（Collective Ownership），避免某些代码只被一个人了解，这样可以减少以此为目的而编写的文档。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">对于第二种，情况有些复杂。接触过敏捷开发的人都知道《敏捷宣言》中的&#8220;可以工作的软件胜于面面俱到的文档&#8221;。接触过CMMI开发或者ISO9001质量管理体系的人知道它们对文档的要求是多么的高。它们看起来水火不相容。但是，它们的宗旨是一致的，即：构建高质量的产品。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">对于敏捷，使用手写用户故事来记录需求和优先级的方法，以及在白板上写画的非正式设计，是不能通过ISO9001的审核的，但当把它们复印、拍照、增加序号、保存后，可以通过审核。每次都是成功的Daily Build和Auto Test报告无法证明它们是否真正被执行并真正成功，所以不能通过ISO9001的审核。但添加一个断言失败（类似assert(false)的断言）的测试后，则可以通过审核。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">CMMI与敏捷也是互补的，前者告诉组织在总体条款上做什么，但是没有说如何去做，后者是一套最佳实践。SCRUM之类的敏捷方法也被引入过那些已通过CMMI5级评估的组织。很多企业忘记了最终目标是改进他们构建软件及递交产品的方式，相反，它们关注于填写按照CMMI文档描述的假想的缺陷，却不关心这些变化是否能改进过程或产品。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">所以敏捷开发在过程中只编写够用的文档，和以&#8220;信息的沟通、符合性的证据以及知识共享&#8221;作为主要目标的质量体系文档要求并不矛盾。在实践中，我们可以按以下方法做，在实现SCRUM的同时，符合审核和评估的要求：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 制作格式良好的、被细化的、被保存的和能跟踪的Backlog。复印和照片同样有效。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 将监管需要的文档工作也放入Backlog。除了可以确保它们不被忘记，还能使监管要求的成本是可见的。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 使用检查列表，以向审核员或评估员证明活动已执行。团队对&#8220;完成&#8221;的定义(Definition of &#8220;Done&#8221;)可以很容易转变为一份检查列表。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">- 使用敏捷项目管理工具。它其实就是开发程序和记录的电子呈现方式。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">总而言之，软件研发需要文档（但文档的形式可以是多种多样的，用Word写的文字式的文件是文档，用Visio画的UML图也是文档，保存在Quality Center中的测试用例也是文档），同时我们只需写够用的文档。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">6. 当有开发人员在开发过程中遇到难题，工作无法继续，因而拖延进度，怎么解决？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">这也是个常遇到的问题。如果管理者对于某个工程师的具体问题进行指导，就会陷入过度微观管理的境地。我们需要找到宏观解决办法。一，我们基于Scrum的&#8220;团队有共同的目标&#8221;这一规则，利用前面提到的集体所有权，当出现这些问题时，用团队中所有可以使用的力量来帮助其摆脱困境，而不是任其他人袖手旁观。当然这里会牵扯到绩效评定的问题，比如：提供帮助的人会觉得，他的帮助无助于自己绩效评定的提高，为什么要提供帮助。这需要人力资源部门在使用Scrum开发的团队的绩效评估中，尽量消除那些倾向个人的因素，还要包含团队协作的因素，广泛听取个方面的意见，更频繁地评估绩效等等。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">二，即使动用所有可以使用的力量，如果某个难题真的无法逾越，为了减少不能按时交付的风险，产品负责人应当站出来，并有所作为。要么重新评估Backlog的优先级，使无法继续的Backlog迟一点交付，先做一些相对较低优先级的Backlog，以保证整体交付时间不至于延长；要么减少部分功能，给出更多的时间去攻克难题。总之逾越技术上难关会使团队的生产率下降，产品负责人必须作出取舍。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">7. 有些开发人员水平相对不高，如何保证他们的代码质量？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">当然首先让较有经验的人Review其要提交的代码，这几乎是所有管理者会做的事。除此之外，管理者有责任帮助这些人（也包括水平较高的人）提高水平，他们可以看一些书，上网看资料，读别人的代码等等，途经还是很多的。但问题是你如何去衡量其是否真正有所收获。我们的经验是，在每年大约3月份为每个工程师制定整个年度的目标，每个人的目标包括产品上的，技术上的，个人能力上的等4到5项。半年后和一年后，要做两次Performance Review，目标是否实现，也会跟绩效评定挂钩。我们在制定目标时，遵循SMART原则，即：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">Specific（明确的）：目标应该按照明确的结果和成效表述。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">Measurable（可衡量的）：目标的完成情况应该可以衡量和验证。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">Aligned（结盟的）：目标应该与公司的商业策略保持一致。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">Realistic（现实的）：目标虽然应具挑战性，但更应该能在给定的条件和环境下实现。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">Time-Bound（有时限的）：目标应该包括一个实现的具体时间。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">比如：某个人制定了&#8220;初步掌握本地化技术&#8221;的目标，他要确定实现时间，要描述学习的途经和步骤，要通过将技术施加到公司现有的产品中，为公司产品的本地化/国际化/全球化作一些探索，并制作Presentation给团队演示他的成果，并准备回答其他人提出的问题。团队还为了配合其实现目标，组织Tech Talk的活动，供大家分享每个人的学习成果。通过这些手段，提高开发人员的自学兴趣，并逐步提高开发人员的技术水平。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;"><strong style="margin: 0px; padding: 0px;">8. 如何提高开发人员的主观能动性？</strong></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">提高开发人员的主观能动性，少不了激励机制。不能让开发人员感到，5年以后的他和现在比不会有什么进步。你要让他感到他所从事的是一个职业（Career），而不只是一份工作（Job）。否则，他们是不会主动投入到工作中的。我们的经验是提供一套职业发展的框架。框架制定了2类发展道路，管理类（Managerial Path）和技术类（Technical Path），6个职业级别（1-3级是Entry/Associate，Intermediate，Senior。4级管理类是Manager/Senior Manager，技术类是Principal/Senior Principal。5级管理类是Director/Senior Director，技术类是Fellow/Architect。6级是Executive Management）。每个级别都有13个方面的具体要求，包括：范围（Scope）、跨职能（Cross Functional）、层次（Level）、知识（Knowledge）、指导（Guidance）、问题解决（Problem Solving）、递交成果（Delivering Result）、责任感（Responsbility）、导师（Mentoring）、交流（Communication）、自学（Self-Learning），运作监督（Operational Oversight），客户响应（Customer Responsiveness）。每年有2次提高级别的机会，开发人员一旦具备了升级的条件，他的Supervisor将会提出申请，一旦批准，他的头衔随之提高，薪水也会有相对较大提高。从而使每个开发人员觉得&#8220;有奔头&#8221;，自然他们的主观能动性也就提高了。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 1.5;">上面的&#8220;套路&#8221;涉及了软件研发团队管理中的研发过程、技术实践、文档管理、激励机制等一些方面。但只是九牛一毛，研发团队管理涵盖的内容还有很多很多，还需要管理者在不断探索和实践的道路上学习和掌握。</p></div></div>转自：<a href="http://www.cnblogs.com/wanghui9072229/archive/2011/03/18/1988477.html">http://www.cnblogs.com/wanghui9072229/archive/2011/03/18/1988477.html</a><img src ="http://www.cppblog.com/flyinghare/aggbug/202699.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-08-22 14:21 <a href="http://www.cppblog.com/flyinghare/archive/2013/08/22/202699.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置管理的精髓</title><link>http://www.cppblog.com/flyinghare/archive/2013/08/09/202429.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Fri, 09 Aug 2013 03:32:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/08/09/202429.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/202429.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/08/09/202429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/202429.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/202429.html</trackback:ping><description><![CDATA[<div style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; font-size: 12px; line-height: normal; background-color: #67a10f;"><div><h3><span style="font-size: 20px; font-family: 微软雅黑, 黑体, Arial, Helvetica, sans-serif;">配置管理的精髓</span>&nbsp;&nbsp;</h3><p clearfix="" nbw-act=""  fc06"="" style="zoom: 1; margin: 0px 0px 20px; padding: 0px; color: #3e6700; line-height: 20px;"><span style="float: left;"><span style="margin: 0px 2px;">2012-05-30 18:00:46</span><span style="margin: 0px 2px;">|&nbsp;&nbsp;分类：</span>&nbsp;<a m2a"="" href="http://blog.163.com/wangdan10799@126/blog/#m=0&amp;t=1&amp;c=fks_087071083086083069085086080095085086083064084086095064" title="配置管理" style="cursor: pointer; text-decoration: none; color: #e6ff82;">配置管理</a>&nbsp;<span id="$_blogTagTitle" style="margin: 0px 2px;">|&nbsp;&nbsp;标签：</span><span id="$_blogTagInfo" style="color: #e6ff82;"><a href="http://blog.163.com/wangdan10799@126/blog/#m=0&amp;t=3&amp;c=配置管理"  m2a"="" style="cursor: pointer; text-decoration: none; color: #e6ff82;">配置管理</a>&nbsp;&nbsp;<br /></span></span><span fc07=""  ztag"="" style="float: right; color: #a5d857;"><span style="margin: 0px 2px;">|</span><span fc03"="" id="$_fontswitch" style="color: #e6ff82; position: relative; cursor: default;">字号</span></span><span pnt=""  fc03"="" id="$_blog_subscribe" style="cursor: pointer; float: right; color: #e6ff82;">&nbsp;<a style="cursor: pointer;">订阅</a></span></p></div></div><div style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; font-size: 12px; line-height: normal; background-color: #67a10f;"></div><div style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; font-size: 12px; line-height: normal; background-color: #67a10f;"></div><div fc05="" fc11="" nbw-blog="" ztag=""  js-fs2"="" style="line-height: 25px; word-wrap: break-word; color: #02540a; margin: 15px 0px; padding-top: 5px; padding-bottom: 5px; overflow: hidden; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;"><p style="margin: 0px 0px 10px; padding: 0px;">配置管理的精髓&nbsp;<br />贝尔实验室先进技术研究院&nbsp;&nbsp; 姜海东</p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 随着国内软件业的崛起和成熟，软件配置管理越来越得到重视。可以说，软件业要想更好的发展，没有软件配置管理的支持是不可能的。手工作坊式的软件开发模式将会成为历史，如何把国外成熟的软件配置管理理论和经验消化吸收，进而应用到国内软件开发中就成为国内软件业迫在眉睫的任务了。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 软件配置管理是管理和技术相结合的一门学科。应该说，软件配置管理理论难以理解是其难以实践的原因。本文试从基本概念的角度来探讨这门对软件开发具有重要意义的领域。</p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br />什么是配置管理&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在软件开发中，变更是不可避免的。从某种角度上讲，软件开发过程就是一个变更的过程。有些变更是有益的，是具有创造性的，但是，也有些变更是有害的，导致混乱的。正像James Bach 总结的那样：&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>我们为变更所困扰，因为代码中的一个极小的混乱可能带来产品的大的故障，但是，他也能够修复大的故障或启用奇妙的新能力。我们为变更所困扰，因为某个喜欢恶作剧的单个开发者可能破坏掉项目，但是，一些奇妙的思想也源自那些喜欢恶作剧的人员。&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因此，如何管理这些变更是一个软件开发能否成功的关键。简言之，软件配置管理就是管理变更的过程，它贯穿着几乎软件的整个生命周期。成功的配置管理系统可以提高产品的质量、项目开发效率，而且最大限度的减少对个别&#8220;英雄&#8221;式人员的依赖。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 尽管配置管理（Configuration Management ）这个概念被提出有几十年了，但是，业内还没有一个全面而权威的定义。Configuration 的意思是&#8220;使成形&#8221;，它来源于拉丁语的com-（表示&#8220;与&#8221;或者&#8220;一起&#8221;）和figurate ( 形成) 。它还有一个意思是&#8220;组成部件或元素的相对排列&#8221;。因此，配置管理（ConfigurationManagement ）指的是管理组成部件或者元素的相对排列。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置管理的概念来自于硬件领域，美国国防部最早使用了配置管理的概念。我们知道一架飞机的构成非常复杂，比如机头、机身、机翼和机尾等。不同型号飞机的各个部分是不能随便组装的。因此，我们只有把相匹配的部件组装在一起，才能构成了一个功能完备的飞机整体。随着技术的提高，各个部件可能还要进行功能改善，我们还要使得不同版本的部件能够正确无误组合在一起。&nbsp;<br />准确地说：&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;配置管理是对产品进行标识、存储和控制，以维护其完整性、可追溯性以及正确性的学科。&nbsp;<br />从上面的描述，我们知道，配置管理的基本单位是配置项。软件配置项可以是：</p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;">&nbsp;与合同、过程、计划和产品有关的文档和数据</div></li><li><div style="margin-right: 0px;">源代码、目标代码和可执行代码</div></li><li><div style="margin-right: 0px;">相关产品，包括软件工具、库内的可复用软件、外购软件及用户提供的软件</div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;">&nbsp;<br />&nbsp; 从&#8220;哲学&#8221;意义上讲，配置管理记录配置项的三个方面：&nbsp;<br /></p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;">从哪里来？此项可归结为WWW 的问题，（Who）谁创建的？（When）什么时间创建的？（Why）为什么创建此配置项？</div></li><li><div style="margin-right: 0px;">当前在哪里？此项纪录配置项当前的存储位置以及状态。</div></li><li><div style="margin-right: 0px;">将到哪里去？通过配置控制来把配置项&#8220;组装&#8221;到正确的版本中去。</div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;">&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置项可以是大粒度的，也可以是小粒度的。如果跟踪个别需求，那么不必要把整个需求规格说明文档定义为一个配置项，可以把每个需求定义为配置项；如果把软件开发工具也放入配置管理系统，那么把配置项定义为文件级就不合适了，只需要跟踪开发工具的版本，即把整个配置工具定义为一个配置项就足够了。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;简而言之，配置项可以是文件级粒度的，也可以使文件版本级粒度的。当然，粒度越小管理的成本越高，但是配置的精度也就越高。&nbsp;<br />一个完整的SCM系统要具有三个核心功能：配置标识、版本控制、变更控制、配置状态统计和配置审核。其中变更控制包括基线管理、变更请求管理、构建管理和发布管理。如下图所示。&nbsp;<br /><br />下面，我们来具体理解这些概念。&nbsp;<br />&nbsp;<br /><strong>配置标识&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置标识就是识别产品的结构、产品的构件及其类型，为其分配唯一的标识符，也就是说，每一个配置项要有一个唯一标识。一般说来，标识包括两个方面：一是文件名，二是版本，可用如下一个二元组来标识：&lt; 文件名，版本&gt; 。每个项目首先要确定一套命名规则，例如，采用&#8220;系统.子系统.模块.文件&#8221;的方式，&lt;/videoConference/audio/compressing/m a in.c , 2.1&gt;就是一个唯一标识。&nbsp;<br />&nbsp;<br /><strong>版本控制&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 版本控制就是对在软件开发过程中所创建的配置对象的不同版本进行管理，保证任何时候都能取到正确的版本以及版本的组合。当前，这方面典型的工具有如VSS 和CVS 。</p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br /><strong>变更控制&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在软件开发过程，要产生许多变更，比如，配置项、配置、基线、构建的版本、发布版本等。对于所有的变更，都要有一个控制机制，以保证所有变更都是可控的、可跟踪的、可重现的。对变更进行控制的机构称为变更控制委员会（Change Control Board，简称<br />CCB ）。变更控制委员会要定期召开会议，对近期所产生的变更请求进行分析、整理，并做出决定。而且要遵循一定的变更机制。&nbsp;<br />&nbsp;&nbsp;<br />下面是一个典型的变更机制：&nbsp;&nbsp;<br /><strong>变更请求管理&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 变更请求管理就是对变更请求（Change Request，简称CR）进行分类、追踪和管理的过程来实现的。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 变更的起源有两种：功能变更和缺陷修补（Bug-Fix）。功能变更是为了增加或者删除某些功能。缺陷修补则是对已存在的缺陷进行修补。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对变更请求的有效管理可以提高产品管理的透明度，经理可以清楚的知道当前产品的进展情况，比如有多少个新产生的CR，已经解决了多少CR等等，有利于经理做出正确的决策。&nbsp;<br />&nbsp;<br /><strong>基线管理&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基线是指经过正式评审和批准，可作为下一步工作的基准的一个配置。软件开发过程中，无论是需求分析、设计、测试都需要在完成时建立基线，以作为下一步工作的基础。</p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过基线管理可以使用户能够通过对适当版本的选择来组成特定属性（配置）的软件系统，这种灵活的&#8220;组装&#8221;策略使得配置管理系统象搭积木似的使用已有的积木（版本）组装成各种各样、不同功能的模型。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基线的变更需要一个严格的流程，需要提出申请，经过审批，然后才能进行。&nbsp;<br /><strong>构建管理&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在做构建时，我们需要首先取出正确的配置，然后再做构建。我们可以利用基线，可以取出某个基线的所有配置项，也可以利用配置管理系统的构建功能直接在工作空间内做构建。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 构建管理需要配置管理工具的支持。&nbsp;<br /><strong>发布管理&nbsp;<br /></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;软件产品的每个版本都是一组配置项（源代码、文档、数据）的集合。举个例子来说，我们要发布软件的32.6 版本，那么我们就要把源代码、文档、数据中所有应该包含到这个版本中的正确配置项检出。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所以如何管理每个版本中包含哪些配置项是非常重要的。&nbsp;&nbsp;<br /><strong>状态报告&nbsp;<br /></strong>状态报告要回答所谓4W 的问题：&nbsp;<br />What：发生了什么事？&nbsp;<br />Who：谁做的此事？&nbsp;<br />When：此事是什么时候发生的？&nbsp;<br />Why：为什么做此事？&nbsp;<br />状态报告要能够报告所有配置项以及变更请求的状态，通过量化的数据和报表反映项目开发进度的状态。&nbsp;<br /><strong>配置审核&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置审核要审查整个配置管理过程是否符合规范，配置项是否与需求一致，记录正确，配置的组成是否具有一致性等等。比如，需求分析文档提交后，需要由一个由相关人组成的小组进行正式评审，只有通过了评审才能基线化。对于源代码也一样，一般说来，每行代码都要进行评审（Review），只有通过评审才能交由测试人员进行测试。&nbsp;<br /><strong>实施配置管理的好处&nbsp;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们知道软件有三个要素：时间、预算和质量。一个成功的软件就是要在限定的时间内，不超过预算，交付符合质量要求的产品。真正实施配置管理后，我们会对产品的开发过程进行有效的控制，可以加快开发进度，降低开发成本，保证产品的质量。&nbsp;<br /><strong>产品经理可以得到什么好处呢？</strong>&nbsp;<br /></p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;">准确掌握项目的开发进度。配置管理系统可以提供详尽的状态报告，例如当前系统有多少个Bug，所有Bug 的状态如何？已经解决了多少Bug？</div></li><li><div style="margin-right: 0px;">了解项目组成员的工作负荷、工作效率以及工作质量。例如，我们可以知道当前分配给每个成员的工作量，每个成员已完成的工作量，每个成员未通过正式评审的工作比例等等。</div></li><li><div style="margin-right: 0px;">减少人员流动所带来的影响。每个成员的所有变更，包括文档、代码的增删都是可追踪的，而且对于变更的原因、描述也都有记录。这样，一旦成员离开，其它成员就可以在最短的时间里接手。</div></li><li><div style="margin-right: 0px;">&nbsp;有效提高过程管理，配置管理产生的许多数据可作为管理者度量项目的依据。</div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br /><strong>开发人员和测试人员可以得到什么好处呢？</strong></p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;">&nbsp;提交的代码被有效保存，开发人员再也不用花费精力去保存各个版本了。</div></li><li><div style="margin-right: 0px;">&nbsp;提高团队的协作效率。开发人员之间以及开发人员和测试人员之间可以有效的沟通，大家都互相知道其它人的工作状态。</div></li><li><div style="margin-right: 0px;">&nbsp;提高修复缺陷的效率。可以依据Bug 发现的版本，迅速重建环境，重现Bug，快速定位代码，找出根源。</div></li><li><div style="margin-right: 0px;">职责清楚，任务明确。每一步的工作都是基于某一基线的，比如，设计文档是依据基线化了的需求分析文档，这样一旦出现问题，就可以找出问题出在什么地方。</div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，实施配置管理的好处远不止这些。软件配置管理作为软件开发的基石，它提供了一个协作开发的环境，只有大家共同遵守配置管理规范，互相协作才能保证项目的成功。&nbsp;<br />&nbsp;<br />结束语&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置管理本身无论从理论和实践都在不断丰富和发展。例如，配置管理应用于&#8220;知识库&#8221;的管理就产生了&#8220;内容管理&#8221;这一新的领域。配置管理提供的状态报告和数据统计也为软件度量提供了决策依据。配置管理为项目管理提供了各种监控项目进展的视角，为项目经理确切掌握项目进程提供了保证。配置管理也为开发人员提供了一个协作的平台，在此平台上，大家能够更有效率的交流和协作。可以说，配置管理是软件开发的基石！&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置管理近年来在中国得到了极大的认可，可以毫不夸张的说，没有配置管理，就谈不上软件开发，就谈不上软件质量，就谈不上软件业的发展。随着软件业规模的扩大，配置管理的实施不是要不要的问题，而是什么时间、如何实施的问题了。&nbsp;<br />参考文献：&nbsp;<br />Babich, W.A., Software Configura tion Management, Addison-Wesley, 1986. Peter H. Feiler, Configuration Management Models in Commercial Environment, CMU/SEI-91-TR-7, 1991.4&nbsp;<br />&nbsp;<br />作者简介：2000年在北方交通大学获工学硕士学位。现供职于朗讯科技（中国）有限公司贝尔实验室先进技术研究院，从事配置管理系统的研究和开发，有四年多的配置管理领域开发、咨询、培训经验。</p></div>转自：<a href="http://blog.163.com/wangdan10799@126/blog/static/10230093201243054322378/">http://blog.163.com/wangdan10799@126/blog/static/10230093201243054322378/</a><img src ="http://www.cppblog.com/flyinghare/aggbug/202429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-08-09 11:32 <a href="http://www.cppblog.com/flyinghare/archive/2013/08/09/202429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有时间一天看一次  </title><link>http://www.cppblog.com/flyinghare/archive/2013/08/09/202428.html</link><dc:creator>会飞的兔子</dc:creator><author>会飞的兔子</author><pubDate>Fri, 09 Aug 2013 03:29:00 GMT</pubDate><guid>http://www.cppblog.com/flyinghare/archive/2013/08/09/202428.html</guid><wfw:comment>http://www.cppblog.com/flyinghare/comments/202428.html</wfw:comment><comments>http://www.cppblog.com/flyinghare/archive/2013/08/09/202428.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flyinghare/comments/commentRss/202428.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flyinghare/services/trackbacks/202428.html</trackback:ping><description><![CDATA[<span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; background-color: #ffffff;">【永远都不要做的事】1，跟知己上床 2、和情人结婚 3、把同事当成朋友4、到朋友公司打工 5、在上司面前知无不言 6、轻信上司的许诺 7、喜怒哀乐都挂在脸上 8、在人堆里大声讲手机 9、习惯于给自己找借口 10、超车过去，看开着车有着窈窕背影的MM的脸 11、对MM的"字信以为真 12、指望前女友回心转意。</span><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; background-color: #ffffff;">【做人的底线】（1） 不做第三者，即使再喜欢（2） 骗我可以，如果被我知道超过两次，请你有多远滚多远（3） 如果你拿我不当回事，我会以同样方式对你（4） 我可以装傻，但别以为我真傻（5） 我可以容忍，但别超过我的底线（6） 我不是没脾气，只是不轻易发脾气（7） 任何真话，我都能接受。</span><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; background-color: #ffffff;">【让你成熟至少5岁的8句话】1、如果你不喜欢现在的工作，要么辞职不干，要么闭嘴不言。2、学会忍受孤独。3、不要像玻璃那样脆弱，做个内心强大的人。4、管住自己的嘴巴。5、会创造机会。6、若电话老是不响，你该打出去。7、不要草率结婚。8、写出你一生要做的事情，把单子放在皮夹里，经常拿出来看。</span><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; background-color: #ffffff;">【成功者的习惯】1.微笑。2.气质纯朴。3.不向朋友借钱。4.背后说别人好话。5.听到某人说别人坏话时只微笑。6.过去的事不让人全知道。7. 尊敬不喜欢你的人。9.对事无情，对人有情。10.多做自我批评。11.为别人喝彩。12.感恩。13.学会聆听。14.说话时常用我们开头。15.少说话。16.喜欢自己。</span><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><br style="line-height: 25px; color: #02540a; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;" /><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; background-color: #ffffff;">【建立人脉的15个提示】1、学会换位思考；2、学会适应环境；3、学会大方；4、学会低调；5、嘴要甜；6、有礼貌；7、言多必失；8、学会感恩；9、遵守时间；10、信守诺言；11、学会</span><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; background-color: #ffffff;">忍耐；12、有一颗平常心；13、学会赞扬别人；14、待上以敬，待下以宽；15</span><span style="font-family: 宋体; line-height: 24px; background-color: #ffffff;">常检讨自己。<br /></span><br />转自：<a href="http://blog.163.com/wangdan10799@126/blog/static/1023009320121064548110/">http://blog.163.com/wangdan10799@126/blog/static/1023009320121064548110/</a><img src ="http://www.cppblog.com/flyinghare/aggbug/202428.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flyinghare/" target="_blank">会飞的兔子</a> 2013-08-09 11:29 <a href="http://www.cppblog.com/flyinghare/archive/2013/08/09/202428.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>