<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_A Lazy Programmer's Footprint</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/60277/rss</id><updated>2012-01-15T09:08:40Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/60277/rss"/><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2012/01/08/2316539.html</id><title type="text">[try it] Apache HTTP Server</title><summary type="text">比较有名的三个web server，Windows下是IIS，而Linux/Unix下则主要为Appache HTTP Server (httpd), 另外还有一个专门为运行java code的Tomcat Server，当然是跟着java一起跨平台了。其实Appache HTTP Server也是跨平台的，比如我这两天用的就是Windows下的版本。基本概念 Apache HTTP Server，或者Apache Server，或者httpd，是一个支持Unix和Linux的，提供插件机制的Web Server。 所谓Web Server，是指用来host web sites的软件，hos</summary><published>2012-01-08T11:32:00Z</published><updated>2012-01-08T11:32:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2012/01/08/2316539.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2012/01/08/2316539.html"/><content type="html">&lt;p&gt;比较有名的三个web server，Windows下是IIS，而Linux/Unix下则主要为Appache HTTP Server (httpd), 另外还有一个专门为运行java code的Tomcat Server，当然是跟着java一起跨平台了。&lt;/p&gt;&#xD;
&lt;p&gt;其实Appache HTTP Server也是跨平台的，比如我这两天用的就是Windows下的版本。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;基本概念&lt;/strong&gt; &lt;br /&gt;Apache HTTP Server，或者Apache Server，或者httpd，是一个支持Unix和Linux的，提供插件机制的Web Server。 所谓Web Server，是指用来host web sites的软件，host的内容包括：database, static content与runnable code。&lt;/p&gt;&#xD;
&lt;p&gt;假设你做了一个网站，无论是几个简单的静态网页，还是一个复杂的包含数据库，cgi的动态网站，都需要有一个web server来托管，实现browser - server间的数据传输。&lt;/p&gt;&#xD;
&lt;p&gt;注：&lt;a href="http://en.wikipedia.org/wiki/Dynamic_web_page"&gt;这里&lt;/a&gt;有个关于动态网页，静态网页非常不错的介绍&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;下载安装&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;Apache的官网提供了&lt;a href="http://httpd.apache.org/download.cgi#apache22"&gt;Win32版本的msi&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;下载安装完后，可以看到大概目录结构:&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;bin - httpd等主要可执行文件&lt;br /&gt;cgi-bin - cgi脚本，程序&lt;br /&gt;conf - 配置文件,httpd.conf, mime.types... 下面这些设置都是由配置文件中的配置的决定的。&lt;br /&gt;htdocs - 静态html, javascript的文件的主目录&lt;br /&gt;include - 用来编写module的sdk&lt;br /&gt;lib - 用来编写module的sdk&lt;br /&gt;logs - 执行log，发生错误时可以参考&lt;br /&gt;manual - 文档&lt;br /&gt;modules - httpd的各个功能模块，以so为后缀名，在windows下他们其实是dll&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/li&gt;&#xD;
&lt;li&gt;在浏览器中输入：&lt;a href="http://localhost/"&gt;http://localhost/&lt;/a&gt;，可以看到页面显示：It Works！ 这其实调用了htdocs目录下的index.html文件。&lt;/li&gt;&#xD;
&lt;li&gt;在浏览器中输入：&lt;a href="http://localhost/cgi-bin/printenv.pl"&gt;http://localhost/cgi-bin/printenv.pl&lt;/a&gt;, 可以看到页面中打印出所有相关的环境变量值，这其实是执行了cgi-bin/printenv.pl文件&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p&gt;&lt;strong&gt;操作实践&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;要完成这么一个工作，通过web页面显示与添加一个sqlite数据库中的数据，这就不用手工去打开数据库并select或者insert了。&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;这些功能可以用SSI与CGI实现，这里有两篇关于SSI与CGI的不错的介绍：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;&lt;a href="http://httpd.apache.org/docs/2.2/howto/cgi.html"&gt;CGI: Dynamic Content&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://httpd.apache.org/docs/2.2/howto/ssi.html"&gt;Server Side Includes (SSI)&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;基本上，你需要在httpd.conf做如下配置来启用这些功能：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;# SSI&lt;br /&gt;Options +Includes&lt;br /&gt;&lt;br /&gt;AddType text/html .shtml&lt;br /&gt;AddOutputFilter INCLUDES .shtml&lt;br /&gt;&lt;br /&gt;# CGI&lt;br /&gt;ScriptAlias /cgi-bin/ &lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;D:/System/Apache Software Foundation/Apache2.2/cgi-bin/&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;然后，创建一个main.shtml文件，用来设计网页的总体框架，在需要从数据库读取数据的地方，使用ssi：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;table &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;border&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="1"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;tbody&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;th &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;valign&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="top"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; width&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="174"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;Date&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;th&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;th &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;valign&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="top"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; width&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="114"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;Goodjob&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;th&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;th &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;valign&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="top"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; width&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="241"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;Explain&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;th&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;lt;!--&lt;/span&gt;&lt;span style="color: #008000;"&gt;#exec cgi="/cgi-bin/webpm/yexiaodata.pl"&lt;/span&gt;&lt;span style="color: #008000;"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;tbody&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;table&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;在cgi脚本中，调用sqlite3打开数据库，查询数据并格式化后print出来，该脚本会在每次页面加载或者刷新时被调用。&lt;/p&gt;&#xD;
&lt;p&gt;需要注意的是：cgi脚本的第一行，必须是打印content type：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;print&lt;/span&gt; "Content-type: text/plain;&lt;br /&gt;or&lt;br /&gt;print "Content-&lt;span style="color: #0000ff;"&gt;type&lt;/span&gt;: text/html;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;对于cgi，第二个需要注意的是你要在第一行指定该脚本的解析器，如：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;#!"C:/Program Files/perl64/bin/perl.exe" &lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;当然，你也可以用c语言直接编写可行性文件作为cgi。&lt;br /&gt;perl与c都有一些成熟的cgi库：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;perl：&lt;a href="http://search.cpan.org/~lds/CGI.pm-3.43/CGI.pm"&gt;http://search.cpan.org/~lds/CGI.pm-3.43/CGI.pm&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;c:&amp;nbsp;&lt;a href="http://www.boutell.com/cgic/"&gt;http://www.boutell.com/cgic/&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;然后，插入数据，则使用html form，设计好需要的数据输入，并把form的action设置为某个cgi脚本：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;form &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;action&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="/cgi-bin/webpm/updateyexiao.pl"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; method&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;=GET&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;&amp;lt;fieldset&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;legend&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;New: &lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;legend&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;Date:&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;input &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="date"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; size&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="30"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; value&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="2012-01"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;Goodjob:&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;select &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="goodjob"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;option &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;selected&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;option&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;option&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;0&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;option&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;select&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;Explain:&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;textarea &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="explain"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;NULL&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;textarea&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;input &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Submit"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; type&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="submit"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;fieldset&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;form&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这样，当submit按钮被按下时，form中的数据通过url传给了cgi脚本，cgi脚本中可以通过QUERY_STRING环境变量拿到：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;REQUEST_METHOD: GET&lt;br /&gt;QUERY_STRING: &lt;span style="color: #0000ff;"&gt;date&lt;/span&gt;=2012-01&amp;amp;goodjob=1&amp;amp;explain=NULL&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;于是，我们可以在cgi脚本中解析用户输入的数据，并组成sql语句插入数据库。&lt;/p&gt;&#xD;
&lt;p&gt;一般这么解析：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Get the name and value for each form input:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;my&lt;/span&gt; &lt;span style="color: #800080;"&gt;@pairs&lt;/span&gt; = &lt;span style="color: #0000ff;"&gt;split&lt;/span&gt;(/&amp;amp;/, &lt;span style="color: #800080;"&gt;$ENV&lt;/span&gt;{&lt;span style="color: #000000; font-weight: bold;"&gt;"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;QUERY_STRING&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;"&lt;/span&gt;});&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;my&lt;/span&gt; &lt;span style="color: #800080;"&gt;%Form&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Then for each name/value pair....&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;foreach&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;my&lt;/span&gt; &lt;span style="color: #800080;"&gt;$pair&lt;/span&gt; (&lt;span style="color: #800080;"&gt;@pairs&lt;/span&gt;) {&lt;br /&gt;    &lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Separate the name and value:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: #0000ff;"&gt;my&lt;/span&gt; (&lt;span style="color: #800080;"&gt;$name&lt;/span&gt;, &lt;span style="color: #800080;"&gt;$value&lt;/span&gt;) = &lt;span style="color: #0000ff;"&gt;split&lt;/span&gt;(/=/, &lt;span style="color: #800080;"&gt;$pair&lt;/span&gt;);&lt;br /&gt;    &lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Convert + signs to spaces:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: #800080;"&gt;$value&lt;/span&gt; =~ tr/+/ /;&lt;br /&gt;    &lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Convert hex pairs (%HH) to ASCII characters:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: #800080;"&gt;$value&lt;/span&gt; =~ s/%([a-fA-F0-&lt;span style="color: #800000;"&gt;9&lt;/span&gt;][a-fA-F0-&lt;span style="color: #800000;"&gt;9&lt;/span&gt;])/&lt;span style="color: #0000ff;"&gt;pack&lt;/span&gt;(&lt;span style="color: #000000; font-weight: bold;"&gt;"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;C&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;hex&lt;/span&gt;($&lt;span style="color: #800000;"&gt;1&lt;/span&gt;))/eg;&lt;br /&gt;    &lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Store values in a hash called %FORM:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: #800080;"&gt;$Form&lt;/span&gt;{&lt;span style="color: #800080;"&gt;$name&lt;/span&gt;} = &lt;span style="color: #800080;"&gt;$value&lt;/span&gt;;&lt;br /&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2316539.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2012/01/08/2316539.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2012/01/02/2310109.html</id><title type="text">[try it] 使用sqlite</title><summary type="text">很早就听说过sqlite这个数据库引擎，但鉴于我一贯好逸恶劳，纸上谈兵的恶劣行径，一直没着手玩过它。记得老东家当年做CAD系统的标准库时，用的就是sqlite来存储那些标准零件 - 作为desktop版本的标准库，作为数据库安装发布到单机，sqlite的确是不二之选。并且按照sqlite支持的容量上限2TB来看，如果每个标准库零件要5M，可以存2*1024*1024/5 = 419430个，应该是足够的！这次用sqlite，主要有两个原因：最近想写一个android下微博知识管理器，对于保存离线数据，sqlite是不二之选csdn泄露的密码，把它导入数据库，一是可以做一些分析，二是可以练习一下</summary><published>2012-01-02T08:12:00Z</published><updated>2012-01-02T08:12:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2012/01/02/2310109.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2012/01/02/2310109.html"/><content type="html">&lt;p&gt;很早就听说过sqlite这个数据库引擎，但鉴于我一贯好逸恶劳，纸上谈兵的恶劣行径，一直没着手玩过它。记得老东家当年做CAD系统的标准库时，用的就是sqlite来存储那些标准零件 - 作为desktop版本的标准库，作为数据库安装发布到单机，sqlite的确是不二之选。并且按照sqlite支持的容量上限2TB来看，如果每个标准库零件要5M，可以存2*1024*1024/5 = 419430个，应该是足够的！&lt;/p&gt;&#xD;
&lt;p&gt;这次用sqlite，主要有两个原因：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;最近想写一个android下微博知识管理器，对于保存离线数据，sqlite是不二之选&lt;/li&gt;&#xD;
&lt;li&gt;csdn泄露的密码，把它导入数据库，一是可以做一些分析，二是可以练习一下sql&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;strong&gt;基本概念&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.sqlite.org/index.html"&gt;sqlite&lt;/a&gt;是一个相当有名的单机数据库系统，据说是世界上被部署的最多的数据库系统了 - 那到不意外，作为serverless的单机版数据库，其已经被部署到无数pc，智能设备中，相比那些只部署在强劲服务器上的MS SQLSERVER, MYSQL, ORACLE,DB2等，自然要占很大的优势，相对于这些大型数据库系统，其优势是：资源占用非常少，配置极其简单（无需配置），进程内数据库操作，效率较高；当然，相对的就是其不适合高并发，大数据(&amp;gt;2TB)的应用。&lt;a href="http://www.sqlite.org/whentouse.html"&gt;这篇文章&lt;/a&gt;比较详细的分析了sqlite适合于不适合的场景。&lt;/p&gt;&#xD;
&lt;p&gt;sqlite支持windows，linux和mac，当然也支持Android，&lt;a href="http://developer.android.com/reference/android/database/sqlite/package-summary.html"&gt;android.database.sqlite&lt;/a&gt;是android sdk中提供的api。sqlite除了提供编程接口之外，也提供了一个命令行工具sqlite3来管理数据库：通过它你可以创建数据库、表;插入、查询数据等等。&lt;/p&gt;&#xD;
&lt;p&gt;另外，sqlite网站上列出的关于&lt;a href="http://www.sqlite.org/lang.html"&gt;sql语法&lt;/a&gt;与&lt;a href="http://www.sqlite.org/pragma.html#toc"&gt;pragma&lt;/a&gt;内容，也是非常值得参考的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;下载安装&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;sqlite，正如其宣称的一样，是zero-configuration的，所以一旦你下载解压好了，它就可以用了。一般可以认为sqlite包含3个部分吧：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;SDK&lt;/li&gt;&#xD;
&lt;li&gt;sqlite3命令行工具&lt;/li&gt;&#xD;
&lt;li&gt;sqlite3_analyzer命令行工具&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;你需要在&lt;a href="http://www.sqlite.org/download.html"&gt;这里&lt;/a&gt;下载不同的zip包获得，简单验证一下sqlite3是否工作：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;D:\Source\Data\Password&lt;br /&gt;$ sqlite3 my.db&lt;br /&gt;SQLite version 3.7.5&lt;br /&gt;Enter ".help" &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; instructions&lt;br /&gt;Enter SQL statements terminated with a ";"&lt;br /&gt;sqlite&amp;gt; create table company(name varchar(50) primary key, address varchar(50));&lt;br /&gt;sqlite&amp;gt; insert into company values("Morgan Stanley", "Huamu Road");&lt;br /&gt;sqlite&amp;gt; insert into company values("Autodesk", "Caobao Road");&lt;br /&gt;sqlite&amp;gt; &lt;span style="color: #0000ff;"&gt;select&lt;/span&gt; * from company;&lt;br /&gt;Morgan Stanley|Huamu Road&lt;br /&gt;Autodesk|Caobao Road&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;操作实践&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;可以用两个例子&lt;/p&gt;&#xD;
&lt;p&gt;一、使用sqlite3命令行工具进行数据分析&lt;/p&gt;&#xD;
&lt;p&gt;对象自然是csdn密码库，首先，将密码文本导入数据库：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;D:\Source\Data\Password&lt;br /&gt;$ sqlite3 csdn.db&lt;br /&gt;SQLite version 3.7.5&lt;br /&gt;Enter ".help" &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; instructions&lt;br /&gt;Enter SQL statements terminated with a ";"&lt;br /&gt;sqlite&amp;gt; create table user(id varchar(50) primary key, pwd varchar(50), mail varchar(50));&lt;br /&gt;sqlite&amp;gt; .separator " # "&lt;br /&gt;sqlite&amp;gt; .import csdn/www.csdn.&lt;span style="color: #0000ff;"&gt;net&lt;/span&gt;.sql user&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这里先创建user表，然后用.separator命令设置列分隔符，并使用.import命令导入，因为源数据的格式为：userid # password # mail，当然，如果有人的密码中用了" # "，导入就会失败 - 但貌似csdn的密码库并没有这种情况。（或许黑客同志们事先把这些行去掉了）。&lt;/p&gt;&#xD;
&lt;p&gt;数据有了，看看有多少行：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;sqlite&amp;gt; &lt;span style="color: #0000ff;"&gt;select&lt;/span&gt; count(*) from user；&lt;br /&gt;6428632&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;现在，我要找出csdn中使用最多的10个密码：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;sqlite&amp;gt; &lt;span style="color: #0000ff;"&gt;select&lt;/span&gt; pwd, count(*) from user group by pwd order by count(*) desc limit 10;&lt;br /&gt;123456789|235012&lt;br /&gt;12345678|212749&lt;br /&gt;11111111|76346&lt;br /&gt;dearbook|46053&lt;br /&gt;00000000|34952&lt;br /&gt;123123123|19986&lt;br /&gt;1234567890|17790&lt;br /&gt;88888888|15033&lt;br /&gt;111111111|6995&lt;br /&gt;147258369|5965&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;可以看到，都是一些比较符合键盘分布密码，至于dearbook，那是csdn的另一个子网站，不知道为什么有那么多人选他；而147258369，则很明显是用小键盘敲入的，看来用先键盘的程序员也不在少数。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;二、是简单是使用sqlite3的C/C++编程接口。&lt;/p&gt;&#xD;
&lt;p&gt;你可以直接使用源代码，也可以使用预编译好的dll文件（windows），这里采用dll，因为直接用源码比较简单：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;下载dll包，里面包含一个sqlite3.def和sqlite3.dll两个文件。&lt;/li&gt;&#xD;
&lt;li&gt;下载source code包，需要里面的sqlite3.h头文件&lt;/li&gt;&#xD;
&lt;li&gt;把sqlite3.def转换成lib文件：&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;$ lib /def&lt;span style="color: #800000;"&gt;:sqlite3&lt;/span&gt;.def /machine&lt;span style="color: #800000;"&gt;:x86&lt;/span&gt;&lt;br /&gt;Microsoft (R) Library Manager Version 9.00.30729.01&lt;br /&gt;Copyright (C) Microsoft Corporation.  All rights reserved.&lt;br /&gt;&lt;br /&gt;   Creating library sqlite3.lib and object sqlite3.exp&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/li&gt;&#xD;
&lt;li&gt;创建VC++工程，拷贝&lt;a href="http://www.sqlite.org/quickstart.html"&gt;这里&lt;/a&gt;的C代码，设置additonal include directories和additonal include libraries, 编译并把sqlite3.dll所在目录加入path&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;ul&gt;&amp;nbsp;&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2310109.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2012/01/02/2310109.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/12/31/2308511.html</id><title type="text">[try it] 使用Apache Ant</title><summary type="text">自从用了豆瓣，每每看完一部电影，或者一本书，总会在豆瓣留下几笔，对内容的理解也好，自己的感想也罢，少则用短评，多则用评论，偶尔复习浏览，整个的过程，对记忆非常有帮助，而且不怎么花时间 - 理解感想那是自然而然的事，不要去管什么格式文笔，一挥而就是了 —— 三拜九叩都做了，还怕这最后一哆嗦？但是对于技术，这方面的习惯不好 - 往往用过（试过）之后不注意记录，若干时间后又要用到，却已经忘的差不多了，又得重新来学一遍。 这些主要是一些工具，库什么的，以后就都记在博客中了,标之以[try it] 。要快速的学会使用一个新的工具，library，基本上有这么几个步骤吧：了解其基本概念：这是工具是干什么的</summary><published>2011-12-31T03:14:00Z</published><updated>2011-12-31T03:14:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/12/31/2308511.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/12/31/2308511.html"/><content type="html">&lt;p&gt;自从用了豆瓣，每每看完一部电影，或者一本书，总会在豆瓣留下几笔，对内容的理解也好，自己的感想也罢，少则用短评，多则用评论，偶尔复习浏览，整个的过程，对记忆非常有帮助，而且不怎么花时间 - 理解感想那是自然而然的事，不要去管什么格式文笔，一挥而就是了 &amp;mdash;&amp;mdash; 三拜九叩都做了，还怕这最后一哆嗦？&lt;/p&gt;&#xD;
&lt;p&gt;但是对于技术，这方面的习惯不好 - 往往用过（试过）之后不注意记录，若干时间后又要用到，却已经忘的差不多了，又得重新来学一遍。 这些主要是一些工具，库什么的，以后就都记在博客中了,标之以[try it] 。&lt;/p&gt;&#xD;
&lt;p&gt;要快速的学会使用一个新的工具，library，基本上有这么几个步骤吧：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;了解其基本概念：这是工具是干什么的，大概长的什么样，有什么特点与局限？ 此时对其的认识还是比较抽象的&lt;/li&gt;&#xD;
&lt;li&gt;下载安装其可用版本：保证其能运行，使用&lt;/li&gt;&#xD;
&lt;li&gt;动手实践：根据教程，或者example，自己动手做个东西出来，这样就有一个非常直观的感受了&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;这些资料，一般在官方网站能够找全，如果没有，相信搜也能搜到。&lt;/p&gt;&#xD;
&lt;p&gt;废话讲完了，下面上ant。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;基本概念&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&lt;a href="http://ant.apache.org/"&gt;Apache Ant&lt;/a&gt;是java世界中的make(make是微软世界中的VC project, btw)，是一个主要用来管理软件编译的工具。和make一样，ant也有target，dependency和rule的概念，只不过格式不一样： &lt;br /&gt;make:&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;target:dependencies&lt;br /&gt;    rules &lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;ant&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;target &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="target3"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; depends&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="target1, target2"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; description&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="demo target"&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt; &lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;echo &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;message&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="rules: everything in this section are rules"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;target&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;那么，已经有了make，为什么还需要ant呢？ apache的理由是：&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;1. make的格式比较不标准，tab啊space啊容易出错，ant采用xml，感觉是要标准很多 &lt;br /&gt;2. make多调用shell命令、程序，这对跨平台的java来讲是不能忍受的，ant采用java class实现的"task"，和java跨一样的平台。&lt;/p&gt;&#xD;
&lt;p&gt;这个理由还是蛮靠谱的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;下载安装&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;如果只是使用ant的话，没必要自己没事找事下载source code编译，直接下binary版本：&lt;a href="http://ant.apache.org/bindownload.cgi"&gt;http://ant.apache.org/bindownload.cgi&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;.zip archive: apache-ant-1.8.2-bin.zip&lt;/li&gt;&#xD;
&lt;li&gt;.tar.gz archive: apache-ant-1.8.2-bin.tar.gz&lt;/li&gt;&#xD;
&lt;li&gt;.tar.bz2 archive: apache-ant-1.8.2-bin.tar.bz2&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;这三个包的内容是一样的，只不过适用于不同的平台，.zip是Windows下常用的zip压缩包；.tar.gz是tar打包，gzip压缩；.tar.bz2是tar打包，bzip2压缩。&lt;/p&gt;&#xD;
&lt;p&gt;安装很简单，就是解压缩：&lt;/p&gt;&#xD;
&lt;pre&gt;ant&#xD;
   +--- README, LICENSE, fetch.xml, other text files. //basic information&#xD;
   +--- bin  // contains launcher scripts&#xD;
   |&#xD;
   +--- lib  // contains Ant jars plus necessary dependencies&#xD;
   |&#xD;
   +--- docs // contains documentation&#xD;
   |      |&#xD;
   |      +--- images  // various logos for html documentation&#xD;
   |      |&#xD;
   |      +--- manual  // Ant documentation (a must read ;-)&#xD;
   |&#xD;
   +--- etc // contains xsl goodies to:&#xD;
            //   - create an enhanced report from xml output of various tasks.&#xD;
            //   - migrate your build files and get rid of 'deprecated' warning&#xD;
            //   - ... and more ;-)&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;注意ant需要用到jdk，而不仅仅是jre，你需要设置相关的环境变量：&amp;nbsp;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;set&lt;/span&gt; ANT_HOME=D:\Source\Tools\apache-ant-1.8.2 &lt;br /&gt;&lt;span style="color: #0000ff;"&gt;set&lt;/span&gt; JAVA_HOME=C:\Program &lt;span style="color: #0000ff;"&gt;Files&lt;/span&gt;\Java\jdk1.7.0 &lt;br /&gt;&lt;span style="color: #0000ff;"&gt;set&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;PATH&lt;/span&gt;=%&lt;span style="color: #0000ff;"&gt;PATH&lt;/span&gt;%;%ANT_HOME%\bin &lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;Ant其实是一个java程序，一般通过shell或者batch封装的script运行，比如windows下就是ant.bat，做一些初始化的工作，然后调用java ant-launcher.jar。&lt;/p&gt;&#xD;
&lt;p&gt;好，现在验证一下是否安装成功：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;D:\Source\TestingArena\Java\Ant &lt;br /&gt;$ ant -version &lt;br /&gt;Apache Ant(TM) version 1.8.2 compiled &lt;span style="color: #0000ff;"&gt;on&lt;/span&gt; December 20 2010&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;动手实践&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;ant manual的内容很多，但是要最快的学会一样东西，就是过一遍他的教程：&lt;a href="http://ant.apache.org/manual/index.html"&gt;Manual&lt;/a&gt; -&amp;gt; Tutorials，这些教程写的非常简单明了，而且提供了可以直接使用的代码与build.xml，我花了大概1个小时过了一遍前两个教程：HelloWorld和Write Tasks，就感觉对用ant写java程序，测试java程序有了很好的理解。&lt;br /&gt;&lt;br /&gt;几个tips：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;ant -diagnostics, ant -verbose, ant -debug对调试ant非常有用&lt;/li&gt;&#xD;
&lt;li&gt;跑junit，你需要自行下载junit(&lt;a href="https://github.com/KentBeck/junit/downloads"&gt;https://github.com/KentBeck/junit/downloads&lt;/a&gt;), 命名成junit.jar并放到ant/lib目录中&lt;/li&gt;&#xD;
&lt;li&gt;只要实现了public void execute()函数的java类就可以是一个ant task，ant会使用反射找到并执行它，当然，需要通过taskdef引入：&lt;br /&gt;&amp;nbsp;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&amp;lt;taskdef name="helloworld"&lt;br /&gt;                 classname="HelloWorld"&lt;br /&gt;                 classpath="helloworld.jar"/&amp;gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://ant-contrib.sourceforge.net/"&gt;ant-contrib&lt;/a&gt;是一个比较常用的第三方task库，提供了不少&lt;a href="http://ant-contrib.sourceforge.net/tasks/tasks/"&gt;辅助性质的task&lt;/a&gt;，如if，switch等控制语句. 他们往往提供了一个属性文件供你导入：&lt;br /&gt;&amp;nbsp;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;taskdef &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;resource&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="net/sf/antcontrib/antcontrib.properties"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
该文件内容是task名字与jar包中类名的对应：&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;if=net.sf.antcontrib.logic.IfTask&lt;br /&gt;foreach=net.sf.antcontrib.logic.ForEach&lt;br /&gt;throw=net.sf.antcontrib.logic.Throw&lt;br /&gt;trycatch=net.sf.antcontrib.logic.TryCatchTask&lt;br /&gt;switch=net.sf.antcontrib.logic.Switch&lt;br /&gt;outofdate=net.sf.antcontrib.logic.OutOfDate&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/li&gt;&#xD;
&lt;li&gt;build.xml中的property类似于变量，它也可以在其中文件中定义并导入：&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #008000;"&gt;&amp;lt;!--&lt;/span&gt;&lt;span style="color: #008000;"&gt; build.properties: define the properties &lt;/span&gt;&lt;span style="color: #008000;"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;helloworld.property1=Hello&lt;br /&gt;helloworld.property2=World&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;&amp;lt;!--&lt;/span&gt;&lt;span style="color: #008000;"&gt; build.xml: import and use &lt;/span&gt;&lt;span style="color: #008000;"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;property &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;file&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="build.properties"&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;target &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="tryproperty"&lt;/span&gt;&lt;span style="color: #ff0000;"&gt; description&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Use property file"&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;echo &lt;/span&gt;&lt;span style="color: #ff0000;"&gt;message&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="${helloworld.property1} ${helloworld.property2}"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;target&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/li&gt;&#xD;
&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2308511.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/12/31/2308511.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/11/20/2256314.html</id><title type="text">C++中的头文件发布</title><summary type="text">所谓头文件发布，就是在build某个工程的build过程中，把头文件发布到特定的输出目录，而依赖于此工程的代码，则需要从此特定的输出目录来include头文件。换句话说，在这种做法下，头文件与最终产生的library/binary具有同等地位，它也是build过程的一个产出。我们写C++代码，一般都是直接从source目录包含所需要的头文件的，那么为什么要使用这种头文件发布的方式呢？ 我们可以先分析一下不发布头文件可能带来的问题：因为直接从source目录包含头文件，我们无法控制哪些头文件可以include，而哪些不可以。因为很多情况下，我们很可能只想对用户暴露某个层次的api，但对于用户来说</summary><published>2011-11-20T09:37:00Z</published><updated>2011-11-20T09:37:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/11/20/2256314.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/11/20/2256314.html"/><content type="html">&lt;p&gt;所谓头文件发布，就是在build某个工程的build过程中，把头文件发布到特定的输出目录，而依赖于此工程的代码，则需要从此特定的输出目录来include头文件。换句话说，在这种做法下，头文件与最终产生的library/binary具有同等地位，它也是build过程的一个产出。&lt;/p&gt;&#xD;
&lt;p&gt;我们写C++代码，一般都是直接从source目录包含所需要的头文件的，那么为什么要使用这种头文件发布的方式呢？ 我们可以先分析一下不发布头文件可能带来的问题：&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;因为直接从source目录包含头文件，我们无法控制哪些头文件可以include，而哪些不可以。因为很多情况下，我们很可能只想对用户暴露某个层次的api，但对于用户来说，因为他们在同一目录下，包含任何头文件都是同等方便的。这明显提高了犯错的可能性。&lt;/li&gt;&#xD;
&lt;li&gt;如果build不完整，有些问题要到链接时才能发现。&amp;nbsp;&lt;br /&gt;举个例子，如果A依赖于B，你在B中新增加了个函数，在A中使用。然后你在没有build B的情况下直接build了A，这个错误无法在编译期检测出来，而只有把所有源文件编译完了链接的时候你才被通知有这么个错误，对于大工程，这会是个问题。&lt;/li&gt;&#xD;
&lt;li&gt;如果build不完整，有些问题在运行时才能发现 - 这就是bug了&lt;br /&gt;举个例子，还是A依赖于B，你在B中修改了一个宏定义或者常量定义，如把#define PI 3.14改成了#define PI 3.1415926，然后你又忘了build B而直接去build A了，此时编译没有问题，但是此时模块B与模块A中对PI的定义就不一致了，必然会造成运行时问题，这种问题要更难发现。&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p&gt;所以，为了保证C++代码中接口与binary的完全统一，包括可见性与行为上的统一，使用头文件发布是非常有效的一个方法，对于上述问题：&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;通过只把需要暴露的头文件发布到特定目录，有效的杜绝了用户&amp;rdquo;包含不该包含&amp;ldquo;的头文件的问题&lt;/li&gt;&#xD;
&lt;li&gt;因为B中被更新的头文件未被发布，该问题被提前到编译期被发现&lt;/li&gt;&#xD;
&lt;li&gt;因为B中被更新的头文件未被发布，此时A与B的binary中使用的PI，都是未更新的3.14，从而保证了一致性。&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p&gt;要实现头文件发布，其实也蛮简单，主要是编译设置上的事，对源代码并没有影响：&lt;br /&gt;为方便说明，还是用A依赖于B为例：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;在build B时，把B的头文件拷贝到与输出目录bin同级的目录，比如include目录&lt;/li&gt;&#xD;
&lt;li&gt;在build A时，把上面提到的include目录作为包含目录&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;如果你用Visual Studio的话，可以用post build event；用gmake的话，可以新加一个publish header的rule。&lt;/p&gt;&#xD;
&lt;p&gt;当然，如果你有一个高度智能的build system，这个过程可以完全自动化，比如我们team现在实现的一个，只需指明dependency关系，发布头文件，设置包含目录都自动完成，大大简化了build的维护。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2256314.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/11/20/2256314.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/09/18/2180317.html</id><title type="text">新环境，新印象</title><summary type="text">两个月前的今天，离开老东家，投奔新东家，中间不带一点过渡的，这点曾经让我觉得无奈，但也偶尔让我为自己感动一把 —— 真够勤劳的~~~。 不管怎样，6年之后，我终于跳了我人生中第一个槽，。好处是，以后同学聚会，大家不会像看外星人一样盯着我，然后声音提高八度：”神马 - - -，你还在那个公司......&amp;quot; （注意，以上马字读4拍） 恩，还是谈谈新的环境吧。 以前，基本上是躺在windo...</summary><published>2011-09-18T04:39:00Z</published><updated>2011-09-18T04:39:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/09/18/2180317.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/09/18/2180317.html"/><content type="html">&lt;p&gt;两个月前的今天，离开老东家，投奔新东家，中间不带一点过渡的，这点曾经让我觉得无奈，但也偶尔让我为自己感动一把 —— 真够勤劳的~~~。&lt;/p&gt;  &lt;p&gt;不管怎样，6年之后，我终于跳了我人生中第一个槽，。好处是，以后同学聚会，大家不会像看外星人一样盯着我，然后声音提高八度：”神马 - - -，你还在那个公司......&amp;quot; （注意，以上马字读4拍） &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;恩，还是谈谈新的环境吧。&lt;/p&gt;  &lt;p&gt;以前，基本上是躺在windows与visual studio的怀抱里做开发的，顶多打开notepad++，写一些perl脚本happy一下。想不到，换个环境，真的就换了个环境，现在，windows基本上是用来收发邮件的；visual studio基本上是不用的。因为基本上是命令行，所以鼠标基本是不要的 ，键盘是要好好供奉的。这是一个很大的mindset的改变，刚开始的时候，经常会对着shell窗口不知所措，linux命令，vim命令，甚至连p4，都是使用命令行版本的 - 实在是有太多命令要记哪。但当渐渐习惯之后，觉得这样的操作实在非常爽，在windows下也恨不得用cmd来做所有的操作。&lt;/p&gt;  &lt;p&gt;除了基本操作模式的改变之外，就是开发环境的不同，linux下C++开发的那一套以前也是不熟悉的：gcc - gdb - gmak。当然，公司基本的IT infrastructure也是大不相同的，最后也是最终要的，就是我所参与的项目本身了。所以很开心，可以接触、实践很多新东西；但是也很明显，学习东西是要时间与精力的，不然，你会很累的~~~ &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;但不知是不是当初招我进来的老板等的不耐烦了，在我入职2个礼拜后，这位大人就毅然决然的离开了，要知道，他入职也不过半年左右而已，公司本来应该是期望他在东亚地区打造一支队伍的~~~。&lt;/p&gt;  &lt;p&gt;可现在，这边连老板本来才三个人，老大跑路了，可该干的活还是要干的，于是，悲剧的一幕出现了：突然天降两个老板各带来一个小项目，兢兢业业的给予讲解，孜孜不倦的给予催促——轮流催促。再加上那么多额外的东西要学，真心是累的要死了。本来骨头挺硬的，work-life balance很重要，回家决不碰工作上的事，看电视、读历史、学技术爱咋咋地。慢慢的就撑不住了，算了，毕竟开头一段时间，辛苦辛苦可以理解，回家可以学点工作相关的知识~~~。&lt;/p&gt;  &lt;p&gt;这事我偶尔也在琢磨，到底为啥会这样呢，磨刀不误砍柴工这个道理，应该老美也懂才对，琢磨来琢磨去，得出这么几个可能原因： &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;老大跑路，没人罩着了&lt;/li&gt;    &lt;li&gt;老大跑路，没做好交接工作，导致老美那边以为我来了好几年了。&lt;/li&gt;    &lt;li&gt;咱公司本来就这样，这叫魔鬼训练~~~&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;虽说我挺喜欢这句话的：&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;Life is not about waiting for storm to pass, it is about learning to dance in the rain&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;但我也相信，学会在雨中跳舞就可以了，谁他妈没事天天在雨中跳舞。 不管咋的，相信再熬段时间，慢慢上手了就不会这么紧张了。&lt;/p&gt;  &lt;p&gt;新老板告诉我，面对这种情况要have a sense of humor，我觉得蛮有道理的，活学活用一下，至少，如此频度的交流，对锻炼英语还是不错的~~~&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;以前上班，那叫一个近啊。每天早上电瓶车，跐溜一下五分钟搞定；现在路上一个小时多，反差太大，导致我一度认为这会是我最大的障碍。然而，我太低估自己的适应能力了，什么换多次车，什么挤地铁，只要你找到了合适的方法，你就能非常好的适应了。几个礼拜前，我每天上下班看电视剧《走向共和》，一趟一集，一天两集，非常高效；而这段时间，则一直在读《明朝那些事》，哗哗的7部就读完了，相当充实，正琢磨接下去看啥呢。 对了，友情提示一下，我是用我那个G7的手机看的，纸质书或者IPAD，携带不便且在拥挤的车厢里不易摆开架势。 如今，想到早上要出门赶车了，竟然还有一丝窃喜：恩，又可以看会书了。 &lt;/p&gt;  &lt;p&gt;当然了，其他的比如不得不穿衬衫皮鞋啥的，每天高强度工作满8个小时啥的（欧特克的时候，上上网，聊聊天，喝喝水，去去洗水间，6个小时就算不错了吧），也都一一适应了。 正如另一位从思科来的同学感慨到：“到了大摩，大大地端正了工作态度啊”。 看来思科和欧特克也差不离~~~&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;公司刚从外滩中心搬到嘉里中心，虽然位置一贯的那么小，但环境还算可以，地带不错，采光巨好。 虽然一度抱怨电脑配置差了点，但发现自己还有一台16核12G内存的机子后，我就闭嘴了，虽然在美国，但好歹归我远程操控。 &lt;/p&gt;  &lt;p&gt;于是，上周带了盆绿萝和一本《代码大全》过去，算是装饰一下我的cubicle - 这是莫大的肯定。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2180317.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/09/18/2180317.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/08/27/2155807.html</id><title type="text">好诗收藏</title><summary type="text">咏菊------黄巢待到秋来九月八，我花开后百花杀。冲天香阵透长安，满城尽带黄金甲。入都------李鸿章丈夫只手把吴钩，意气高于百尺楼。一万年来谁著史，三千里外欲封侯。定将捷足随途骥，哪有闲情逐水鸥？遥指芦沟桥畔月，几人从此到瀛洲？石灰吟 ------于谦千锤万凿出深山，烈火焚烧若等闲。粉骨碎身浑不怕，要留清白在人间。元末明初造反口号------韩山童，刘福通莫道石人一只眼，挑动黄河天下反（说实话我真没理解这词到底啥逻辑，不过感觉读起来朗朗上口，而且最后三个字也挑明了主题~）</summary><published>2011-08-27T13:56:00Z</published><updated>2011-08-27T13:56:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/08/27/2155807.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/08/27/2155807.html"/><content type="html">&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;咏菊&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;------黄巢&lt;/p&gt;&#xD;
&lt;p&gt;待到秋来九月八，我花开后百花杀。&lt;/p&gt;&#xD;
&lt;p&gt;冲天香阵透长安，满城尽带黄金甲。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&#xD;
&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;入都&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;------李鸿章&lt;/p&gt;&#xD;
&lt;p&gt;丈夫只手把吴钩，意气高于百尺楼。&lt;/p&gt;&#xD;
&lt;p&gt;一万年来谁著史，三千里外欲封侯。&lt;/p&gt;&#xD;
&lt;p&gt;定将捷足随途骥，哪有闲情逐水鸥？&lt;/p&gt;&#xD;
&lt;p&gt;遥指芦沟桥畔月，几人从此到瀛洲？&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&#xD;
&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;石灰吟 &lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;------于谦&lt;/p&gt;&#xD;
&lt;p&gt;千锤万凿出深山，烈火焚烧若等闲。&lt;/p&gt;&#xD;
&lt;p&gt;粉骨碎身浑不怕，要留清白在人间。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br /&gt;&#xD;
&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;元末明初造反口号&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;------韩山童，刘福通&lt;/p&gt;&#xD;
&lt;p&gt;莫道石人一只眼，挑动黄河天下反&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span style="color: #008000;"&gt;（说实话我真没理解这词到底啥逻辑，不过感觉读起来朗朗上口，而且最后三个字也挑明了主题~）&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2155807.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/08/27/2155807.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/07/26/2117684.html</id><title type="text">又见Dooyoul</title><summary type="text">Dooyoul是个韩国人，他有个很古代的韩国名字，翻译过来叫：郑斗悦，恩，有点像《大长今》中的某个人物了。Dooyoul是我在Autodesk时的同事，我们不是同一个team，但是去美国office的时候，让我认识了这个热情，友善、坦率的韩国人。Dooyoul保龄球玩的很酷，高尔夫据说也是江湖闻名，而且，除了韩文和英文，尽然还能读中文和日文，怎一个牛逼了得~~~我们在Novi期间，Dooyoul是我们最好的伙伴 -周末了，开车带我们出去玩，至今我还念念不忘环密西根游那次美好的经历中午了，带我们在公司周围遍尝不同的餐馆，要知道，那个乡下地方，要没个车，那是寸步难行哪下雨了，开车到hotel下面来</summary><published>2011-07-26T13:53:00Z</published><updated>2011-07-26T13:53:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/07/26/2117684.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/07/26/2117684.html"/><content type="html">&lt;p&gt;Dooyoul是个韩国人，他有个很古代的韩国名字，翻译过来叫：郑斗悦，恩，有点像《大长今》中的某个人物了。&lt;br /&gt;Dooyoul是我在Autodesk时的同事，我们不是同一个team，但是去美国office的时候，让我认识了这个热情，友善、坦率的韩国人。&lt;br /&gt;Dooyoul保龄球玩的很酷，高尔夫据说也是江湖闻名，而且，除了韩文和英文，尽然还能读中文和日文，怎一个牛逼了得~~~&lt;/p&gt;&#xD;
&lt;p&gt;我们在Novi期间，Dooyoul是我们最好的伙伴 -&lt;br /&gt;周末了，开车带我们出去玩，至今我还念念不忘环密西根游那次美好的经历&lt;br /&gt;中午了，带我们在公司周围遍尝不同的餐馆，要知道，那个乡下地方，要没个车，那是寸步难行哪&lt;br /&gt;下雨了，开车到hotel下面来等我们，送我们去公司&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;太好的一个韩国男人了，怎么说呢，他给我一个错觉，让我觉得韩国人都他妈是非常nice的~&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这次Dooyoul来上海了，怎么着也得招待一下，虽然我不在公司了，还是想方设法约了出来，一起吃个饭，聊聊天，叙叙旧，还是当时一起的几个人，Danio和Cher，&amp;nbsp;非常感谢Danio同学的细心安排，还有他那辆307～～～　&lt;/p&gt;&#xD;
&lt;p&gt;公司比较远，所以4:30就下班了，赶到&amp;ldquo;母司&amp;rdquo;后，6点出发，本来Danio是在龙茗路找了一家牛蛙馆，但遭到了大家的一致反对，于是便就近进了家徽珍源~ 然后便是吃啊，聊啊，还弄了瓶上海石库门（上海特色）和一扎杨梅汁（余姚老家特产），够有意义的了吧。&lt;/p&gt;&#xD;
&lt;p&gt;聊得甚欢...&lt;/p&gt;&#xD;
&lt;p&gt;还在聊...&lt;/p&gt;&#xD;
&lt;p&gt;还在聊...&lt;/p&gt;&#xD;
&lt;p&gt;之间不由得又聊到了Dooyoul那美丽贤惠的而又know everything的妻子，他说我离开公司他一点都不surprise，因为她妻子当时见过我之后就对他说：He can't stay long, he wants to know everything, and won't be satisfied with... &amp;nbsp; 我靠~~~这她也能看出来！！！(此为嘉宾言论，不代表本台观点)&lt;/p&gt;&#xD;
&lt;p&gt;本来是我招待的，结果还是Dooyoul付的钱 - 出差那个啥的，你懂的！&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;可惜Dooyoul这次只呆一个礼拜，且没有周末，希望下次他来上海，有时间带他到上海周围转转~&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2117684.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/07/26/2117684.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/07/10/2102484.html</id><title type="text">不要在公共接口中传递STL容器</title><summary type="text">最近的一个项目，是开发一个framework，提供给公司内部不同的产品线使用。 之间遇到的一个问题，就是STL容器的使用， 而结论是不要在公共接口中传递STL容器：这里说的STL容器，但主要则是指容器，字符串类，但其实可以推广到在STL中提供的任何类型，这里说的公共接口，是指需要暴露给客户的sdk头文件，包括函数签名，或者类成员变量；也可以说，不要在暴露给客户的头文件中包含STL的头文件。原因分析为什么有这个结论，我们可以从几个方面来论述：客户端使用的STL版本可能不同因为STL作为标准库，Framework编译的时候使用的STL，与客户端编译的时候使用的STL，版本是有可能不一样的，比如Fr</summary><published>2011-07-10T11:32:00Z</published><updated>2011-07-10T11:32:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/07/10/2102484.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/07/10/2102484.html"/><content type="html">&lt;p&gt;最近的一个项目，是开发一个framework，提供给公司内部不同的产品线使用。 之间遇到的一个问题，就是STL容器的使用， 而结论是不要在公共接口中传递STL容器：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;这里说的STL容器，但主要则是指容器，字符串类，但其实可以推广到在STL中提供的任何类型，&lt;/li&gt;&#xD;
&lt;li&gt;这里说的公共接口，是指需要暴露给客户的sdk头文件，包括函数签名，或者类成员变量；&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;也可以说，不要在暴露给客户的头文件中包含STL的头文件。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;为什么有这个结论，我们可以从几个方面来论述：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;客户端使用的STL版本可能不同&lt;br /&gt;因为STL作为标准库，Framework编译的时候使用的STL，与客户端编译的时候使用的STL，版本是有可能不一样的，比如Framework使用VC8编译发布，而客户代码使用VC10编译使用，那么Framework所理解的STL容器，与客户端代码所理解的STL容器，在内存布局上，数据表示上是有可能不一样的，出错也就不可避免了。&lt;/li&gt;&#xD;
&lt;li&gt;编译选项&lt;br /&gt;即使Framework和客户端使用的是同一个版本的STL，但是如果编译选项不一样，也可能导致其不一致性，自然也会出错。&lt;/li&gt;&#xD;
&lt;li&gt;静态变量&lt;br /&gt;即使版本一致，编译选项一致，仍然是不安全的，因为STL容器的实现中，有可能使用了静态变量，而在Framework模块和客户端模块中，虽然由于模板扩展产生的两份代码总体上是一致的，但都各自维护了一份静态变量，从而造成了内部状态的不一致性。&lt;/li&gt;&#xD;
&lt;li&gt;客户端的STL被自定义&lt;br /&gt;但从文件的角度来看，在客户端包含的STL头文件实现，可以是完全不同于标准的 - 只要其接口和标准保持一致。 比如客户那边使用的STL在内存管理方面有特殊需求，改写了默认的allocator，那么内存必然会出问题；比如客户在实现中加入了其他成员变量，那么内存布局必然也不一致。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;虽然，&lt;a href="http://support.microsoft.com/kb/168958"&gt;微软这篇文章&lt;/a&gt;提到导出vector是安全的，但这应该是有风险的：&lt;/p&gt;&#xD;
&lt;p&gt;除非能够确信你的DLL和DLL的使用者会使用完全相同的STL - 版本一致，编译选项一致，没有被自定义过等，不然就可能导致行为的不一致性：&lt;br /&gt;举个例子，你在DLL中导出了vector&amp;lt;int&amp;gt;，而这个DLL的客户使用的stl是自定义的版本，内存管理由其自己实现，那么vector&amp;lt;int&amp;gt;在客户方就可能有了两种含义。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;可选方案&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;但事实上，你还是可能存在这种需求的 - 你需要容器类的函数参数或者返回值，你可能也需要容器类的类成员变量，那么如何解决？&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;对于前者，我们可以针对具体的类型封装一个具体的容器类，内部还是可以使用STL container的；&lt;br /&gt;对于后者，我们可以用一些办法，防止STL容器出现在头文件中；&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;解决的方法，可以有以下几种：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;提供自己的容器类&lt;br /&gt;这是最彻底，最直接的方法，但是提供一套与STL相当的模板容器类需要蛮大的工作量，而且明显是重复制造轮子了。 要注意，这里简单的对STL容器进行封装是行不通，因为模板不支持分离编译，这么做还是会把STL容器带入公共接口。&lt;/li&gt;&#xD;
&lt;li&gt;PImpl&lt;br /&gt;PImpl模式当然很强大，当然可以解决这个问题，但是此处如果仅仅是为了隐藏容器类，难免杀鸡用牛刀，还引入了不必要的间接层与繁琐的脚手架代码。&lt;/li&gt;&#xD;
&lt;li&gt;使用void*作为数据成员，而后强制转换为容器类&lt;br /&gt;不安全也太丑陋，用起来也繁琐，每次都要cast以下，除非别无他法，是在不应该考虑这个方案。&amp;nbsp;&lt;/li&gt;&#xD;
&lt;li&gt;前置声明STL容器&amp;nbsp;&lt;br /&gt;这个方法在VC9中是可以工作的，但是根据C++标准：&amp;nbsp;17.4.3.1 Reserved names，这种做法是未定义的：&lt;br /&gt;&amp;ldquo;&#xD;
It is undefined for a C++ program to add declarations or definitions to namespace&amp;nbsp;&lt;tt&gt;std&amp;nbsp;&lt;/tt&gt;or namespaces within namespace&amp;nbsp;&lt;tt&gt;std&amp;nbsp;&lt;/tt&gt;unless otherwise specified&amp;rdquo;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&#xD;
&lt;li&gt;自定义结构体封装容器并前置声明&lt;br /&gt;这个方案是这样的：&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;头文件&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; PublicClassData;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; PublicClass&lt;br /&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;br /&gt;    PublicClass();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;br /&gt;    PublicClassData&lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt; m_pData;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;实现文件&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; PublicClassData&lt;br /&gt;{&lt;br /&gt;    vector&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _array;&lt;br /&gt;    map&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _map;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;PublicClass::PublicClass()&lt;br /&gt;{&lt;br /&gt;    m_pData &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; PublicClassData;&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;br /&gt;当然，需要注意的是我们需要遵循：rule of three，提供析构，赋值与拷贝构造函数以管理内存。&lt;br /&gt;这个方案相对来讲比较简洁，应该说是现有方案的最有实践性的一个。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;所以，结论就是不要在DLL/SO的公共接口中使用STL容器，如果你确实需要，那么请用&lt;strong&gt;自定义结构体封装容器并前置声明&lt;/strong&gt;的方式隔离STL容器！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2102484.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/07/10/2102484.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/05/31/2063905.html</id><title type="text">尾递归的优化</title><summary type="text">尾递归就是递归调用在函数的最后一步，这样的递归可以被编译器优化成类似于循环的形式，无须保存stack frame和局部变量，提高性能，一般可以通过一个accumulator参数将一个传统递归改造成尾递归， 一下是一个C++中的例子：int factorial_tail_recursion(int n, int acc){	if (n == 1)	{ return acc;	}	return factorial_tail_recursion(n-1, acc * n);}int factorial(int n){	if (n == 1)	{ return 1;	}	return n * fact</summary><published>2011-05-30T20:30:00Z</published><updated>2011-05-30T20:30:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/05/31/2063905.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/05/31/2063905.html"/><content type="html">&lt;p&gt;尾递归就是递归调用在函数的最后一步，这样的递归可以被编译器优化成类似于循环的形式，无须保存stack frame和局部变量，提高性能，一般可以通过一个accumulator参数将一个传统递归改造成尾递归， 一下是一个C++中的例子：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;int factorial_tail_recursion(int n, int acc)&#xD;
{&#xD;
	if (n == 1)&#xD;
	{&#xD;
		return acc;&#xD;
	}&#xD;
&#xD;
	return factorial_tail_recursion(n-1, acc * n);&#xD;
}&#xD;
&#xD;
int factorial(int n)&#xD;
{&#xD;
	if (n == 1)&#xD;
	{&#xD;
		return 1;&#xD;
	}&#xD;
&#xD;
	return n * factorial(n-1);&#xD;
}&#xD;
&#xD;
int main(int argc, const char *argv[])&#xD;
{&#xD;
&#xD;
	// no stack overflow&#xD;
	int v1 = factorial_tail_recursion(1000000000, 1);&#xD;
	cout &amp;lt;&amp;lt; v1 &amp;lt;&amp;lt; endl;&#xD;
&#xD;
&#xD;
	// stack overflow&#xD;
	int v2 = factorial(1000000000);&#xD;
&#xD;
	cout &amp;lt;&amp;lt; v2 &amp;lt;&amp;lt; endl;&#xD;
&#xD;
	return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;可以参考：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/03/26/tail-recursion-and-continuation.html"&gt;http://www.cnblogs.com/JeffreyZhao/archive/2009/03/26/tail-recursion-and-continuation.html&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Tail_recursion"&gt;http://en.wikipedia.org/wiki/Tail_recursion&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2063905.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/05/31/2063905.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/baiyanhuang/archive/2011/05/20/2051704.html</id><title type="text">C++阴暗面</title><summary type="text">近来一篇&amp;lt;The Dark Side Of C++&amp;gt;在坊间广为转载，作为一个以C++为吃饭家伙的程序员，还是应该下载下来好好读一读的。 总的来讲还是总结的蛮全的，由于个人知识的限制，我读完后将其分为三类：一类是我不以为然的，觉得算不上阴暗面；一类是深有同感，深受其害；而另外一类则是还不理解，需要日后有时间的时候加以研究的。一、不以为然不断变更的标准，迫使我们需要不断更新已有代码。 作者列出了几点其实影响并不是很大（循环变量的scope；头文件后缀；名字空间）。而且，为了标准的进步，偶尔做出的妥协也是应该的吧。不断变更的style，作者举得例子是：Old and busted:for</summary><published>2011-05-20T03:55:00Z</published><updated>2011-05-20T03:55:00Z</updated><author><name>lzprgmr</name><uri>http://www.cnblogs.com/baiyanhuang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/baiyanhuang/archive/2011/05/20/2051704.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/baiyanhuang/archive/2011/05/20/2051704.html"/><content type="html">&lt;p&gt;近来一篇&lt;a href="http://www.fefe.de/c++/c%2b%2b-talk.pdf"&gt;&amp;lt;The Dark Side Of C++&amp;gt;&lt;/a&gt;在坊间广为转载，作为一个以C++为吃饭家伙的程序员，还是应该下载下来好好读一读的。 总的来讲还是总结的蛮全的，由于个人知识的限制，我读完后将其分为三类：一类是我不以为然的，觉得算不上阴暗面；一类是深有同感，深受其害；而另外一类则是还不理解，需要日后有时间的时候加以研究的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;一、不以为然&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;不断变更的标准，迫使我们需要不断更新已有代码。 &lt;br /&gt;作者列出了几点其实影响并不是很大（循环变量的scope；头文件后缀；名字空间）。而且，为了标准的进步，偶尔做出的妥协也是应该的吧。&lt;/li&gt;&#xD;
&lt;li&gt;不断变更的style，作者举得例子是：&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #000000;"&gt;Old and busted:&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; i &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;; i &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; n; i&lt;/span&gt;&lt;span style="color: #000000;"&gt;++&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br /&gt;New hotness:&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; i(&lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;); i &lt;/span&gt;&lt;span style="color: #000000;"&gt;!=&lt;/span&gt;&lt;span style="color: #000000;"&gt; n; &lt;/span&gt;&lt;span style="color: #000000;"&gt;++&lt;/span&gt;&lt;span style="color: #000000;"&gt;i)&lt;/span&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&amp;nbsp; 有这个问题吗？有人用第二种方式的吗？&amp;nbsp;&lt;/li&gt;&#xD;
&lt;li&gt;auto_ptr很烂。&lt;br /&gt;这个，你不用它就是了，而且最近在智能指针加入C++0x大家庭后，应该达成共识了吧&lt;/li&gt;&#xD;
&lt;li&gt;iterator可能会失效。&lt;br /&gt;这个我感觉还好，没遇到过太多问题；&lt;/li&gt;&#xD;
&lt;li&gt;iterator对container毫不知情。&lt;br /&gt;我觉得这是STL设计的一个优点吧，通过iterator解耦算法与容器。&lt;/li&gt;&#xD;
&lt;li&gt;vector::at会做边界检查，而operator []不会。&lt;br /&gt;很好啊，提供两种选择&lt;/li&gt;&#xD;
&lt;li&gt;构造函数与析构函数中的虚函数调用，可能会调用基类的虚函数，甚至是纯虚函数。&lt;br /&gt;这个不怎么阴暗吧，不要在构造函数与析构函数总调用虚函数应该是个常识，而且，其他语言难道没有这个问题？&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;strong&gt;二、深有同感&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;模板中排山倒海式的编译错误，在繁琐无比的错误后面，原因可能仅仅是用错了iterator类型。那个被毙掉的C++ 0x proposal不知是否可以解决此问题。&lt;/li&gt;&#xD;
&lt;li&gt;用C++写的代码不太容易读，函数重载，操作符重载，虚函数重定义，类型重定义，宏定义等等，把代码的真实面貌严严实实的藏在了身后。（当然，这也是为了抽象与一致性），几个例子：&lt;br /&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; a(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;blah&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;); &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 定义一个string对象&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; a(); &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;声明一个函数&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;a &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; b &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 如果&amp;amp;&amp;amp;没被重定义，是短路计算；但若是被重载了，那么可能两个都要计算&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;typedef OtherType&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; Type;&lt;br /&gt;Type a &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; b;&lt;br /&gt;a.value &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;23&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 不看到那个typedef，鬼知道b的值会不会被改掉&lt;/span&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;br /&gt;&amp;nbsp;另外，&amp;nbsp;baz = foo-&amp;gt;bar(3)；如此简单的一行代码背后蕴含的无穷可能，也充分体现了C++代码难读的特点。&lt;/li&gt;&#xD;
&lt;li&gt;关于cin为什么typecast到void*，而不是bool的讨论，凸显了C++中剑走偏锋的情况 - 火候不到，一招不慎就很容易伤及自身。&lt;/li&gt;&#xD;
&lt;li&gt;析构函数中不应该抛出异常，我以前只知道一个原因 - 就是在前次异常的栈展开过程中调用析构函数并抛出异常，会导致程序退出。但这里给出了我觉得更有说服力的原因：在delete []数组的时候，前面对象析构抛出异常，会导致数组中其他对象内存泄露。&lt;/li&gt;&#xD;
&lt;li&gt;类成员的初始化顺序由其定义的顺序决定，而不是初始化列表中的顺序 - 这点的确引起了较大的迷惑，也带来了不少bug - 因为C++的行为是反直觉的。&lt;/li&gt;&#xD;
&lt;li&gt;函数调用中，传指针的方式比较明显的告诉你该函数可能会改变这个参数，而引用却没这么明显，语法和传值调用一样，却也可以改变参数值。&lt;/li&gt;&#xD;
&lt;li&gt;C++过于强大，过于灵活，很多人无法很好的掌控 - 太多复杂的feature set，要用好它，你可以读个博士了~~~&lt;/li&gt;&#xD;
&lt;li&gt;prefix ++的重载语法是：operator++(yourtype&amp;amp;)， 为了加以区别，postfix的重载语法有个dummy的int参数：operator++(yourtype&amp;amp;, int dummy)。&lt;br /&gt; 虽然我也没有更好的方法，但我承认这的确很傻。&lt;/li&gt;&#xD;
&lt;li&gt;同样的容器，由于使用了不同的allocator就无法交互了，这可以理解，因为STL中allocator是容器类型的一部分，allocator不同导致容器类型不同 - 但这不得不让我们思考STL用这种方式提供allocator是不是合适。&lt;/li&gt;&#xD;
&lt;li&gt;map的operator[]自动添加元素，如果不存在的话。&lt;br /&gt;因为相比于find和insert，operator []实在是太方便了，这个方便的诱惑的确造成了不少麻烦。&lt;/li&gt;&#xD;
&lt;li&gt;模板中你不得不把&amp;gt;&amp;gt;写成&amp;gt; &amp;gt;。因为&amp;gt;&amp;gt;已经被占用了。&lt;/li&gt;&#xD;
&lt;li&gt;用不用exception，如何用好exception实在是个太大太深的话题，都可以在大学开个博士学位了。其中异常安全中resource leak，deadlock是常见的问题。&lt;/li&gt;&#xD;
&lt;li&gt;delete []可以很好的处理退化为指针的数组，如果是类的话调用会调用的析构函数s，因为数组元素的个数可以通过sizeof(memoryblock)/sizeof(type)求出。&lt;/li&gt;&#xD;
&lt;li&gt;new []可能会引起int的溢出，如: new double [0x8000000] = malloc (8 * 0x80000000)，超过了int的表达范围，溢出~&lt;/li&gt;&#xD;
&lt;li&gt;局部静态变量的初始化不是线程安全的 - 这个问题在多线程环境下的单件模式中尤为常见，一般可以用lock解决，但是每次访问都lock比较费力，所以会用一种double-check lock的方式，但是这种方式由于编译器优化引起的reorder，也会线程不安全，需要使用volatile，或者memory barrier防止优化。这个估计可以另外写篇文章了。&lt;/li&gt;&#xD;
&lt;li&gt;用基类指针操作派生类的数组，p++不是指向下一个元素，而是指向了一个不合适的内存地址。&lt;/li&gt;&#xD;
&lt;li&gt;如果你在派生类中有个函数的名字和基类中的函数名字重复，即使函数原型不一样，其基类中的函数都将在派生类中被隐藏。&lt;br /&gt;这点的确比较过分！背后有什么原因呢？&amp;nbsp;&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;strong&gt;三、日后研究&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;关于名字空间，C++有过什么大的更改么？ &lt;br /&gt;这个估计要查查《C++语言的设计与演化》了&lt;/li&gt;&#xD;
&lt;li&gt;用C++写出好的库基本是不可能的。&lt;br /&gt;我看到很多人，包括牛人都说过这个，但是不知有没有给过一个列表，C++中那些缺点使其写出好的库成为不可能，哪些语言可以，为什么？&lt;/li&gt;&#xD;
&lt;li&gt;我们不应该在构造函数中抛出异常，因为：Exceptions in constructor don&amp;rsquo;t unwind the constructor itself。 &lt;br /&gt;这个不太理解，据我所知，在构造函数中抛出异常是构造函数报错的一个方法，因为构造函数本身不返回任何值。&lt;/li&gt;&#xD;
&lt;li&gt;抛出异常时：Does not even clean up local variables！&lt;br /&gt;不理解，我们的RAII不就是利用local对象的析构来做内存管理的吗。&lt;/li&gt;&#xD;
&lt;li&gt;assert(s[s.size()] == 0); works if s is a const std::string, butis undeﬁned if it is not const&lt;br /&gt;在VC2008上试了一下，没问题。为什么会这么说，为什么？&amp;nbsp;&lt;/li&gt;&#xD;
&lt;li&gt;If you call delete when you should have called delete[], the pointer wilbe off by sizeof(int), leading to heap corruption and possibly code execution. &lt;br /&gt;不懂。&lt;/li&gt;&#xD;
&lt;li&gt;If you call delete[] when you should have called delete, some randomdestructors will be called on garbage data, probably leading to code execution. &lt;br /&gt;为什么，delete[]会去计算该数组中有几个元素，而答案应该是1，那就不该有问题 - 这个可能和上一点的答案有关。&lt;/li&gt;&#xD;
&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/baiyanhuang/aggbug/2051704.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/baiyanhuang/archive/2011/05/20/2051704.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
