﻿<?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/findingworld/</link><description>C++绝对是个好东西</description><language>zh-cn</language><lastBuildDate>Sun, 05 Apr 2026 13:42:21 GMT</lastBuildDate><pubDate>Sun, 05 Apr 2026 13:42:21 GMT</pubDate><ttl>60</ttl><item><title>C++基础知识: list结构体排序方法(一)</title><link>http://www.cppblog.com/findingworld/archive/2010/03/06/109050.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Sat, 06 Mar 2010 07:42:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2010/03/06/109050.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/109050.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2010/03/06/109050.html#Feedback</comments><slash:comments>21</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/109050.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/109050.html</trackback:ping><description><![CDATA[<p>&nbsp;说明：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;感谢<a id=AjaxHolder_Comments_CommentList_ctl01_NameLink href="http://www.cppblog.com/luckycat/" target=_blank><font color=#ff9900>luckycat</font></a> 和<a id=AjaxHolder_Comments_CommentList_ctl02_NameLink href="http://www.cppblog.com/vczh/" target=_blank><font color=#ff9900>陈梓瀚(vczh)</font></a> 的留言。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面的代码已经在Windows VC6/ Cygwin/ Suse Linux环境下编译测试通过.</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><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"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">list</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">cctype</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><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;<br><br>typedef&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;UINT32;<br>typedef&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;&nbsp;UINT16;<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">**********************************************************************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;枚举定义:&nbsp;性别&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">**********************************************************************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>typedef&nbsp;</span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">&nbsp;enumSexyType<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;SEXY_TYPE_MAN,&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">男性</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SEXY_TYPE_WOMAN,&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">女性</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SEXY_TYPE_GAY,&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">男同性恋</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SEXY_TYPE_LESIBAIN,&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">女同性恋</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;SEXY_TYPE_BUTT&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">未知性别</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">}ENUM_SEXY_TYPE;<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">**********************************************************************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;结构体定义:&nbsp;&nbsp;人&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">**********************************************************************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>typedef&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;structMan<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;UINT32&nbsp;&nbsp;&nbsp;&nbsp;sexType;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;性别&nbsp;ENUM_SEXY_TYPE</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;UINT16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usAge;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;年龄</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;strName;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;名字</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;strAddress;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;工作地址</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;structMan&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">man)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;usAge&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;man.usAge;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;structMan&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">man)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;usAge&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;man.usAge;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;structMan(UINT32&nbsp;enumSexType&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SEXY_TYPE_MAN,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UINT16&nbsp;usAge&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">refStrName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">refStrAddress&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">)\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sexType(enumSexType),\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usAge(usAge)&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strName(refStrName),\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strAddress(refStrAddress)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">DO&nbsp;NOTHING&nbsp;HERE</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;<br>}MAN;<br><br><br><br></span><span style="COLOR: #808080">////////////////////////////////////////////////////////////////////////</span><span style="COLOR: #008000">//</span><span style="COLOR: #808080"><br></span><span style="COLOR: #000000"><br>typedef&nbsp;list</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAN</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;Family;<br>typedef&nbsp;list</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAN</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::iterator&nbsp;FamilyIterator;<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"><br>&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;main函数&nbsp;定义<br>&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;初始化&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;MAN&nbsp;stFather(SEXY_TYPE_MAN,&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">28</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">倒霉熊老爸</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">华为技术有限公司</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;MAN&nbsp;stMother(SEXY_TYPE_WOMAN,&nbsp;</span><span style="COLOR: #000000">27</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">虾米老妈</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">郑州大学第二附属医院</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;MAN&nbsp;stBaby&nbsp;&nbsp;(SEXY_TYPE_BUTT,&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">小天使</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">未知</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;Family&nbsp;myFamily;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;依次存放到list中&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;myFamily.push_back(stFather);<br>&nbsp;&nbsp;&nbsp;&nbsp;myFamily.push_back(stMother);<br>&nbsp;&nbsp;&nbsp;&nbsp;myFamily.push_back(stBaby);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;调用list的sort函数进行排序,&nbsp;默认会使用结构体重载的&lt;号,&nbsp;进行从小到大排序&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;myFamily.sort();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">按年龄从小到大排序:\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;FamilyIterator&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;myFamily.begin();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(it&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;myFamily.end())<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">姓名:&nbsp;%s&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;it</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">strName.c_str());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;调用模板函数&nbsp;greater,&nbsp;传入MAN结构体,&nbsp;这样会调用结构体重载的&gt;号,&nbsp;进行从大到小排序&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;greater</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MAN</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;myFamily.sort(gt);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\n按年龄从大到小排序:\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;myFamily.begin();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(it&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;myFamily.end())<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">姓名:&nbsp;%s&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;it</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">strName.c_str());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br><br><br></span></div>
<img src ="http://www.cppblog.com/findingworld/aggbug/109050.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2010-03-06 15:42 <a href="http://www.cppblog.com/findingworld/archive/2010/03/06/109050.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c语言基础</title><link>http://www.cppblog.com/findingworld/archive/2009/10/28/99622.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Tue, 27 Oct 2009 16:18:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2009/10/28/99622.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/99622.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2009/10/28/99622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/99622.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/99622.html</trackback:ping><description><![CDATA[1、下题的输出是什么?<br>typedef struct<br>{<br>&nbsp;&nbsp;&nbsp; int&nbsp; num;<br>&nbsp;&nbsp;&nbsp; char name[10];<br>&nbsp;&nbsp;&nbsp; int&nbsp; age;<br>}Student,*pStudent;<br><br>void printName(pStudent pt)<br>{<br>&nbsp;&nbsp;&nbsp; printf("%s\n",pt-&gt;name);<br>&nbsp;&nbsp;&nbsp; return;<br>}<br><br>void main()<br>{<br>&nbsp;&nbsp;&nbsp; Student students[3]={{111, "liu", 18},<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {222, "wang", 19},<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {333, "zhao", 10}};<br>&nbsp;&nbsp;&nbsp; printName(students+2);<br>&nbsp;&nbsp;&nbsp; return;<br>}<br><br>2、选择<br>#include &lt;stdio.h&gt;<br>void main()<br>{<br>&nbsp;&nbsp;&nbsp; union<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int k;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; char i[2];<br>&nbsp;&nbsp;&nbsp; }*s, a;<br>&nbsp;&nbsp;&nbsp; s=&amp;a;<br>&nbsp;&nbsp;&nbsp; s-&gt;i[0]=0x39;<br>&nbsp;&nbsp;&nbsp; s-&gt;i[1]=0x38;<br>&nbsp;&nbsp;&nbsp; printf("%x\n", a.k);<br>}<br><br>A.3839 B.3938 C.380039 D.不可预知<br><br>3、<br>enum ENUM_A<br>{<br>&nbsp;&nbsp;&nbsp; X1,<br>&nbsp;&nbsp;&nbsp; Y1,<br>&nbsp;&nbsp;&nbsp; Z1=6,<br>&nbsp;&nbsp;&nbsp; A1,<br>&nbsp;&nbsp;&nbsp; B1<br>};<br><br>enum ENUM_A enumA=Y1;<br>enum ENUM_A enumB=B1;<br><br>enumA=_______<br>enumB=_______<br><br>4、<br>VCHAR *pucCharArray[10][10];<br>typedef union unRec<br>{<br>&nbsp;&nbsp;&nbsp; ULONG ulIndex;<br>&nbsp;&nbsp;&nbsp; USHORT usLevel[6];<br>&nbsp;&nbsp;&nbsp; UCHAR ucDos;<br>}REC_S;<br><br>REC_S stMax, *pstMax;<br><br>四字节对齐时&nbsp;&nbsp;&nbsp; sizeof(pucCharArray)=______<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(stMax)=______<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sizeof(*stMax)=______<br><br>5、<br>typedef union unHead<br>{<br>&nbsp;&nbsp;&nbsp; UCHAR aucSrc[6];<br>&nbsp;&nbsp;&nbsp; struct tagContent<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; UCHAR ucFlag[3];<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ULONG ulNext;<br>&nbsp;&nbsp;&nbsp; }Content;<br>}HEAD_S;<br><br>32位CPU,VC编译环境下:<br>强制一字节对齐情况下,请指出sizeof(HEAD_S)<br>强制二字节对齐情况下,请指出sizeof(HEAD_S)<br>强制四字节对齐情况下,请指出sizeof(HEAD_S)<br><br><br>6、<br>四字节对齐的情况下:<br>typedef struct tagRec<br>{<br>&nbsp;&nbsp;&nbsp; long lA1;<br>&nbsp;&nbsp;&nbsp; char cA2;<br>&nbsp;&nbsp;&nbsp; char cA3;<br>&nbsp;&nbsp;&nbsp; long lA4;<br>&nbsp;&nbsp;&nbsp; long lA5;<br>}REC_S;<br><br>void main()<br>{<br>&nbsp;&nbsp;&nbsp; REC_S stMax;<br>&nbsp;&nbsp;&nbsp; printf("\r\n sizeof(stMax)=%d", sizeof(stMax));<br>&nbsp;&nbsp;&nbsp; return;<br>}<br><br>输出结果为: sizeof(stMax)=______<br><br>7、<br>typedef struct tagtest<br>{<br>&nbsp;&nbsp;&nbsp; unsigned char ucFlag;<br>&nbsp;&nbsp;&nbsp; unsigned long ulLen;<br>}TEST_S;<br><br>TEST_S test[10];<br><br>四字节对其时: sizeof(TEST_S)=_____ sizeof(test)=______<br><br>8、<br>#pragma pack(4)<br>int main(int argc, char* argv[])<br>{<br>&nbsp;&nbsp;&nbsp; struct tagtest1<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp; short a;<br>&nbsp;&nbsp;&nbsp; &nbsp; char&nbsp; d;<br>&nbsp;&nbsp;&nbsp; &nbsp; long&nbsp; b;<br>&nbsp;&nbsp;&nbsp; &nbsp; long&nbsp; c;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; struct tagtest2<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp; long&nbsp; b;<br>&nbsp;&nbsp;&nbsp; &nbsp; short c;<br>&nbsp;&nbsp;&nbsp; &nbsp; char&nbsp; d;<br>&nbsp;&nbsp;&nbsp; &nbsp; long&nbsp; a;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; struct tagtest3<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp; short c;<br>&nbsp;&nbsp;&nbsp; &nbsp; long&nbsp; b;<br>&nbsp;&nbsp;&nbsp; &nbsp; char&nbsp; d;<br>&nbsp;&nbsp;&nbsp; &nbsp; long&nbsp; a;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; struct tagtest1 stT1;<br>&nbsp;&nbsp;&nbsp; struct tagtest2 stT2;<br>&nbsp;&nbsp;&nbsp; struct tagtest3 stT3;<br>&nbsp;&nbsp;&nbsp; printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3));<br>&nbsp;&nbsp;&nbsp; return 0;<br>}<br>#pragma pack()<br><br>输出是______<br><br>9、<br>typedef struct Head<br>{<br>&nbsp;&nbsp;&nbsp; VCHAR aucSrc[6];<br>&nbsp;&nbsp;&nbsp; VLONG ulType;<br>}HEAD_S;<br><br>在强制一字节对其的情况下,sizeof(HEAD_S)=____<br>在强制二字节对其的情况下,sizeof(HEAD_S)=____<br><br>10、<br>union tagAAAA<br>{<br>&nbsp; struct<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; char&nbsp; ucFirst;<br>&nbsp;&nbsp;&nbsp; short usSecond;<br>&nbsp;&nbsp;&nbsp; char&nbsp; ucThird;<br>&nbsp; }half;<br>&nbsp; long lI;<br>}number;<br><br>struct tagBBBB<br>{<br>&nbsp; char&nbsp; ucFirst;<br>&nbsp; short usSecond;<br>&nbsp; char&nbsp; ucThird;<br>&nbsp; short usForth;<br>}half;<br><br>struct tagCCCC<br>{<br>&nbsp; struct<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp; char ucFirst;<br>&nbsp;&nbsp;&nbsp;&nbsp; short usSecond;<br>&nbsp;&nbsp;&nbsp;&nbsp; char ucThird;<br>&nbsp; }half;<br>&nbsp; long lI;<br>};<br><br>在字节对其为1的情况下:<br>sizeof(union tagAAAA)=_____<br>sizeof(struct tagBBBB)=____<br>sizeof(struct tagCCCC)=____<br>字节对齐为4的情况下:<br>sizeof(union tagAAAA)=_____<br>sizeof(struct tagBBBB)=____<br>sizeof(struct tagCCCC)=____<br><img src ="http://www.cppblog.com/findingworld/aggbug/99622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2009-10-28 00:18 <a href="http://www.cppblog.com/findingworld/archive/2009/10/28/99622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代码统计打折率</title><link>http://www.cppblog.com/findingworld/archive/2009/08/21/94059.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Fri, 21 Aug 2009 15:24:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2009/08/21/94059.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/94059.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2009/08/21/94059.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/94059.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/94059.html</trackback:ping><description><![CDATA[<table style="WIDTH: 320px; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>&nbsp;语言</td>
            <td>打折率</td>
        </tr>
        <tr>
            <td>ASM</td>
            <td>1.44</td>
        </tr>
        <tr>
            <td>C/C++</td>
            <td>1</td>
        </tr>
        <tr>
            <td>Java</td>
            <td>0.7</td>
        </tr>
        <tr>
            <td>SQL</td>
            <td>0.62</td>
        </tr>
        <tr>
            <td>JSP</td>
            <td>0.7</td>
        </tr>
        <tr>
            <td>HTML</td>
            <td>0.35</td>
        </tr>
        <tr>
            <td>XML</td>
            <td>0.7</td>
        </tr>
        <tr>
            <td>JS</td>
            <td>0.7</td>
        </tr>
        <tr>
            <td>SHELL</td>
            <td>1</td>
        </tr>
        <tr>
            <td>VHDL</td>
            <td>1</td>
        </tr>
        <tr>
            <td>Python</td>
            <td>0.7</td>
        </tr>
        <tr>
            <td>VB</td>
            <td>0.8</td>
        </tr>
        <tr>
            <td>Delphi</td>
            <td>0.8</td>
        </tr>
        <tr>
            <td>Bat</td>
            <td>1</td>
        </tr>
    </tbody>
</table>
<br>
<img src ="http://www.cppblog.com/findingworld/aggbug/94059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2009-08-21 23:24 <a href="http://www.cppblog.com/findingworld/archive/2009/08/21/94059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gcc 库顺序问题解决方法</title><link>http://www.cppblog.com/findingworld/archive/2008/11/09/66408.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Sun, 09 Nov 2008 04:18:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2008/11/09/66408.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/66408.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2008/11/09/66408.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/66408.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/66408.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 使用gcc生成可执行文件时,大部分时候我们需要连接我们自己打包(AR)好的一些库文件,对于中大型(50万代码行以上)项目上，你将面对数个项目组,最好的情况是每个项目组发布自己的打包.ar文件,这些.ar文件之间没有任何依赖关系, 然后由持续集成（ci）小组对这些包进行连接,不幸的是,这几乎是不可能的, 我们在连接时还是遇到了liba.ar和libb.ar相互依赖的情况。<br><br>因为gcc的库是个有点怪怪的特性,在看-l帮助时可以看到:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -l library<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Search the library named library when linking.&nbsp; (The second alter-<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; native with the library as a separate argument is only for POSIX<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compliance and is not recommended.)<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">It makes a difference where in the command you write this option;</span><br style="font-weight: bold;">
<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the linker searches and processes libraries and object files in the</span><br style="font-weight: bold;">
<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; order they are specified.&nbsp; Thus, foo.o -lz bar.o searches library z</span><br style="font-weight: bold;">
<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; after file foo.o but before bar.o.&nbsp; If bar.o refers to functions in</span><br style="font-weight: bold;">
<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; z, those functions may not be loaded.</span><br><br>&nbsp;&nbsp;&nbsp; 出于知识产权保护的考虑,每一个项目组可能只允许看到自己的代码和别的项目组的头文件,这给CI小组带来了很头痛的事情,很多时候你不得不把库顺序来回调整。我也遇到了这样让人崩溃的情形，问题是对于liba.ar和libb.ar相互以来的情形，你可能最终采取丑陋的做法,将其中一个库在前后放两次:<br>gcc -o out.bin liba.ar libb.ar liba.ar -lrt<br>否则，您将不得不面对 "xx not referenced"之类的错误。<br><br>看看gcc的帮助,有下面的选项<br>-Xlinker option<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">Pass option as an option to the linker.</span>&nbsp; You can use this to supply<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; system-specific linker options which GCC does not know how to rec-<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ognize.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If you want to pass an option that takes an argument, you must use<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -Xlinker twice, once for the option and once for the argument.&nbsp; For<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; example, to pass -assert definitions, you must write -Xlinker<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -assert -Xlinker definitions.&nbsp; It does not work to write -Xlinker<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "-assert definitions", because this passes the entire string as a<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; single argument, which is not what the linker expects.<br><br>也就是说，-Xlinker是将连接选项传给连接器的，赶快看看ld的帮助有没有解决库顺序的选项吧:<br>&nbsp;-( archives -)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --start-group archives --end-group<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The archives should be a list of archive files.&nbsp; They may be either<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; explicit file names, or -l options.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight: bold;"> The specified archives are searched repeatedly until no&nbsp; new&nbsp; unde-</span><br style="font-weight: bold;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fined&nbsp; references&nbsp; are&nbsp; created.&nbsp;</span>&nbsp; Normally, an archive is searched<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; only once in the order that it is specified on&nbsp; the&nbsp; command&nbsp; line.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If&nbsp; a symbol in that archive is needed to resolve an undefined sym-<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bol referred to by an object in an archive that&nbsp; appears&nbsp; later&nbsp; on<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the command line, the linker would not be able to resolve that ref-<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; erence.&nbsp; By grouping the archives, they all be searched&nbsp; repeatedly<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; until all possible references are resolved.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Using&nbsp; this&nbsp; option has a significant performance cost.&nbsp; It is best<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to use it only&nbsp; when&nbsp; there&nbsp; are&nbsp; unavoidable&nbsp; circular&nbsp; references<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; between two or more archives.<br><br><br>不错，我们有个有点怪异的选项,-(和-),它能够强制"The specified archives are searched repeatedly"<br>god,这就是我们要找的啦。<br><br>最终的做法:<br>gcc -o output.bin -Xlinker "-(" liba.ar libb.ar -Xlinker "-)" -lrt<br><br>这样可以解决库顺序的问题了！问题是，如果你的库相互间的依赖如果错综复杂的话，可能会增加连接的时间，不过，做架构设计的都应该能考虑到这些问题吧。<br><br><br><br><br><br><br><br><br> <img src ="http://www.cppblog.com/findingworld/aggbug/66408.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2008-11-09 12:18 <a href="http://www.cppblog.com/findingworld/archive/2008/11/09/66408.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]理解 RSA/DSA 认证 </title><link>http://www.cppblog.com/findingworld/archive/2008/05/01/48588.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Thu, 01 May 2008 07:54:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2008/05/01/48588.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/48588.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2008/05/01/48588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/48588.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/48588.html</trackback:ping><description><![CDATA[<span class="atitle2">理解 RSA/DSA 认证</span>
<p><a  href="http://www-900.ibm.com/developerWorks/cn/linux/security/openssh/part1/index.shtml#author1"><u>Daniel Robbins</u></a> (<a  href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#100;&#114;&#111;&#98;&#98;&#105;&#110;&#115;&#64;&#103;&#101;&#110;&#116;&#111;&#111;&#46;&#111;&#114;&#103;"><u>drobbins@gentoo.org</u></a>)<br>总裁／首席执行官，Gentoo Technologies，Inc.<br>2001 年 7 月</p>
<blockquote>在本系列文章中，您将学习 RSA 和 DSA 认证的工作原理，以及了解如何正确设置无密码认证。在本系列的第一篇文章里，Daniel Robbins 主要介绍 RSA 和 DSA 认证协议并向您展示如何在网络上应用这些协议。</blockquote>
<p>我们中有许多人把优秀的 OpenSSH（参见本文后面的<a  href="http://www-900.ibm.com/developerWorks/cn/linux/security/openssh/part1/index.shtml#resources"><u>参考资料</u></a>）用作古老的 <code><font face="新宋体">telnet</font></code> 和 <code><font face="新宋体">rsh</font></code> 命令的替代品，OpenSSH 不仅是安全的而且是加密的。OpenSSH 更加吸引人的特性之一是它能够使用基于一对互补的数字式密钥的 RSA 和 DSA 认证协议来认证用户。RSA 和 DSA 认证承诺<em>不必提供密码</em>就能够同远程系统建立连接，这是它的主要魅力之一。虽然这非常吸引人，但是 OpenSSH 的新用户们常常以一种快速却不完善的方式配置 RSA/DSA，结果虽然实现了无密码登录，却也在此过程中开了一个很大的安全漏洞。</p>
<p><a id="1" name="1"></a><span class="atitle2">什么是 RSA/DSA 认证？</span><br>SSH，特别是 OpenSSH（完全免费的 SSH 的实现），是一个不可思议的工具。类似于 <code><font face="新宋体">telnet</font></code> 或 <code><font face="新宋体">rsh</font></code>，<code><font face="新宋体">ssh</font></code> 客户程序也可以用于登录到远程机器。所要求的只是该远程机器正在运行 <code><font face="新宋体">sshd</font></code>，即 <code><font face="新宋体">ssh</font></code> 服务器进程。但是，与 <code><font face="新宋体">telnet</font></code> 不同的是，<code><font face="新宋体">ssh</font></code> 协议非常安全。加密数据流，确保数据流的完整性，甚至安全可靠的进行认证它都使用了专门的算法。</p>
<p>然而，虽然 <code><font face="新宋体">ssh</font></code> 的确很棒，但还是有一个 <code><font face="新宋体">ssh</font></code> 功能组件常常被忽略、被危险的误用或者简直就是被误解。这个组件就是 OpenSSH 的 RSA/DSA 密钥认证系统，它可以代替 OpenSSH 缺省使用的标准安全密码认证系统。</p>
<p>OpenSSH 的 RSA 和 DSA 认证协议的基础是一对专门生成的密钥，分别叫做<em>专用密钥</em>和<em>公用密钥</em>。使用这些基于密钥的认证系统的优势在于：在许多情况下，有可能不必手工输入密码就能建立起安全的连接。</p>
<p>尽管基于密钥的认证协议相当安全，但是当用户并不完全了解这些简化操作对安全性的影响，为了方便而使用某些简化操作时，就会出现问题。本文中，我们
将详细讨论如何正确使用 RSA 和 DSA 认证协议，使我们不会冒任何不必要的安全性风险。在我的下一篇文章里，我将向您展示如何使用 <code><font face="新宋体">ssh-agent</font></code> 隐藏已经解密的专用密钥，还将介绍 <code><font face="新宋体">keychain</font></code>，它是 <code><font face="新宋体">ssh-agent</font></code> 的前端，可以在不牺牲安全性的前提下提供许多便利。如果您一直想要掌握 OpenSSH 更高级的认证功能的话，那么就请您继续往下读吧。</p>
<p><a id="2" name="2"></a><span class="atitle2">RSA/DSA 密钥的工作原理</span><br>下面从整体上粗略的介绍了 RSA/DSA 密钥的工作原理。让我们从一种假想的情形开始，假定我们想用 RSA 认证允许一台本地的 Linux 工作站（称作 <em>localbox</em>）打开 <em>remotebox</em> 上的一个远程 shell，<em>remotebox</em> 是我们的 ISP 的一台机器。此刻，当我们试图用 <code><font face="新宋体">ssh</font></code> 客户程序连接到 <em>remotebox</em> 时，我们会得到如下提示：</p>
<a id="code1" name="code1"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>ssh drobbins@remotebox</strong><br>drobbins@remotebox's password:<br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>此处我们看到的是 <code><font face="新宋体">ssh</font></code> 处理认证的<em>缺省</em>方式的一个示例。换句话说，它要求我们输入 <em>remotebox</em> 上的 <em>drobbins</em> 这个帐户的密码。如果我们输入我们在 <em>remotebox</em> 上的密码，<code><font face="新宋体">ssh</font></code> 就会用安全密码认证协议，把我们的密码传送给 <em>remotebox</em> 进行验证。但是，和 <code><font face="新宋体">telnet</font></code> 的情况不同，这里我们的密码是加密的，因此它不会被偷看到我们的数据连接的人截取。一旦 <em>remotebox</em> 把我们提供的密码同它的密码数据库相对照进行认证，成功的话，我们就会被允许登录，还会有一个 <em>remotebox</em> 的 shell 提示欢迎我们。虽然 <code><font face="新宋体">ssh</font></code> 缺省的认证方法相当安全，RSA 和 DSA 认证却为我们开创了一些新的潜在的机会。</p>
<p>但是，与 <code><font face="新宋体">ssh</font></code> 安全密码认证不同的是，RSA 认证需要一些初始配置。我们只需要执行这些初始配置步骤一次。之后，<em>localbox</em> 和 <em>remotebox</em> 之间的 RSA 认证就毫不费力了。要设置 RSA 认证，我们首先得生成一对密钥，一把专用密钥和一把公用密钥。这两把密钥有一些非常有趣的性质。公用密钥用于对消息进行加密，只有拥有专用密钥的人才能对该消息进行解密。公用密钥只能用于<em> 加密</em>，而专用密钥只能用于对由匹配的公用密钥编码的消息进行<em>解密</em>。RSA（和 DSA）认证协议利用密钥对的这些特殊性质进行安全认证，并且不需要在网上传输任何保密的信息。</p>
<p>要应用 RSA 或者 DSA 认证，我们要执行一步一次性的配置步骤。我们把<em>公用密钥</em>拷贝到 <em>remotebox</em>。公用密钥之所以被称作是&#8220;公用的&#8221;有一个原因。因为它只能用于对那些给我们的消息进行<em> 加密</em>，所以我们不需要太担心它会落入其它人手中。一旦我们的公用密钥已经被拷贝到 <em>remotebox</em> 并且为了 <em>remotebox</em> 的 <code><font face="新宋体">sshd</font></code> 能够定位它而把它放在一个专门的文件（~/.ssh/authorized_keys）里，我们就为使用 RSA 认证登录到 <em>remotebox</em> 上做好了准备。</p>
<p>要用 RSA 登录的时候，我们只要在 <em>localbox</em> 的控制台键入 <code><font face="新宋体">ssh drobbins@remotebox</font></code>，就象我们常做的一样。可这一次，<code><font face="新宋体">ssh</font></code> 告诉 <em>remotebox</em> 的 <code><font face="新宋体">sshd</font></code> 它想使用 RSA 认证协议。接下来发生的事情非常有趣。<em>Remotebox</em> 的 <code><font face="新宋体">sshd</font></code> 会生成一个随机数，并用我们先前拷贝过去的公用密钥对这个随机数进行加密。然后，<code><font face="新宋体"> sshd</font></code> 把加密了的随机数发回给正在 <em>localbox</em> 上运行的 <code><font face="新宋体">ssh</font></code>。接下来，轮到我们的 <code><font face="新宋体">ssh</font></code> 用<em>专用密钥</em>对这个随机数进行解密后，再把它发回给 <em>remotebox</em>，实际上等于在说：&#8220;瞧，我<em>确实</em>有匹配的专用密钥；我能成功的对您的消息进行解密！&#8221;最后，<code><font face="新宋体"> sshd</font></code> 得出结论，既然我们持有匹配的专用密钥，就应当允许我们登录。因此，我们有匹配的专用密钥这一事实授权我们访问 <em>remotebox</em>。</p>
<p><a id="3" name="3"></a><span class="atitle2">两项注意事项</span><br>关于 RSA 和 DSA 认证有两项重要的注意事项。第一项是我们的确只需要生成一对密钥。然后我们可以把我们的公用密钥拷贝到想要访问的那些远程机器上，它们都会根据我们的那把专用密钥进行恰当的认证。换句话说，我们并不需要为想要访问的<em> 每个</em>系统都准备一对密钥。只要一对就足够了。</p>
<p>另一项注意事项是<em>专用密钥不应落入其它人手中</em>。正是专用密钥授权我们访问远程系统，任何拥有我们的专用密钥的人都会被授予和我们完全
相同的特权。如同我们不想让陌生人有我们的住处的钥匙一样，我们应该保护我们的专用密钥以防未授权的使用。在比特和字节的世界里，这意味着没有人是本来就
应该能读取或是拷贝我们的专用密钥的。</p>
<p><code><font face="新宋体">ssh</font></code> 的开发者们当然知道专用密钥的重要性，而且他们已经在 <code><font face="新宋体">ssh</font></code> 和 <code><font face="新宋体">ssh-keygen</font></code> 里加入了一些防范措施，以防止我们的专用密钥被滥用。首先，<code><font face="新宋体">ssh</font></code> 被设置成了如果我们的密钥的文件权限允许除我们之外的任何人读取密钥，就打印出一条大大的警告消息。其次，在我们用 <code><font face="新宋体">ssh-keygen</font></code> 创建公用／专用密钥对的时候，<code><font face="新宋体">ssh-keygen</font></code> 会要求我们输入一个密码短语。如果我们输入了密码短语，<code><font face="新宋体">ssh-keygen</font></code> 就会用该密码短语加密我们的专用密钥，这样，即使专用密钥被盗，对于那些碰巧不知道密码短语的人而言，这把专用密钥是毫无用处的。具备了这一知识后，让我们看一下如何设置 <code><font face="新宋体">ssh</font></code> 以应用 RSA 和 DSA 认证协议。</p>
<p><a id="4" name="4"></a><span class="atitle2">ssh-keygen 细探</span><br>设置 RSA 认证的第一步从生成一对公用／专用密钥对开始。RSA 认证是 <code><font face="新宋体">ssh</font></code> 密钥认证的最初形式，因此 RSA 应该可以用于 OpenSSH 的所有版本，尽管这样，我还是推荐您安装可用的最近版本，在我写这篇文章的时候是 openssh-2.9_p2。生成一对 RSA 密钥的方法如下：</p>
<a id="code2" name="code2"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>ssh-keygen</strong><br>Generating public/private rsa1 key pair.<br>Enter file in which to save the key (/home/drobbins/.ssh/identity): <font color="#ff0000">(hit enter)</font><br>Enter passphrase (empty for no passphrase): <font color="#ff0000">(enter a passphrase)</font><br>Enter same passphrase again: <font color="#ff0000">(enter it again)</font><br>Your identification has been saved in /home/drobbins/.ssh/identity.<br>Your public key has been saved in /home/drobbins/.ssh/identity.pub.<br>The key fingerprint is:<br>a4:e7:f2:39:a7:eb:fd:f8:39:f1:f1:7b:fe:48:a1:09 drobbins@localbox<br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>当 <code><font face="新宋体">ssh-keygen</font></code> 要求输入存放密钥的缺省位置时，我们敲回车键接受缺省的 /home/drobbins/.ssh/identity。<code><font face="新宋体">ssh-keygen</font></code> 将把专用密钥保存在此路径中，<em>公用</em>密钥就存在紧临它的一个叫做 identity.pub 的文件里。</p>
<p>还要请您注意一下 <code><font face="新宋体">ssh-keygen</font></code> 还提示过我们输入密码短语。当时我们输入了一个好的密码短语（七位或者更多位难以预测的字符）。然后 <code><font face="新宋体">ssh-keygen</font></code> 用这个密码短语加密了我们的专用密钥（~/.ssh/identity），以使我们的专用密钥对于那些不知道这个密码短语的人将变得毫无用处。</p>
<p><a id="5" name="5"></a><span class="atitle2">追求快速的折衷方案</span><br>当我们指定密码短语时，虽然这使得 <code><font face="新宋体">ssh-keygen</font></code> 保护我们的专用密钥以防误用，但是也带来了一点小小的不便。现在，每当我们试图用 <code><font face="新宋体">ssh</font></code> 连接到 <em>drobbins@remotebox</em> 帐户时，<code><font face="新宋体">ssh</font></code> 都会提示我们输入该密码短语以便它能对我们的专用密钥进行解密，并使用我们的专用密钥进行 RSA 认证。此外，我们输入的不是 <em>remotebox</em> 上 <em>drobbins</em> 帐户的密码，而是在本地机器上对专用密钥进行解密所需要的密码短语。一旦我们的专用密钥被解密，我们的 <code><font face="新宋体">ssh</font></code> 客户程序就会处理其余的事情。虽然使用我们的远程密码和使用 RSA 密码短语的机制完全不同，但实际上还是会提示我们输入一个&#8220;保密的短语&#8221;给 <code><font face="新宋体">ssh</font></code>。</p>
<a id="code3" name="code3"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code># <strong>ssh drobbins@remotebox</strong><br>Enter passphrase for key '/home/drobbins/.ssh/identity': <font color="#ff0000">(enter passphrase)</font><br>Last login: Thu Jun 28 20:28:47 2001 from localbox.gentoo.org <br><br>Welcome to remotebox!<br><br>%<br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>这里就是人们经常会被误导而导致追求快速的折衷方案的地方。有很多时候，仅仅是为了不必输入密码，人们就会创建不加密的专用密钥。那样的话，他们只要输入 <code><font face="新宋体">ssh</font></code> 命令，立刻就会通过 RSA（或是 DSA）认证并登录。</p>
<a id="code4" name="code4"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code># <strong>ssh drobbins@remotebox</strong><br>Last login: Thu Jun 28 20:28:47 2001 from localbox.gentoo.org <br><br>Welcome to remotebox!<br><br>%<br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>然而，尽管这样很方便，但是在还没有完全理解这种方法对安全性的影响时，您不应该使用。如果有人在某一时刻闯入了 <em>localbox</em>，一把不加密的专用密钥使得他们也自动有权访问 <em>remotebox</em> 以及其它所有用这把公用密钥配置过的系统。</p>
<p>我知道您在想些什么。无密码认证，虽然有点冒险，可看起来的确很诱人。我完全同意。但是，<em> 还有更好的办法！</em>请相信我，我将向您展示如何既可以享受到无密码认证的好处，又不必牺牲专用密钥的安全性。在我的下一篇文章里，我还将向您展示如何熟练的使用 <code><font face="新宋体">ssh-agent</font></code>（正是它最先使得<em>安全</em>无密码认证成为可能）。现在，让我们通过设置 RSA 和 DSA 认证为使用 <code><font face="新宋体">ssh-agent</font></code> 做好准备。下面是逐步的指导。</p>
<p><a id="6" name="6"></a><span class="atitle2">RSA 密钥对的生成</span><br>要设置 RSA 认证，我们需要执行生成公用／专用密钥对的一次性步骤。我们的输入如下：</p>
<a id="code5" name="code5"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>ssh-keygen</strong><br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>出现提示时，请接受缺省的密钥位置（典型的情况下是 ~/.ssh/identity 和存储公用密钥的 ~/.ssh/identity.pub），并提供给 <code><font face="新宋体">ssh-keygen</font></code> 一个安全的密码短语。一旦 <code><font face="新宋体">ssh-keygen</font></code> 完成，您将会得到一把公用密钥和一把用密码短语加密的专用密钥。</p>
<p><a id="7" name="7"></a><span class="atitle2">RSA 公用密钥的安装</span><br>接下来，我们需要把正在运行 <code><font face="新宋体">sshd</font></code> 的远程系统设置成使用我们的<em>公用</em> RSA 密钥进行认证。典型情况下，我们通过象下面这样把公用密钥拷贝到远程系统完成这一步：</p>
<a id="code6" name="code6"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>scp ~/.ssh/identity.pub drobbins@remotebox:</strong><br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>由于 RSA 认证还没有完全设置好，所以会提示我们输入 <em>remotebox</em> 上的密码。请您照做。然后，登录到 <em>remotebox</em> 并把公用密钥附加到文件 ~/.ssh/authorized_keys 上，如下所示：</p>
<a id="code7" name="code7"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>ssh drobbins@remotebox</strong><br>drobbins@remotebox's password: <font color="#ff0000">(enter password)</font><br>Last login: Thu Jun 28 20:28:47 2001 from localbox.gentoo.org <br><br>Welcome to remotebox!<br><br>% <strong>cat identity.pub &gt;&gt; ~/.ssh/authorized_keys</strong><br>% <strong>exit</strong><br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>现在，配置过 RSA 认证以后，当我们试图使用 <code><font face="新宋体">ssh</font></code> 连接到 <em>remotebox</em> 时，应该会提示我们输入 RSA <em>密码短语</em>（而不是我们的<em>密码</em>）。</p>
<a id="code8" name="code8"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>ssh drobbins@remotebox</strong><br>Enter passphrase for key '/home/drobbins/.ssh/identity': <br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p>好哇，RSA 认证的配置完成了！如果刚才没有提示您输入密码短语，您可以试验一下以下几种情况。第一，尝试通过输入 <code><font face="新宋体">ssh -1 drobbins@remotebox</font></code> 登录。它会让 <code><font face="新宋体">ssh</font></code> 只应用 ssh 协议版本 1，如果出于某种原因远程系统缺省设置的是 DSA 认证的话，可能会要求这么做。如果不奏效的话，请确认您的 /etc/ssh/ssh_config 里没有写着这么一行 <code><font face="新宋体">RSAAuthentication no</font></code>。如果有的话，请您在前面加上一个&#8220;#&#8221;把这行注释掉。另外，还可以试着同 <em>remotebox</em> 的系统管理员联络，核实一下在他们那一端已经启用了 RSA 认证，并且 /etc/ssh/sshd_config 里的设置是正确的。</p>
<p><a id="8" name="8"></a><span class="atitle2">DSA 密钥的生成</span><br><code><font face="新宋体">ssh</font></code> 协议的版本 1 使用的是 RSA 密钥，而 DSA 密钥却用于协议级 2，这是 <code><font face="新宋体">ssh</font></code> 协议的最新版本。目前所有的 OpenSSH 版本都应该既能使用 RSA 密钥又能使用 DSA 密钥。DSA 密钥以如下类似于 RSA 密钥的方式使用 OpenSSH 的 <code><font face="新宋体">ssh-keygen</font></code> 生成：</p>
<a id="code9" name="code9"></a>
<table bgcolor="#cccccc" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code>% <strong>ssh-keygen -t dsa</strong><br></code><br></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>又会提示我们输入密码短语。输入一个安全的密码短语。还会提示我们输入保存 DSA 密钥的位置。正常情况下，缺省的
~/.ssh/id_dsa 和 ~/.ssh/id_dsa.pub 就可以了。在我们一次性生成 DSA 密钥完成后，就该把我们的 DSA
公用密钥安装到远程系统上去了。</p>
<p><a id="9" name="9"></a><span class="atitle2">DSA 公用密钥的安装</span><br>DSA 公用密钥的安装又是几乎和 RSA 安装完全一样。对于 DSA，我们将要把 ~/.ssh/id_dsa.pub 文件拷贝到 <em>remotebox</em>，然后把它附加到 <em>remotebox</em> 上的 ~/.ssh/authorized_keys2 文件。请注意这个文件的名字和 RSA 的 authorized_keys 文件名不同。一旦配置完毕，输入我们的 DSA 专用密钥的密码短语就应该能登录到 <em>remotebox</em>，而不需要我们输入在 <em>remotebox</em> 上真正的密码。</p>
<p><a id="10" name="10"></a><span class="atitle2">下一篇</span><br>此刻，您应该已经可以使用 RSA 或者 DSA 认证了，但是在每一次新连接时，您仍需输入您的密码短语。在我的下一篇文章里，我们将会了解到如何使用 <code><font face="新宋体">ssh-agent</font></code>，它确实是一个很不错的系统，不仅允许我们<em>不</em>提供密码就建立连接，而且还使我们的专用密钥可以在磁盘上保持加密状态。我还将介绍 <code><font face="新宋体">keychain</font></code>，它是一个非常方便的 <code><font face="新宋体">ssh-agent</font></code> 前端，可以使 <code><font face="新宋体">ssh-agent</font></code> 比以前更可靠、更方便而且使用起来更具趣味性。在此之前，请就近查阅下面列出的参考资料以使您能跟上进度。</p>
<!-- RESOURCES -->
<p><a id="resources" name="resources"><span class="atitle2">参考资料</span></a></p>
<ul><!-- Comment out list item below if there is no forum for this article
    <li>Participate in the <a href="javascript:void forumWindow()">discussion forum</a> on this article by clicking <strong>Discuss</strong> at the top or bottom of the article.</li>
    -->
    <li>请务必访问 <a  href="http://www.openssh.com/"><u>OpenSSH</u></a> 的开发主页。<br><br>
    </li>
    <li>请看看最新的 <a  href="ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/"><u>OpenSSH 源代码 tarball 和 RPM</u></a>。<br><br>
    </li>
    <li>请查阅 <a  href="http://www.openssh.com/faq.html"><u>OpenSSH 常见问题解答</u></a>。<br><br>
    </li>
    <li><a  href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/"><u>PuTTY</u></a> 是用于 Windows 机器的极好的 <code><font face="新宋体">ssh</font></code> 客户程序。<br><br>
    </li>
    <li>您会发现 O'Reilly 的 <em>SSH, The Secure Shell: The Definitive Guide</em> 会对您有所帮助。<a  href="http://www.snailbook.com/"><u>作者的网站</u></a>上有关于这本书、常见问题解答、新闻和最新信息。<br><br>
    </li>
    <li>请阅读 <em>developerWorks</em> 上的 <a  href="http://www-106.ibm.com/developerworks/library/l-sec/index.html"><u>Addressing security issues in Linux</u></a> 以获得关于数据加密和许多其它安全性论题的概述。<br><br>
    </li>
    <li>请浏览 <em>developerWorks</em> 上<a  href="http://www-900.ibm.com/developerWorks/cn/linux/index.shtml"><u>更多的 Linux 参考资料</u></a>。<br><br>
    </li>
    <li>请浏览 <em>developerWorks</em> 上<a  href="http://www-106.ibm.com/developerworks/opensource/?article=osr"><u> 更多的开放源代码参考资料</u></a>。 </li>
</ul>
<br><br><!-- AUTHOR BIOS --><!-- Make author heading singular or plural as needed -->
<a id="author1" name="author1"><span class="atitle2">关于作者</span></a> <br><img  src="http://www-900.ibm.com/developerWorks/cn/i/authors/robbins.gif" alt="author" align="left" border="0" width="64" height="71">Daniel Robbins 居住在美国新墨西哥州的阿尔布开克。他主创了 <a  href="http://www.gentoo.org/"><u>Gentoo Linux</u></a>，这是一种用于 PC 的高级 Linux，以及 <strong>Portage</strong> 系统，是用于 Linux 的下一代移植系统。他还是几本 Macmillan 出版的书籍 <em>Caldera OpenLinux Unleashed</em>、<em>SuSE Linux Unleashed</em> 和 <em>Samba Unleashed</em> 的投稿人。Daniel 自二年级起就与计算机结下了不解之缘，那时他最先接触的是 Logo 程序语言，并沉溺于 Pac Man 游戏中。这也许就是他至今仍担任 <strong>SONY Electronic Publishing/Psygnosis</strong> 首席图形设计师的原因所在。Daniel 喜欢与妻子 Mary 和新出生的女儿 Hadassah 一起共度时光。您可以通过 <a  href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#100;&#114;&#111;&#98;&#98;&#105;&#110;&#115;&#64;&#103;&#101;&#110;&#116;&#111;&#111;&#46;&#111;&#114;&#103;"><u>drobbins@gentoo.org</u></a> 和 Daniel 联系。<br><img src ="http://www.cppblog.com/findingworld/aggbug/48588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2008-05-01 15:54 <a href="http://www.cppblog.com/findingworld/archive/2008/05/01/48588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL  统计体验</title><link>http://www.cppblog.com/findingworld/archive/2007/07/13/27943.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Fri, 13 Jul 2007 01:32:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2007/07/13/27943.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/27943.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2007/07/13/27943.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/27943.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/27943.html</trackback:ping><description><![CDATA[<p style="FONT-FAMILY: Arial">今日见小王同志眉头微皱，心想这兄台必然遇到难题，遂问其故。果不其然，他在通过日志表统计用户使用情况时创建试图屡屡失败。<br>我以前也没有做过类似的SQL,但又想这实现总该不难，于是拿来分析，情况如下:<br>表1-日志表，表结构如下:<br>ID,F_LOGIN,MTime,ManageName 这ID是主键(ID在我看来都是主键，下文不再赘述),F_LOGIN是用户的登陆名缩写，MTime是用户的操作时间，ManageName是用户操作的模块名称<br>表2-用户表，结构如下:<br>ID,F_ORDER,F_LOGIN,F_USERNAME,F_DEPTNAME...,F_ORDER是用户的顺序号，F_LOGIN是用户的登陆名缩写,F_USERNAME是用户的中文名,F_DEPTNAME是用户所在单位的名称<br>表3-部门表，结构如下:<br>ID,F_DEPTORDER,F_DEPTNAME F_DEPTORDER是部门顺序号，F_DEPTNAME是部门名称。</p>
<p style="FONT-FAMILY: Arial">好了，就是这么三个表，客户要求根据统计用户对每个模块的使用次数，并要求按照部门顺序进行排序,并且统计结果排除管理帐号admin：<br>怎么办? 看到小王以前的视图是：</p>
<p style="FONT-FAMILY: Arial">SELECT&nbsp; 用户表.F_DEPTNAME, COUNT(*) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AS count, 部门表.F_ORDER<br>FROM 日志表 INNER JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户表 ON <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志表.F_login = 用户表.F_LOGIN INNER JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表 ON <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户表.F_DEPTNAME = 部门表.F_DEPATNAME<br>WHERE (日志表.F_login &lt;&gt; 'admin')<br>GROUP BY 用户表.F_DEPTNAME, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表.F_NO<br>ORDER BY 部门表.F_NO</p>
<p style="FONT-FAMILY: Arial">郁闷，这试图看起来没什么问题啊，但是一运行问题就来了:<br>考，如果部门A的用户都没有使用，也就是日志表里没有记录，那么视图里根本就不会显示该单位，但是很明显这样不对，我们需要没有使用的单位显示次数为0嘛，<br>我想办法不是明摆着的嘛，把"INNER JOIN 部门表"改为"RIGHT JOIN"部门表不就ok了么，好，改变:</p>
<p style="FONT-FAMILY: Arial">SELECT&nbsp; 用户表.F_DEPTNAME, COUNT(*) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AS count, 部门表.F_ORDER<br>FROM 日志表 INNER JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户表 ON <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志表.F_login = 用户表.F_LOGIN RIGHT JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表 ON <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户表.F_DEPTNAME = 部门表.F_DEPATNAME<br>WHERE (日志表.F_login &lt;&gt; 'admin')<br>GROUP BY 用户表.F_DEPTNAME, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表.F_NO<br>ORDER BY 部门表.F_NO</p>
<p style="FONT-FAMILY: Arial">运行，又郁闷，怎么还是没有出现，抓耳挠腮半晌弄不明白，心想反正老子最不怕的就是困难(最怕的是美女放电^_^),我一句一句来，调试、调试,终于发现问题所在：<br>"WHERE (日志表.F_login &lt;&gt; 'admin')"<br>当Right join以后，没有操作的部门会在视图留下一条记录，而这条记录只包含部门表的信息，用户表和日志表均为NULL,NULL是没有办法和'admin'比较的，也就是说NULL &lt;&gt; 'admin' 返回的是false,怎么办?调整视图join的次序，如下:<br>SELECT&nbsp; 用户表.F_DEPTNAME, COUNT(*) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AS count, 部门表.F_ORDER<br>FROM 用户表 INNER JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表 ON <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户表.F_DEPTNAME = 部门表.F_DEPATNAME LEFT JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志表 ON<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志表.F_login = 用户表.F_LOGIN <br>WHERE (用户表.F_login &lt;&gt; 'admin')<br>GROUP BY 用户表.F_DEPTNAME, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表.F_NO<br>ORDER BY 部门表.F_NO</p>
<p style="FONT-FAMILY: Arial">这样不管怎么变，这所有用户和部门都是有的，而且admin也过滤的，但是....不对啊，怎么没有用户的单位使用次数都很大啊，哦，原来是我用的count(*)<br>有问题，肯定得用sum函数啦。查查联机丛书，最后定稿如下：<br>SELECT&nbsp; 用户表.F_DEPTNAME, <br>SUM(CASE WHEN 统计表.F_login IS NULL THEN 0 ELSE 1 END) as count,<br>部门表.F_ORDER<br>FROM 用户表 INNER JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表 ON <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户表.F_DEPTNAME = 部门表.F_DEPATNAME LEFT JOIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志表 ON<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志表.F_login = 用户表.F_LOGIN <br>WHERE (用户表.F_login &lt;&gt; 'admin')<br>GROUP BY 用户表.F_DEPTNAME, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门表.F_NO<br>ORDER BY 部门表.F_NO</p>
<p style="FONT-FAMILY: Arial"><br>终于搞定了，万岁！！不过CASE的使用也分两种，一种是简单CASE函数，一种是CASE搜索函数，联机从书中关于when_expression 和Boolean_expression 写的很笼统，我的理解when_expression就是一个值，而Boolean_expression是一个判断,嗯，写这个破东西也婆婆妈妈的写了半个小时，到此收笔。<br></p>
<img src ="http://www.cppblog.com/findingworld/aggbug/27943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2007-07-13 09:32 <a href="http://www.cppblog.com/findingworld/archive/2007/07/13/27943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于Trac的项目管理系统</title><link>http://www.cppblog.com/findingworld/archive/2007/04/04/21237.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Wed, 04 Apr 2007 06:55:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2007/04/04/21237.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/21237.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2007/04/04/21237.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/21237.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/21237.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这里我们要构建一个基于Trac的项目管理系统。代码管理使用subversion，项目管理使用Trac。所需要的软件包如下：&#167;&nbsp;&nbsp;&nbsp;Trac 0.10，Trac程序 &#167;&nbsp;&nbsp;&nbsp;Apache 2.0.59，Web服务器 &#167;&nbsp;&nbsp;&nbsp;subversion 1.4.3，...&nbsp;&nbsp;<a href='http://www.cppblog.com/findingworld/archive/2007/04/04/21237.html'>阅读全文</a><img src ="http://www.cppblog.com/findingworld/aggbug/21237.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2007-04-04 14:55 <a href="http://www.cppblog.com/findingworld/archive/2007/04/04/21237.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ILOVEQQ木马及源码下载</title><link>http://www.cppblog.com/findingworld/archive/2007/01/31/18201.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Wed, 31 Jan 2007 02:39:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2007/01/31/18201.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/18201.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2007/01/31/18201.html#Feedback</comments><slash:comments>27</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/18201.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/18201.html</trackback:ping><description><![CDATA[用vc写的QQ木马,<br />破解QQ2006键盘保护。<br />在xp下测试通过。<br /><br />使用windows消息和键盘钩子,修改QQ键盘保护函数地址,使其键盘保护失去作用。<br /><br />声明:<br />仅供vc爱好者学习参考使用,不得用于非法盗取他人QQ号码及密码,任何因此引起的纠纷概与本人无关。<br /><br />QQ：270083015<br />Mail: <a href="mailto:findingworld@sina.com">findingworld@sina.com</a><br /><br /><br />下载生成器: <u><a href="/Files/findingworld/iloveqq木马生成器.rar" target="_blank"><font color="#0000ff">http://www.cppblog.com/Files/findingworld/iloveqq木马生成器.rar<br /></font></a></u>下载源码: <a title="http://www.cppblog.com/Files/findingworld/iloveqq木马源码.rar" href="/Files/findingworld/iloveqq木马源码.rar" target="_blank"><font color="#0000ff">http://www.cppblog.com/Files/findingworld/iloveqq木马源码.rar</font></a><br /><br />删除办法:<br /><br />1. 停掉QQ.exe和Timplatform.exe <br />2. 停掉Explorer.exe 并新建此进程 <br />3. 到C:\windows下 删除loveqq.exe和hookdll.dll <br />4. 删除 HKEY_LOCAL_MACHINE-&gt;software-&gt;microsoft-&gt;windows-&gt;currentversion-&gt;run-&gt;loveqq <br /><br /><br />如果在测试中有什么问题,给我留言啦。<img src ="http://www.cppblog.com/findingworld/aggbug/18201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2007-01-31 10:39 <a href="http://www.cppblog.com/findingworld/archive/2007/01/31/18201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网页中一些比较隐蔽的用法</title><link>http://www.cppblog.com/findingworld/archive/2006/11/29/15789.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Wed, 29 Nov 2006 11:35:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2006/11/29/15789.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/15789.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2006/11/29/15789.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/15789.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/15789.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放 event.srcElement.setCapture(); event.srcElement.releaseCapture(); 								事件按键 event.keyCode event.shiftKey event.altKey event.ctrlKey ...&nbsp;&nbsp;<a href='http://www.cppblog.com/findingworld/archive/2006/11/29/15789.html'>阅读全文</a><img src ="http://www.cppblog.com/findingworld/aggbug/15789.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2006-11-29 19:35 <a href="http://www.cppblog.com/findingworld/archive/2006/11/29/15789.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ArrayList versus LinkedList: Aren't they same?</title><link>http://www.cppblog.com/findingworld/archive/2006/11/29/15758.html</link><dc:creator>小苏</dc:creator><author>小苏</author><pubDate>Tue, 28 Nov 2006 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/findingworld/archive/2006/11/29/15758.html</guid><wfw:comment>http://www.cppblog.com/findingworld/comments/15758.html</wfw:comment><comments>http://www.cppblog.com/findingworld/archive/2006/11/29/15758.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/findingworld/comments/commentRss/15758.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/findingworld/services/trackbacks/15758.html</trackback:ping><description><![CDATA[
		<h3 class="title">copied from <a accesskey="1" href="http://www.pankaj-k.net/weblog/"><font color="#003366">Pankaj Kumar's Weblog</font></a></h3>
		<h3 class="title">
				<br />The trade-offs in using <b>java.util.ArrayList</b> and <b>java.util.LinkedList </b>should be straight-forward, shouldn't it? At least this is what I used to think till today. But then most of my thinking around these datastructures were formed during college days, when C was the hottest language and Java and its Collection classes just didn't exist. </h3>
		<p>Not surprisingly, it is natural for me to think of arrays as fixed size containers, where elements can be accessed at random location through O(1) operation (ie; in constant time) and insertion/deletion in the middle are O(N) operations (ie; could take time proportional to the size of the array) and hence, are better avoided. In contrast, a linked list can grow in size, access of its head or tail and insertion/deletion in the middle are all O(1) operations (assuming that you have pointer to an adjacent element). </p>
		<p>It is possible get around the fixed size limitation of arrays by writing a wrapper which will allocate a new array, copy the elements of the old array into the new one and then discard the old one (BTW, this is what ArrayList does). Still, the basic arrays remain a datastructure for collections of fixed size. In contrast, a linked list consists of nodes with 'pointers' to the next and previous node in the list. So, adding or removing a node is simply a matter of reassigning the pointers. Of course, this implies linear time for traversing upto an indexed node, starting from beginning or end. This simple model is very handy in deciding when to use an array and when to use a linked list.</p>
		<p>In Java, the ArrayList and LinkedList classes provide a uniform interface to both these datastructures and hence, destroy this simple conceptual model, so necessary to make judicious implementation decisions, in impressionable young minds of many Java programmers. Let me further elaborate this with my recent own experience.</p>
		<p>Today, while going over a graph traversal code, I was somewhat alarmed by the generous use of ArrayLists. This code was written by someone who perhaps had learnt programming with Java. As hinted earlier, both ArrayList and LinkedList implement List interface and support similar operations. An ArrayList can grow dynamically and allows insertion/deletion of elements. A LinkedList also allows access of elements through an index, exactly the same way as an ArrayList. This is all fine. However, the problem is that the apparent similarity in the API hides the widely different memory and time costs of these datastructures for different kinds of operations, luring the unwary to use them in dangerous ways:<br /></p>
		<ol>
				<p>
				</p>
				<p>
				</p>
				<li>An empty ArrayList takes two to three times more memory than an empty LinkedList (because ArrayList would typically preallocate memory). This becomes important if you plan to keep an adjacency list of nodes for each node in the graph and you know beforehand that the nodes will have at most one or two adjacent nodes and the total number of nodes in the graph can be quite large. 
<p></p><p></p></li>
				<li>The following straight-forward loop to iterate over all elements of a list<br /><br /><br />  for (int i = 0; i &lt; list.size(); i++)<br />    doSomething(list.get(i));<br /><br /><br />works great for an ArrayList but will cause serious performance problems for a LinkedList. Can you guess why? The right way to iterate over a LinkedList is:<br /><br /><br />  ListIterator li = list.listIterator(0);<br />  while (li.hasNext())<br />    doSomething(li.next());<br /><br /><br /><p></p><p></p></li>
				<li>Although both ArrayList and LinkedList allow insertion/deletion in the middle through similar operations (ie; by invoking add(int index) or remove(index)), these operations do not offer you the advantage of O(1) insertion/deletion for a LinkedList. For that, you must work through a ListIterator.<br /></li>
		</ol>
		<p>
		</p>
		<p>While researching on this topic, I did find a couple of good articles on the Web:<br /></p>
		<ul>
				<br />
				<li>JDC Tech Tip article on <a href="http://java.sun.com/developer/JDCTechTips/2002/tt0910.html">Using ArrayList/LinkedList</a>. Good coverage of the topic. Worth reading if you want to know more about performance tradeoffs.<br /></li>
				<li>joustlog entry titled <a href="http://joust.kano.net/weblog/archives/000066.html">LinkedList vs. ArrayList performance tests</a> and <a href="http://joust.kano.net/weblog/archives/000068.html">subsequent clarification</a>. This entry is more focussed in scope, pointing out the fact that addition as the end is faster for ArrayList than for LinkedList. The only thing I would like to add is that addition at the end of a LinkedList is always O(1) whereas addition at the end of an ArrayList is amortized O(1), meaning if you do M at-the-end additions then the total cost will be proportional to M. This is due to the fact that the underlying array may have to be grown (a new one to be allocated, old one to be copied and discarded) when the capacity is reached. However, I can understand that a normal at-the-end addition (ie; not involving resizing of the underlying array) will be faster for ArrayList (compared to LinkedList).<br /></li>
		</ul>
		<p>
		</p>
		<p>I am not advocating either ArrayList or LinkedList, though it can be justifiably argued that the use of ArrayList is better suited in many more programming scenarios, and I have no contention with that. The point I am making is that the sameness of the API makes it easy for programmers to assume that these can be used interchangeably. Nothing can be farther from truth. They are distinct datastructures, each optimized for certain kinds of operations and domain of applicability. And a good programmer should be aware of the distinction. The API exposed by the above mentioned Java classes blur this distinction. In my opinion, this is one of those areas where <i>implementation hiding</i> behind a common, easy-to-use interface (think of List interface that both ArrayList and LinkedList implement) may not be in the best interest of the primary user of these classes.</p>
<img src ="http://www.cppblog.com/findingworld/aggbug/15758.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/findingworld/" target="_blank">小苏</a> 2006-11-29 00:05 <a href="http://www.cppblog.com/findingworld/archive/2006/11/29/15758.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>