<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feedsky.blogbus.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><link atom:type="text/html">http://bigwhite.blogbus.com/</link><fs:self_link href="http://feeds.feedsky.com/blogbus.com/bigwhite_blogbus_com" type="application/rss+xml"></fs:self_link><lastBuildDate>Fri, 05 Sep 2008 16:11:05 GMT</lastBuildDate><title>Tony Bai</title><description>一个程序员的心路历程</description><atom:link href="http://feedsky.blogbus.com/bigwhite_blogbus_com" type="application/rss+xml" rel="self"></atom:link><generator xmlns="http://www.w3.org/2005/Atom" uri="http://www.blogbus.com/">博客大巴</generator><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/atom.xml</id><link xmlns="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://bigwhite.blogbus.com/atom.xml"></link><pubDate>Fri, 05 Sep 2008 23:59:53 GMT</pubDate><image><title>Tony Bai</title><url>http://www.blogbus.com/profile/5/4/4/40445/avatar_40445_96.jpg</url><link>http://bigwhite.blogbus.com/</link></image><item><title>发现一隐藏多年的Bug？</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/28582799.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/28582799.html</id><description>C语言程序员在平时工作中，到底如何获取成就感呢？我几乎可以肯定的是：找到一个隐藏已久，多年无人发现的大Bug肯定可以归属到C程序员成就感的范畴中。与操作系统斗、与编译器斗、与内存斗，其乐无穷吗^_^。&lt;br /&gt;&lt;br /&gt;今天测试人员在进行平台迁移测试时发现一个致命的问题，导致系统不能正常工作。问题提到我这，为了不耽误测试进度，马上丢下手头的工作开始问题的查找，经过&lt;a href=&quot;http://bigwhite.blogbus.com/logs/1801699.html&quot; target=&quot;_blank&quot;&gt;GDB&lt;/a&gt;多次跟踪调试，终于发现了一隐藏多年的问题，至于能否称为Bug呢，我还不敢确定，因为我尚不清楚当年的前辈们在书写这些代码时到底是如何考虑的。&lt;br /&gt;&lt;br /&gt;前不久听说隐藏在FreeBSD系统中长达25年的一个Bug终于被Fixed了，当然今天我发现的这个问题肯定不及FreeBSD的这个Bug重要，但是对于我们的产品来说还是有很大意义的。&lt;br /&gt;&lt;br /&gt;其实这个问题很简单，这里简单用一个例子来展示这个问题(稍后我还会用这个例子做进一步深入分析)：&lt;br /&gt;/* TestFoo.c 注意该文件并不一定在所有编译器下都能顺利编译通过，警告是不可避免的了 */&lt;br /&gt;&lt;br /&gt;typedef struct Foo {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c;&lt;br /&gt;} Foo;&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Foo f;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; f.a = 17;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; f.b = 23;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; f.c = 19;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; test_foo(f);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void test_foo(Foo *pfoo) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pfoo-&amp;gt;c = 29;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;明眼人一眼就能看得出来，test_foo调用时，没有按照test_foo的原型传入f的地址，而是将f以值得形式传给了test_foo这个函数。就是这样的一个很低级的问题。当然了如果一个系统只有几行代码的话，这个问题可能会马上暴露出来；但是在一个拥有几十万行代码且稳定运行了若干年的系统中，没人会注意这个问题。&lt;br /&gt;&lt;br /&gt;有人马上会提出两个疑问：&lt;br /&gt;1) 为什么编译器没能给出参数类型不匹配的警告？&lt;br /&gt;2) 为什么系统能在这样明显的问题下稳定运行若干年而不出错呢？&lt;br /&gt;&lt;br /&gt;首先回答第一个问题：之所以编译器没能给出警告是因为项目遗留代码不规范的缘故，在调用test_foo这个角色函数的C文件中并没有引用test_foo原型声明所在的头文件，更不专业的是：test_foo这个函数根本没有在任何头文件中给予原型声明；这样一来，编译器在编译阶段无从知道test_foo到底是个什么样子的函数，也就无法给出正确的调用检查了。而在链接阶段根本不对参数进行有效检查，导致漏洞得以延续。&lt;br /&gt;&lt;br /&gt;第二个问题也是今天在发现这个问题后我最最疑惑的了。按理论上分析，如果按照上述例子中代码，f以值传递方式传入test_foo，test_foo会将f的头4个字节转换成一个Foo指针类型，这样在test_foo中引用pfoo时实际***问的地址应该是0x11(17d)，这个地址在应用程序进程地址空间属于系统地址空间，用户根本无法访问，一旦访问势必违法，如果在SUN SPARC平台上势必是要崩core的。但是实际情况是这样吗？我将上述程序放到SPARC Solaris9平台上用GCC 3.2版本编译器编译后，居然执行后一切OK。而这个源代码放到X86 Solaris 10上用GCC 3.4.6编译后(如果想编译成功，需要将test_foo的返回值改成int)运行就会出Core。初步得出结论：不同CPU体系对该种代码的处理有不同，需逐一分析。&lt;br /&gt;&lt;br /&gt;先来看看SPARC Solaris9，用GDB跟踪程序：&lt;br /&gt;Starting program: a.out &lt;br /&gt;&lt;br /&gt;Breakpoint 1, test_foo (pfoo=0xffbff0c0) at TestFoo.c:20&lt;br /&gt;20&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pfoo-&amp;gt;c = 29;&lt;br /&gt;(gdb) up&lt;br /&gt;#1&amp;nbsp; 0x0001069c in main () at TestFoo.c:15&lt;br /&gt;15&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; test_foo(f);&lt;br /&gt;(gdb) p &amp;amp;f&lt;br /&gt;$1 = (Foo *) 0xffbff0d0&lt;br /&gt;&lt;br /&gt;可以看到在main中，f的地址是0xffbff0d0，而传入test_foo后，pfoo指向的地址居然是0xffbff0c0了。一个推翻前面推理的猜想：编译器在栈上复制了一份f，得到了f'，并将f'的地址传给了test_foo。但是编译器为什么要这么做呢？似乎是当编译器发现传入函数的实际参数的值类型大于形式参数类型的时候，都要这么来做，这里我也没有什么特殊的根据，只是通过实验得出这个结论。比如：&lt;br /&gt;&lt;br /&gt;/* testvaluepass.c */&lt;br /&gt;typedef struct Foo {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c;&lt;br /&gt;} Foo;&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Foo&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; f;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; f.a&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = 17;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; func(f);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void func(int x) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x = 7;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* testvaluepass.s , &amp;lt;=gcc -S testvaluepass.c*/&lt;br /&gt;main:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; save&amp;nbsp;&amp;nbsp;&amp;nbsp; %sp, -144, %sp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 寄存器窗口切换（似乎是SPARC独有的机制），fp&amp;lt;- old_sp, new_sp &amp;lt;- old_sp - 144&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 17, %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-32]&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//%fp-32 &amp;lt;=&amp;gt; &amp;amp;f.a&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ldd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [%fp-32], %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; std&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-48]&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//从%fp-48开始，复制f得到f'，先copy一个dword，再来一个word，一共12个字节&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ld&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [%fp-24], %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-40]&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; add&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %fp, -48, %o0&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//将f'的地址存入%o0，在subroutine func中, %o0随着寄存器窗口的变动，新栈帧中%i0等于old栈帧中的%o0，也就是f'在栈上的首地址&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; func, 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, %i0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; restore&lt;br /&gt;&lt;br /&gt;func:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; save&amp;nbsp;&amp;nbsp;&amp;nbsp; %sp, -112, %sp&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %i0, [%fp+68]&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//将f'地址写入本地变量x中&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7, %i0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %i0, [%fp+68]&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//将7赋值给x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; restore&lt;br /&gt;&lt;br /&gt;有了这个例子之后，我们可以分析第一个例子了，同样也是在经过汇编之后：&lt;br /&gt;main:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; save&amp;nbsp;&amp;nbsp;&amp;nbsp; %sp, -144, %sp&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 17, %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-32]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 23, %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-28]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 19, %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-24]&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ldd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [%fp-32], %o0&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//这四行语句在重新复制一个f&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; std&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-48]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ld&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [%fp-24], %o0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, [%fp-40]&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; add&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %fp, -48, %o0 &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//将新f'的地址放到%o0中，而不是将[%fp-48]存入%o0，关键啊！&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; test_foo, 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %o0, %i0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; restore&lt;br /&gt;&lt;br /&gt;test_foo:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; save&amp;nbsp;&amp;nbsp;&amp;nbsp; %sp, -112, &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 寄存器窗口切换，fp&amp;lt;- old_sp, new_sp &amp;lt;- old_sp - 144，%o0-&amp;gt;%i0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; !#PROLOGUE# 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %i0, [%fp+68] &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//%i0存储的是f'的地址，是在save时由%o0得来的，存入[%fp+68]，即形式参数变量在栈上的地址。而恰好的是这个参数还是一个Foo*类型，这也是在SPARC上没出错的原因了。 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ld&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [%fp+68], %i1&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//%i此时存储的是f'的地址, 这个就是gdb跟踪时的0xffbff0c0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 29, %i0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; %i0, [%i1+8]&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//将29存入f'.c里面去了&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; restore&lt;br /&gt;&lt;br /&gt;这样一来，没有出core的原因也就找到了，但是编译器为何如此做，还无法得出确切结论。&lt;br /&gt;&lt;br /&gt;前面说过，在X86平台上，第一个例子程序是出core的，我们同样也来看看x86平台下的汇编码(与SPARC不同，esp一直在动)：&lt;br /&gt;.globl main&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .type&amp;nbsp;&amp;nbsp; main, @function&lt;br /&gt;main:&lt;br /&gt;.LFB2:&lt;br /&gt;.LM1:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pushl&amp;nbsp;&amp;nbsp; %ebp&lt;br /&gt;.LCFI0:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; %esp, %ebp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//ebp &amp;lt;- old sp&lt;br /&gt;.LCFI1:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; subl&amp;nbsp;&amp;nbsp;&amp;nbsp; $24, %esp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;.LCFI2:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; andl&amp;nbsp;&amp;nbsp;&amp;nbsp; $-16, %esp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; $0, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addl&amp;nbsp;&amp;nbsp;&amp;nbsp; $15, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addl&amp;nbsp;&amp;nbsp;&amp;nbsp; $15, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; shrl&amp;nbsp;&amp;nbsp;&amp;nbsp; $4, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sall&amp;nbsp;&amp;nbsp;&amp;nbsp; $4, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; subl&amp;nbsp;&amp;nbsp;&amp;nbsp; %eax, %esp&lt;br /&gt;.LM2:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; $17, -24(%ebp)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//f.a&amp;nbsp; init %ebp-24&lt;br /&gt;.LM3:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; $23, -20(%ebp)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//f.b&amp;nbsp; init %ebp-20&lt;br /&gt;.LM4:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; $19, -16(%ebp)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//f.c&amp;nbsp; init %ebp-16&lt;br /&gt;.LM5:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; subl&amp;nbsp;&amp;nbsp;&amp;nbsp; $4, %esp&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pushl&amp;nbsp;&amp;nbsp; -16(%ebp)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//push onto stack, as first parameter&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pushl&amp;nbsp;&amp;nbsp; -20(%ebp)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pushl&amp;nbsp;&amp;nbsp; -24(%ebp)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;.LCFI3:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; test_foo&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addl&amp;nbsp;&amp;nbsp;&amp;nbsp; $16, %esp&lt;br /&gt;.LM6:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; leave&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&lt;br /&gt;test_foo:&lt;br /&gt;.LFB3:&lt;br /&gt;.LM7:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pushl&amp;nbsp;&amp;nbsp; %ebp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//save old ebp&lt;br /&gt;.LCFI4:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; %esp, %ebp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//current ebp &amp;lt;- old esp&lt;br /&gt;.LCFI5:&lt;br /&gt;.LM8:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; 8(%ebp), %eax&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//eax &amp;lt;- ebp + 8 ，将ebp+8那块内存的值放到%eax，而这个值恰好是0x11(17d)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp; $29, 8(%eax)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;//访问0x11+8显然不合理，出core&lt;br /&gt;&lt;br /&gt;看来，不同平台的编译器生成代码差异还是不小的，但是在系统里发现的这个问题到底是否定性为Bug呢?也许这样的一个问题在早期的实现者头脑里早已经是已知的了，他可能就是故意这么做的。如果真的是这样的话，那还真不能算作一个bug，而是我们水平太浅，没能意识到这点。但可以肯定的是是这样编写代码绝对是一个不好的代码风格和习惯。另外发现代码中除了这一处之外还有多处相类似的调用，多是将变量值直接付给一个地址参数了。&lt;br /&gt;&lt;br /&gt;附:&amp;nbsp; &lt;a href=&quot;http://www.cs.clemson.edu/%7Emark/sparc_assembly.html&quot; target=&quot;_blank&quot;&gt;SPARC汇编笔记&lt;/a&gt;&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28467620.html&quot;&gt;无意中的Pair Programming&lt;/a&gt; 2008-09-02&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28234984.html&quot;&gt;尝试Scrum中的Demo模式&lt;/a&gt; 2008-08-27&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27940065.html&quot;&gt;CruiseControl.rb初体验&lt;/a&gt; 2008-08-20&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18879495.html&quot;&gt;C单元测试之Mock Test篇&lt;/a&gt; 2008-04-12&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18679464.html&quot;&gt;Mingle初体验&lt;/a&gt; 2008-04-09&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F28582799.html&amp;title=%E5%8F%91%E7%8E%B0%E4%B8%80%E9%9A%90%E8%97%8F%E5%A4%9A%E5%B9%B4%E7%9A%84Bug%EF%BC%9F&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Sat, 06 Sep 2008 00:11:05 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/28582799.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/28582799.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111480247/5013394</fs:itemid></item><item><title>小议架构师</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/28535954.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/28535954.html</id><description>&lt;p&gt;这周我在两个会议场合听到&amp;ldquo;架构师&amp;rdquo;这个词。对于软件开发领域的人来说，&amp;quot;架构师&amp;quot;这三个字并不陌生，甚至很崇高。每当提到架构师的时候，大家眼睛都会放出羡慕和期待的光芒，因为众所周知的原因：&amp;quot;架构师&amp;quot;对于搞技术的人来说，都是&amp;quot;大牛&amp;quot;的代名词。&lt;/p&gt;&lt;p&gt;就像不想当将军的士兵不是好士兵一样，不想当大牛的技术人员肯定也不是好的技术人员。&lt;/p&gt;&lt;p&gt;第一个谈到&amp;quot;架构师&amp;quot;的场合是在会议室和一位要好的同事讨论新项目的需求时，他感慨道：&amp;quot;当初我还以为架构师有多厉害，现在我们都是架构师了，也没有经过什么专业培训，带一两个项目，项目里架构不都是自己设计出来的吗，在客户那照样运行的很好&amp;quot;。&lt;/p&gt;&lt;p&gt;第二个说到&amp;quot;架构师&amp;quot;的场合是今天，也同样是在会议室，和几个同事一起做一个性能测试方案的评审时。部门即将投标的一个系统，该系统有一个硬性指标就是系统的消息处理能力要达到x万条。针对该标，一位资深的老同事，也是我们开发部的副部长说：如果能搞定这个x万条技术方案的人才算是真正的架构师，我们在座的目前还都是&amp;lsquo;伪架构师&amp;rsquo;。&lt;/p&gt;&lt;p&gt;说心里话，目前我自己还根本不够一个架构师的资格，自己的水平还浅的很。从上述两个场合来看，每个人对'架构师'这个角色的理解有不同。我曾经是这样理解一个架构师的：架构师一定要是一个技术大牛，既要专又要广，对计算机体系结构有着X光般透彻的理解；在某门语言方向上有着语言专家般的把握；对前沿技术有着鹰眼般敏锐的眼光，对操作系统、编译器、数据库、网络等都了如指掌，或者说无所不知；任何复杂的系统在他的大脑中都有精妙的技术解决方案。但现在看来，这种想法有些幼稚，也太理想化。&lt;/p&gt;&lt;p&gt;我开始质疑：技术大牛是否是&amp;ldquo;架构师&amp;rdquo;的充要条件呢？我们看看其他行业领域吧，比如说三峡工程、比如说神舟飞船系统工程、比如说阿联酋的迪拜塔等等。想像一下他们的架构师们是一些什么样的人呢？他们每天做的事情都有哪些呢？我想他们做的最多的应该不是技术。这里又回到了上面的问题，是否架构师一定就是技术大牛呢？我们看看拥有架构师头衔的名人：微软首席架构师-比尔.盖茨、网易首席架构师丁磊；没听说过比尔.盖茨亲手设计了Windows的内核，也没听说丁磊在网易的主流产品中亲自设计了什么什么架构；我们更多的是在媒体里看到他们对技术的理解，对未来产品方向的把握；当然了我们平时见到的架构师肯定没有这二位有名气，但是他们应该有些共同之处：他们集各种基础素质于一身，这些素质包括技术能力、沟通能力、管理技巧、业务分析能力、问题的分析和解决能力等。技术牛只是架构师的一个基本素质或者说基础条件之一，也就是说技术牛人不一定就能被称为架构师，而架构师可能在技术上有很高建树，但也不一定是如我最初理解的那种技术大牛。&lt;/p&gt;&lt;p&gt;除了上述那么多能力之外，其实架构师也是一般人，他们也许更擅长的是平衡的艺术，他们拥有更多的是沉淀后的经验，他们知道哪里是短板、哪里是硬伤、哪里是死穴，他们的魅力在于他们的智慧，他们给人的感觉是热情中却不乏稳重，这样的人才真正值得&amp;quot;架构师&amp;quot;这个称号。&lt;/p&gt;&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27753947.html&quot;&gt;CHECKLIST的不实用之处&lt;/a&gt; 2008-08-15&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27379836.html&quot;&gt;从座位调换看文化差异&lt;/a&gt; 2008-08-07&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/13942911.html&quot;&gt;再谈如何评价人的技巧&lt;/a&gt; 2008-01-15&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/13579704.html&quot;&gt;如何评价一个人&lt;/a&gt; 2008-01-09&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/13441383.html&quot;&gt;程序员与影视作品&lt;/a&gt; 2008-01-07&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F28535954.html&amp;title=%E5%B0%8F%E8%AE%AE%E6%9E%B6%E6%9E%84%E5%B8%88&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Thu, 04 Sep 2008 19:23:26 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/28535954.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/28535954.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007197/5013394</fs:itemid></item><item><title>无意中的Pair Programming</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/28467620.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/28467620.html</id><description>Pair Programming, 结对编程是敏捷开发中一个重要的实践，并受到很多业界大师级人物的推崇。但是明知它对我们可能会很有帮助，但是如果推广、实践起来还是要突破各种束缚的，心理上的、流程规范上的等等。我想也许这也或多或少也和公司或者部门的开发文化有些关系。我很想去尝试，但是一直没有找到一个很好的机会，也没有找到&amp;quot;心仪&amp;quot;的Partner。&lt;br /&gt;&lt;br /&gt;今天上午恰好要完成一个脚本的编写，这是一个升级产品时使用的自动升级脚本，基础接口在上个月组内的一个同事已经完成了，并经过了大家的评审，认为可行。今天我就是要利用他的这个基础shell函数库来完成我的自动升级脚本的整理。&lt;br /&gt;&lt;br /&gt;时间久了，那点关于这个脚本的模糊记忆早已经不存在了，很多细节我需要向我的那位同事请教。本打算找间会议室，坐在一起讨论的，后来发现会议室也被人占领了。上午的计划就是完成这个脚本，计划既然定下来了，就得执行，提高执行力一直是我这阶段的目标之一。就这样，我把这位同事叫到跟前，我们找了一块还算空旷和僻静的办公区坐了下来。我把我的想法向他做了陈述，告诉他我们一起完成这个脚本的初稿。我来掌控笔记本。按照以前我们升级的步骤，我们一步一步来实现脚本的功能，中间有自己不能确认的问题，就将键盘交予他来确认；他的基础脚本当初没有经过详尽的系统测试，也是碰巧，我们在一起写代码的时候居然又发现了原有代码中两个不妥的地方。&lt;br /&gt;&lt;br /&gt;Pair的确是会调动人的热情和积极性的。但前提是有一个良好的、适合二人的工作空间；我自己觉得转角的办公桌是不太适合Pair的，两个人坐在转角旁，估计一会就累了-手脚无法伸展。掌控键盘的一方要多与另一方沟通，保持另一方的精神一直集中在你们的工作上，人和人在一起还是很容易溜号儿的。&lt;br /&gt;&lt;br /&gt;经过半个多小时的编写，初稿搞定；回想一下，如果我选择的是自己闷头写脚本，然后再让那位同事评审，势必牵扯出不少额外工作量的；而结对的这种方法的确帮我解决了这样的一个问题。&lt;br /&gt;&lt;br /&gt;事后反思，觉得的确应该把这一活动看成是一种Pair Programming。虽然现在我对Pair的认识和实践还处于肤浅之状态，但我想万事万物都无定式，最适合的才是最好的，摸索出适合我们组开发的PP模式才是最重要的，还需要实践、积累以及让更多的人参与其中。&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28582799.html&quot;&gt;发现一隐藏多年的Bug？&lt;/a&gt; 2008-09-06&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28234984.html&quot;&gt;尝试Scrum中的Demo模式&lt;/a&gt; 2008-08-27&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27940065.html&quot;&gt;CruiseControl.rb初体验&lt;/a&gt; 2008-08-20&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18879495.html&quot;&gt;C单元测试之Mock Test篇&lt;/a&gt; 2008-04-12&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18679464.html&quot;&gt;Mingle初体验&lt;/a&gt; 2008-04-09&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F28467620.html&amp;title=%E6%97%A0%E6%84%8F%E4%B8%AD%E7%9A%84Pair+Programming&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Tue, 02 Sep 2008 23:36:59 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/28467620.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/28467620.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007198/5013394</fs:itemid></item><item><title>装修的遗憾，其实不美</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/28329786.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/28329786.html</id><description>从4月初到8月中旬，装修(+家具、电器采购)整整持续了四个多月，由于亲戚朋友都不在身边，装修的劳顿使我在这段时间内体重急剧减少了近10斤，体力的不堪重负和心理的烦躁促成了这一&amp;quot;减肥&amp;quot;过程。都说装修是门遗憾的艺术，凡是亲历过装修的人想必都有所感悟吧。有人说：遗憾是一种美，但我的感觉是装修中的遗憾，其实不美。&lt;br /&gt;&lt;br /&gt;我的装修遗憾列表(按装修流程的先后顺序):&lt;br /&gt;&lt;br /&gt;设计阶段&lt;br /&gt;- 年初找装修公司时恰逢人力成本和各种材料涨价，因此多付了数千元的装修费用；&lt;br /&gt;- 设计师水平平庸，整体设计没有亮点，很多地方还是我们提供给设计师的思路；让我感觉设计师似乎可有可无；&lt;br /&gt;&lt;br /&gt;施工阶段&lt;br /&gt;- 由于无人监督，以致墙体大白铲除不干净，特别是门框内测部位，给木门安装带来隐患；&lt;br /&gt;- 原有插座、开关没有嘱咐工人做保护，在电改造时付出很多浪费；&lt;br /&gt;- 没有考虑到数字电视机顶盒的影响，导致卧室内有线口位置留得不当；&lt;br /&gt;- 卫生间没有坚持留出拖布池的下水，抹布的洗涮很是不便；&lt;br /&gt;- 电工在埋设墙体电视线管时将客厅和卧室间的墙体打穿，留下隐患；&lt;br /&gt;- 阳台洗衣机龙头留的过于低矮了，不美观；&lt;br /&gt;- 多留了一个小区纯净水的水口，结果发现小区纯净水是单循环的，水质很差根本不能用；&lt;br /&gt;- 橱柜后面预留的两个插座太靠边，最右侧的一个伸手根本无法够到，派不上用场；&lt;br /&gt;- 厅里沙发背后的插座位置有些偏中间，导致沙发长度只能买3米以内的；&lt;br /&gt;- 厅里留了两个电话口，中间那个根本无用，还多花了一个电话口的价钱；&lt;br /&gt;- 厨房墙砖挑选来挑选去，居然买了铺装后效果最不好的一款，价钱还很贵；&lt;br /&gt;- 厨房墙砖面积计算不准确，导致二次补货时，价钱提升，且工期导致延迟；&lt;br /&gt;- 瓦工工人技艺一般，客厅地砖某些起伏很大；卫生间墙砖有些水泥填充不足，有空鼓；&lt;br /&gt;- 两卧室用水泥找平后，仍不平，二次用石膏找平仍有坑洼，导致后期地板踩上去后某些位置能感觉明显的下陷感；&lt;br /&gt;- 厨房烟道部位瓷砖有15cm长裂纹，无法判断是砖质量问题，还是瓦工的技艺问题；&lt;br /&gt;- 橱柜后隐蔽的瓷砖买多了，无法退货，浪费了；&lt;br /&gt;- 客厅地砖用了白色勾缝剂，弄脏后，样子很是难看；&lt;br /&gt;- 沙发背景墙造型木盒当初不做就好了，商场里的又漂亮，价钱也相差不多；&lt;br /&gt;- 木工在安装沙发背景墙造型木盒时，将隔壁邻居家的卧室墙面钉出裂纹；&lt;br /&gt;- 沙发背景墙造型木盒初次安装时位置太低，经拆卸后重新安装，留下隐患；&lt;br /&gt;- 南阳台的平棚不该做的太大，导致后期纱帘和布帘太拥挤，拉动时很不顺滑；&lt;br /&gt;- 厨房吊顶颜色太深，导致厨房感觉偏暗；&lt;br /&gt;- 厨房与餐厅之间的假梁做的太窄，拉门安装后，顶部宽出2个mm；&lt;br /&gt;- 沙发背景墙造型木盒刷成全白就好了，后期的红色似乎效果没有我想象中的好；&lt;br /&gt;- 沙发背景墙造型木盒顶部的油漆刷的很烂，手摸上去有凸凹不平的感觉；&lt;br /&gt;- 烟道内烟机的排风管忘记打发泡胶挤压住就被橱柜挡板封死了；&lt;br /&gt;- 橱柜的白色顶部挡板很是难看，与橱柜整体似乎很不配套；&lt;br /&gt;- 橱柜安装时一上柜挂钩没有挂住墙体的膨胀螺丝，二次返工后留下隐患；&lt;br /&gt;- 水槽安装时下水管用密封胶圈封住了下水管，厨宝安装时安装师傅为了做过压排水，将密封圈打开，这样密封圈失去了原有的作用；&lt;br /&gt;- 地板和脚线在离家很远的居然之家购买的，由于买多了，退货很不方便；&lt;br /&gt;- 木门安装后，发现门框与墙体有很大距离，不知是否为安装工人的问题，总之很难看；&lt;br /&gt;- 橱柜送货时，弄碎了一块玻璃门，二次送货，耽误了我不少时间；&lt;br /&gt;- 餐厅的灯安完之后发现，居然有些倾斜，无法调整了；&lt;br /&gt;- 主卧壁纸压边贴，导致花纹对不上，效果很差；&lt;br /&gt;- 客厅壁纸，时间长了之后，发现白色部分有些发黄；&lt;br /&gt;- 客厅壁纸边缘部分未粘牢，导致二次返工；&lt;br /&gt;- 客厅窗帘软滑道不是很顺滑，当初买铝合金的就好了；&lt;br /&gt;- 浴室柜厂家送货出错，手盆无法安装，浴室柜门样式不对，重新拆卸安装，费时费力，且不如原装的好，留下隐患；&lt;br /&gt;- 主卧室大床安装时，工人不小心将卧室窗台撞坏，后期才发现；&lt;br /&gt;- 主卧室窗帘花纹样式与壁纸雷同，导致效果有些凌乱；&lt;br /&gt;&lt;br /&gt;电器采购&lt;br /&gt;- 液晶电视购买仓促，奥运期间断货，不得不高价从中兴购买，多花了几百块；&lt;br /&gt;&lt;br /&gt;装修后留下的遗憾，带来的是心理上的不平衡和生活上的很多不便，但也许这就是生活。&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27756475.html&quot;&gt;无线路由设置也'疯狂'-续&lt;/a&gt; 2008-08-15&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/25437849.html&quot;&gt;“撒哈拉大森林”&lt;/a&gt; 2008-07-24&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20783112.html&quot;&gt;一分之差&lt;/a&gt; 2008-05-12&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/17141466.html&quot;&gt;装修博弈·主材选购&lt;/a&gt; 2008-03-17&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/16597416.html&quot;&gt;无线路由设置也'疯狂'&lt;/a&gt; 2008-03-08&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F28329786.html&amp;title=%E8%A3%85%E4%BF%AE%E7%9A%84%E9%81%97%E6%86%BE%EF%BC%8C%E5%85%B6%E5%AE%9E%E4%B8%8D%E7%BE%8E&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Sat, 30 Aug 2008 10:39:36 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/28329786.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/28329786.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007199/5013394</fs:itemid></item><item><title>尝试Scrum中的Demo模式</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/28234984.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/28234984.html</id><description>昨天，在下班前的一分钟，突然有一个想法：项目刚刚完成一个阶段性的任务，是否将项目组所有人召集在一起，每个人将自己在这个阶段做的东西向大家做一个展示呢？把这个想法和几个同事交换了一下意见，获得了支持。说做就做，恰好这段时间我一直尝试不断提高自己的执行力。遂在上午的一个短会上和大家道出了我的想法，并决定在今天就做这个演示活动。&lt;br /&gt;&lt;br /&gt;这种想法其实不是什么独创，最近拜读了一本叫&amp;quot;硝烟中的Scrum和XP&amp;quot;的书，书中关于Agile Srcum实践的做法很是吸引我。骨子里的我是不想做让自己感到别扭的事情的，也不愿重复以前已经做过的事情，不断的改进、每天的充实和提高才是我的目标。既然书中有让我认同的最佳实践，为什么我不去尝试一下呢？持续集成、看板(KanBan)管理以及这个Demo模式是我最近一直努力的几个方向，没想到的是今天Demo尝试意外的给了我第一个尝试改进工作的成就感。&lt;br /&gt;&lt;br /&gt;做一件事情容易，但是将你所做的事情展示或讲解给其他人则是不是件容易的事情。项目组在宣布今天做演示活动之后，每个人似乎都有一些态度上的转变，似乎有那么一丝丝紧张。大家重新回顾了这一阶段实现的需求列表，对比需求，努力想着自己所做的东西是否满足需求，哪些不能确定的地方，赶紧向达人请教，一种责任感似乎平地冒出，在大家身上都有不同的展现。&lt;br /&gt;&lt;br /&gt;按照我的要求：每个人在演示自己所做的任务之前，需要给大家简单的介绍一下演示点所对应的需求是什么？让大家大致知道你做的东西是个什么样子，这样每个人不能紧紧只了解自己实现的那一块，而是要将业务流程理解的透彻些，特别是对实现管理系统的同事。我很遗憾和愧疚平时没有给大家很多机会去在众人面前说话的机会，大家莫名的都有那么一丝紧张。其实从另一方面来看，这种Demo实践实际上也是给了这些人一个说话的机会，相信每个人说过之后，他们都会感觉很好。&lt;br /&gt;&lt;br /&gt;按照Scrum的做法，演示放到项目的最后一个时间段，需注意的是演示不是评审，不是让大家找bug和不足。演示是为了让你的工作为大家所知，得到同事的认可和赞同，获得反馈，取得成就感的。今天的项目组的第一次演示在我的控制下好歹没有转变成评审会，我两次和大家重申要求：希望以后我们的阶段性Demo没有bug出现，Demo是我们阶段性任务的最后环节，所有我们能力范围之内可以找出的bug都需要在前期的工作中予以解决，否则你的成果物是不能被accepted的。&lt;br /&gt;&lt;br /&gt;每个同事演示结束后，我都会建议所有组员以掌声予以鼓励，我们的掌声是发自内心的，让演示的同事感觉到他/她的工作得到了认可，心血和汗水没有白费。由于会上得到了很好的效果，我们决定将这种实践作为项目过程的常态持续下去，以后所有组员在接到任务的时候都要以终为始，时刻想着项目阶段末期的演示活动，认真对待自己的任务。相信大家心里也都憋着一股劲－－在下次演示的时候能做得更好，这恰好是我想要的。&lt;br /&gt;&lt;br /&gt;演示中可能不可避免的发现bug，不要过多纠缠于这些bugs，先记下，会后讨论解决，以让我们的演示会能持续良好的进行下去。&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28582799.html&quot;&gt;发现一隐藏多年的Bug？&lt;/a&gt; 2008-09-06&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28467620.html&quot;&gt;无意中的Pair Programming&lt;/a&gt; 2008-09-02&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27940065.html&quot;&gt;CruiseControl.rb初体验&lt;/a&gt; 2008-08-20&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18879495.html&quot;&gt;C单元测试之Mock Test篇&lt;/a&gt; 2008-04-12&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18679464.html&quot;&gt;Mingle初体验&lt;/a&gt; 2008-04-09&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F28234984.html&amp;title=%E5%B0%9D%E8%AF%95Scrum%E4%B8%AD%E7%9A%84Demo%E6%A8%A1%E5%BC%8F&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Wed, 27 Aug 2008 23:17:19 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/28234984.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/28234984.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007200/5013394</fs:itemid></item><item><title>北京奥运会完美谢幕</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/28103228.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/28103228.html</id><description>燃烧在鸟巢上空16天的第29届北京奥林匹克运动会的圣火终于在今天完成了使命，在万众瞩目下熄灭了。作为一个普通的中国观众，我从电视等媒体中见证了北京奥运会的这16天的历程，客观的说：她很完美。&lt;br /&gt;&lt;br /&gt;闭幕式上，国际奥委会主席罗格给予了北京奥运会一个与众不同的评价：真正的无与伦比。的确如此，北京奥运会从&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27442230.html&quot; target=&quot;_blank&quot;&gt;开幕式&lt;/a&gt;那天起就让大家眼前一亮，让国外一些媒体对北京的质疑彻底不攻自破。&lt;br /&gt;&lt;br /&gt;北京奥运会是一个拥有13亿人口的发展中国家倾全国之力举办的，其组织、协调、建设等准备工作持续了很多年，就拿礼炮手来说，一个简单的弹壳退膛动作居然连续练习了一年多，可见在中国上自领导人，下自普通老百姓都为十分重视此届盛会，很多人为此没日没夜的工作着、有些人在奥运准备工作中受伤、有些人甚至献出了自己的宝贵生命；让我们高兴的是这16个日日夜夜，奥运会一切顺利进行，我们国家兑现了我们的承诺，展现了一个大国的风范，我们的运动员和观众无不展现出新的风貌。&lt;br /&gt;&lt;br /&gt;中国在为世界作出贡献的同时，自己也收获了很多。不可否认的是奥运会是将中国展现给世界的最美好的舞台；中国代表团在这届奥运会中以51枚金牌，100枚奖牌的优异成绩，成功超越了老对手美国队，称霸了金牌榜。就连美国的纽约时报也撰文告诉美国人和欧洲人，奥运只是个起点，现在中国在体育上超越了欧美国家，将来中国在文化、教育、科技、经济都会逐渐超越，西方人要在未来习惯中国人的超越。&lt;br /&gt;&lt;br /&gt;中国给世界各国运动员创造了良好的赛场环境，世界各国的运动员也表现出了良好的竞技状态和职业操守。菲尔普斯的八金、博尔特的自我超越、埃蒙斯面对悲情的镇定坦然与大度、杨威、马琳的终成正果、丘索维津娜博大母爱的力量等等，让我们看到了一届精彩无比的奥运。更高、更快、更强在本届奥运会表现的更加淋漓尽致。&lt;br /&gt;&lt;br /&gt;北京奥运会给我们留下了美好的回忆，对于中国，对于中国人，北京奥运会的确是一个新的起点。突然想起欣赏开幕式时，同事发来的那条短信，用这条短信的内容作为本篇的结束语吧：为中华崛起干杯！&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27442230.html&quot;&gt;此刻，让我们共同见证第29届北京奥运会&lt;/a&gt; 2008-08-08&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/24734229.html&quot;&gt;城市窒息&lt;/a&gt; 2008-07-14&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20896176.html&quot;&gt;关注四川汶川地震，为灾区人民祈祷&lt;/a&gt; 2008-05-14&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20067024.html&quot;&gt;由一把座椅想到的&lt;/a&gt; 2008-04-30&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/15349020.html&quot;&gt;这注定是个难忘的春节&lt;/a&gt; 2008-02-14&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F28103228.html&amp;title=%E5%8C%97%E4%BA%AC%E5%A5%A5%E8%BF%90%E4%BC%9A%E5%AE%8C%E7%BE%8E%E8%B0%A2%E5%B9%95&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Sun, 24 Aug 2008 22:45:31 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/28103228.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/28103228.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007201/5013394</fs:itemid></item><item><title>CruiseControl.rb初体验</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/27940065.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/27940065.html</id><description>&lt;p&gt;我所在的项目一直以C语言作为主要开发语言，与做Java以及其他新兴语言的人不同，组内的同事似乎对新鲜的东西不是那么感兴趣，也没有主动去研究新鲜事物的意愿和意识。我深为此闹心，看到外面世界中那么多美妙的工具，再也不能坐以待毙了。我一直都是有很多想法的，但是迫于自身精力有限，自己无法全身投入，以前都是交予别人去做的，但是收到的效果都不是很好。认识到这点后，我决定自己动手，丰衣足食。&lt;/p&gt;&lt;p&gt;从心底一直对公司的CMMI流程有所抵触，眼看着外面世界中的Agile Development等轻量级开发过程日益壮大，但自己每天还不得不按照各种繁复的流程去做，真有一种&amp;quot;身在曹营心在汉&amp;quot;的感觉。但是在一个CMMI流程&amp;quot;森严&amp;quot;的公司，又如何才能让大家接受Agile的思想呢？我想让大家看到新实践的与以往不同的成效，大家自然也就能够接受了。在&lt;a href=&quot;http://www.infoq.com.cn&quot; target=&quot;_blank&quot;&gt;Infoq&lt;/a&gt;上，有人也给出了建议：&amp;ldquo;切莫开口提大名词(例如SCRUM或者XP)。建议以CMMI x级的&amp;quot;自我改进&amp;quot;做旗帜，找到组织中存在浪费的环节，引入最佳实践来消除浪费，没有必要把敏捷挂在嘴边 &amp;rdquo;。而持续集成也是文章中建议的首选实践，与我的想法不谋而合。&lt;/p&gt;&lt;p&gt;持续集成，以前不是没有做过，在部门的一个项目组中曾经尝试过，自己编写脚本，完成定时更新代码、构建的任务，后因项目紧张，似乎没有收到良好效果。我也曾经在项目组内推进过做Java的同事进行持续集成的实践，并安排一个同事搭建了CruiseControl的服务器，但后来似乎不了了之，也怪我没有在后期给予充分的重视和压力。有过这些教训后，我时常也在想？推进一个持续集成的实践就这么难么？这回我亲自来做，从C开发人员入手。&lt;/p&gt;&lt;p&gt;持续集成是需要良好的工具支持的，业内最知名的持续集成工具莫过于&lt;a href=&quot;http://cruisecontrol.sourceforge.net/index.html&quot; target=&quot;_blank&quot;&gt;CruiseControl&lt;/a&gt;了，CruiseControl在Java开发领域占据着No.1的地位，而且其设计思想也影响着后续的持续集成工具的开发。但是一想到Java，我第一感觉就是复杂，CruiseControl会不会也像配置一个Web服务器一样那样复杂呢？另外CruiseControl使用Maven + Ant + cvs/subversion的组合，我曾经研究过Ant, Maven，大量的xml配置让我感到很头疼，另外是否与C/C++良好配合也是疑问。这样一来，我就没有继续走CruiseControl这条路，我尝试寻找一种配置简单能快速上手，核心功能也不逊于CruiseControl的工具，Thoughtworks的&lt;a href=&quot;http://cruisecontrolrb.thoughtworks.com/&quot; target=&quot;_blank&quot;&gt;CruiseControl.rb&lt;/a&gt;走入我的视野。&lt;/p&gt;&lt;p&gt;一直关注Thoughtworks，因为以前部门的&lt;a href=&quot;http://dreadhead.blogbus.com&quot; target=&quot;_blank&quot;&gt;两位大牛&lt;/a&gt;级别的同事都在那任职，另外Thoughtworks推出的产品也的确让我很感兴趣，以前就曾研究过&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18679464.html&quot; target=&quot;_blank&quot;&gt;Mingle&lt;/a&gt;，只不过Mingle是收费的，而且目前性能还有待提高。CruiseControl.rb(以下称为CC.rb)是Thoughtworks的一款开源作品，其主页上的一小段话很是对我的胃口：&amp;quot;continuous integration isn't rocket science. we keep it simple.&amp;quot;。简单，正是我所期望的。&lt;/p&gt;&lt;p&gt;目前CC.rb的最新版本是&lt;a href=&quot;http://rubyforge.org/frs/download.php/36026/cruisecontrolrb-1.3.0.tgz&quot; target=&quot;_blank&quot;&gt;1.3.0&lt;/a&gt;，下载后就是一个压缩包：cruisecontrolrb-1.3.0.tgz。解压后，在你的当前目录下会出现一个cruisecontrolrb-1.3.0的目录。CC.rb的依赖非常之少，你只需要在你的集成服务器上安装上ruby和svn客户端即可，注意:ruby和svn的可执行程序的路径需要添加到你的环境变量的PATH中，否则CC.rb将无法找到ruby和svn。目前CC.rb只是支持Svn，其他版本管理工具尚未得到支持，毕竟CC.rb还年轻，开发时间较少，情有可原。&lt;/p&gt;&lt;p&gt;现在CC.rb已经安装完毕了，没错！CC.rb是用ruby实现的，ruby是脚本类语言，无需编译。你现在就可以进入cruisecontrolrb-1.3.0目录下，执行&amp;quot;cruise --version&amp;quot;(在Unix主机上，你需要先将cruise文件chmod一次，否则cruise将无可执行权限)，你会看到：&lt;br /&gt;CruiseControl.rb, version 1.3.0&lt;br /&gt;Copyright (C) 2007 ThoughtWorks&lt;/p&gt;&lt;p&gt;现在你可以添加和配置你的project了。这里要先说一下，CC.rb默认将用户的project数据放在$(HOME)/.cruise/下面，如果你是在Windows平台上，project数据会被默认放在C:\Documents and Settings\USER_NAME\.cruise下面。添加一个proj很简单，你只要提供足够的信息即可：进入到cruisecontrolrb-1.3.0目录下，执行命令：&lt;br /&gt;cruise add PROJ_NAME --url SVN_URL --username USER_NAME --password PASS_WORD，如果你的svn库有权限管理，你需要提供user和passwd。举例: cruise add test_proj --url svn://192.168.0.2:3999/trunk/test_proj --username tony --password tony&lt;/p&gt;&lt;p&gt;这样你就在$(HOME)/.cruise/projects的下面建立了一个test_proj的工程，如果你提供的信息是正确的，CC.rb会在初始建立工程的时候，将你的svn库中的代码checkout出来一份最新的，放在$(HOME)/.cruise/projects/test_proj/work下面。&lt;/p&gt;&lt;p&gt;完成上一步后，$(HOME)/.cruise目录下面有几个配置文件是我们需要重点关注的：&lt;br /&gt;$(HOME)/.cruise&lt;br /&gt;&amp;nbsp;- config/site_config.rb&lt;br /&gt;&amp;nbsp;- projects/test_proj/cruise_config.rb&lt;/p&gt;&lt;p&gt;$(HOME)/.cruise/config下的site_config.rb文件是一个全局性的配置文件，无论你在一份CC.rb下建立几个proj，这些proj都会共享该配置，该配置每次修改后都需要重启CC.rb才能生效；该文件中有两个最主要的配置：&lt;br /&gt;1) 邮件服务器配置&lt;br /&gt;如果你想将每次build的结果通过mail的形式发送给相关干系人的话，你就需要配置你的mail server相关信息。&lt;br /&gt;ActionMailer::Base.smtp_settings = {&lt;br /&gt;&amp;nbsp;&amp;nbsp; :address =&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;xx.xx.xx.xx&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp; :port =&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 25,&amp;nbsp;&amp;nbsp; #一般服务器默认smtp端口都是25&lt;br /&gt;&amp;nbsp;&amp;nbsp; :domain =&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;YOUR_DOMAIN.com&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp; :authentication =&amp;gt; :plain,&lt;br /&gt;&amp;nbsp;&amp;nbsp; :user_name =&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;YOUR_USER_NAME&amp;quot;,&lt;br /&gt;&amp;nbsp;&amp;nbsp; :password =&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;quot;YOUR_PASSWD&amp;quot;&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;2) Dashboard URL&lt;br /&gt;Configuration.dashboard_url = 'http://ip : port'； Dashboard URL将被加入到发给干系人的mail中，这样相关干系人收到mail后可以直接点击该url登录到CC.rb的Dashboard查看相关内容。CC.rb的配置文件也同样适用ruby语言编写的，ruby语言语法较为简单，相信大家都看得懂。&lt;/p&gt;&lt;p&gt;$(HOME)/.cruise/projects/test_proj下的cruise_config.rb文件则是一个Project-specific的local配置文件，它是动态更新的，你的更新在下一次build时是即时生效的。该配置文件中的内容都很重要和实用：&lt;br /&gt;1) project.email_notifier.emails = ['email1@your.site'] 该配置用于添加干系人邮件，这样每次build后，CC.rb都会读取该配置，发送mail给该email list的人；&lt;br /&gt;2) project.email_notifier.from = &lt;a href=&quot;mailto:'email2@your.site'&quot;&gt;'email2@your.site'&lt;/a&gt;，该配置将指定notify mail中的发件人，你可以因项目的不同而配置不同的mail。&lt;br /&gt;3)&amp;nbsp; project.rake_task = 'custom'，似乎该配置只有当你使用rake这个工具时才需要配置，如果你使用诸如ant,make等工具的话，该配置还需保留原先的被注释状态；&lt;br /&gt;4) project.build_command = 'build_my_app.sh'，该配置给予你自定义build脚本的机会，也正是这样，你才可以将CC.rb与Ant, Make等工具集成在一起使用。如：project.build_command = 'make'。注意CC.rb执行build_command的working dir是$(HOME)/.cruise/projects/test_proj/work下面，如果你的build_my_app.sh没有放在work下面，而是在$(HOME)/.cruise/projects/test_proj下面的话，你这块就要配置成：project.build_command = '../build_my_app.sh'; project.build_command与 project.rake_task不能一起使用。&lt;br /&gt;5) project.scheduler.polling_interval = 5.minutes ，CC.rb定期去检测svn是否有new revision，这个配置就是用来指定检测周期的，如果你不配置，那默认是30s。&lt;/p&gt;&lt;p&gt;如果你以上都配置完毕了，你现在就可以启动CC.rb了。启动方法：进入到cruisecontrolrb-1.3.0目录下，执行&amp;quot;cruise start -p port&amp;quot;。CC.rb会启动自带一个轻量级web server - WEBrick ，对于我这个对web server不熟悉的人还是很方便的，我只需要告诉CC.rb端口即可。CC.rb启动后，你可以在浏览器输入&lt;a href=&quot;http://ip:port&quot;&gt;http://ip:port&lt;/a&gt;，CC.rb的简洁的页面就会显示出来，你会在页面上看到你刚才建立的工程test_proj，点击右上方的&amp;quot;build now&amp;quot;按钮，你就开始了一次build的过程。无论成功还是失败，你都应该收到一封mail，关于此次build的详情可以点击mail中的链接。如果失败了，你可以在页面上的&amp;quot;build log&amp;quot;中看到此次build的详细日志，以帮助你分析失败原因。&lt;/p&gt;&lt;p&gt;CC.rb是如何判断build过程成功还是失败了呢？我们以project.build_command = 'xx'的配置为例，其实CC.rb是通过判断xx这个builder的返回值来决定build过程是否成功的。当xx这个builder返回0，说明build成功；否则build失败；我们不妨测试一下：在$(HOME)/.cruise/projects/test_proj/work下面写一个小程序：&lt;br /&gt;/* test.c */&lt;br /&gt;int main() {&lt;br /&gt;&amp;nbsp;exit(0);&lt;br /&gt;}&lt;br /&gt;gcc -o test test.c&lt;/p&gt;&lt;p&gt;配置project.build_command = 'test'，点击&amp;quot;build now&amp;quot;，收到mail，提示build success；如果你将exit(0)改成exit(1)，那么一封failed的mail就会发到你的邮箱里。&lt;/p&gt;&lt;p&gt;C/C++没有很好的单元测试工具，一般&lt;a href=&quot;http://bigwhite.blogbus.com/logs/1574745.html&quot; target=&quot;_blank&quot;&gt;C/C++单元测试工具&lt;/a&gt;都会将单元测试用例编译链接成为一个可执行文件，然后执行，以判断是否通过。到这里你是否想到了如何将C/C++的单元测试与CC.rb集成到一起的方法呢？对，我们通过脚本也好，或者干脆自己编写一个单元测试框架，通过程序返回值告知CC.rb新提交的代码是否通过了单元测试的考验。&lt;/p&gt;&lt;p&gt;以上是第一次使用体验CC.rb时记录下的内容，其实CC.rb就是这么简单！&lt;/p&gt;&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28582799.html&quot;&gt;发现一隐藏多年的Bug？&lt;/a&gt; 2008-09-06&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28467620.html&quot;&gt;无意中的Pair Programming&lt;/a&gt; 2008-09-02&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28234984.html&quot;&gt;尝试Scrum中的Demo模式&lt;/a&gt; 2008-08-27&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18879495.html&quot;&gt;C单元测试之Mock Test篇&lt;/a&gt; 2008-04-12&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/18679464.html&quot;&gt;Mingle初体验&lt;/a&gt; 2008-04-09&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F27940065.html&amp;title=CruiseControl.rb%E5%88%9D%E4%BD%93%E9%AA%8C&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Wed, 20 Aug 2008 18:43:06 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/27940065.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/27940065.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007202/5013394</fs:itemid></item><item><title>switch语句性能考量</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/27859703.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/27859703.html</id><description>每年都有应届毕业生来到公司，每年都要对新同事进行代码方面的培训，比如编码规范就是其中之一。编码规范初听起来比较新鲜，但是培训时间长了，显然有些乏味。今年我打算改变策略，让新同事结合已有规范文档和项目代码，自己先挖掘一遍，然后大家通过坐下来讨论的互动方式来加深对规范的理解，每次讨论时间限制在1 hour以内，不给大家打瞌睡的机会^_^。&lt;br /&gt;&lt;br /&gt;上周和新同事一起讨论表达式和语句，说到了switch和if，谈到了他们的用途和区别。大家都清楚switch语句被称为多分支语句，当代码中即将出现3个及3个以上分支时，推荐用switch，这样代码可读性好，清晰，格式工整；但是同样switch也是有局限的，就是switch(xx)中的xx必须是整型变量；如果你的条件判断是字符串比较，就无法直接使用switch了。switch的这一局限实际上是有原因的，为什么呢？在于其性能优化。那switch语句在底层到底是如何实现的呢？和if语句相比，switch除了美观之外，优势又在哪里呢？我们唯有到汇编层去看个究竟了。&lt;br /&gt;&lt;br /&gt;我们先来看看if多分支的情况：//Windows XP + gcc v3.4.2 (mingw-special)&lt;br /&gt;//testif.c&lt;br /&gt;int test_if_performance(int i) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;int rv = i;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (rv == 10) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;rv += 100;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;} else if (rv == 11) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;rv += 101;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;} else if (rv == 12) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;rv += 102;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;} else if (rv == 13||rv == 14 || rv == 15) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;rv += 105;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;} else {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;rv += 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return rv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;我们通过-S选项得到test_if_performance的汇编代码，我们加上了-O2的优化选项：&lt;br /&gt;//gcc -S O2 testif.c&lt;br /&gt;//testif.s&lt;br /&gt;... ...&lt;br /&gt;_test_if_performance:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;pushl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%esp, %ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;8(%ebp), %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;cmpl&amp;nbsp;&amp;nbsp; &amp;nbsp;$10, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;je&amp;nbsp;&amp;nbsp; &amp;nbsp;L11&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;cmpl&amp;nbsp;&amp;nbsp; &amp;nbsp;$11, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;je&amp;nbsp;&amp;nbsp; &amp;nbsp;L12&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;cmpl&amp;nbsp;&amp;nbsp; &amp;nbsp;$12, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;je&amp;nbsp;&amp;nbsp; &amp;nbsp;L13&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;-13(%edx), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;cmpl&amp;nbsp;&amp;nbsp; &amp;nbsp;$2, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ja&amp;nbsp;&amp;nbsp; &amp;nbsp;L3&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;addl&amp;nbsp;&amp;nbsp; &amp;nbsp;$105, %edx&lt;br /&gt;L3:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%edx, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L11:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;$110, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%edx, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L12:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;$112, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%edx, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L13:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;$114, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%edx, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&lt;br /&gt;从这段汇编码来看，if语句是逐个判断下来的，如果i = 19的话，程序需要从头判断到尾，&amp;quot;一个都不能少&amp;quot;^_^。那么拥有同样语义功能的switch代码又是如何实现的呢？我们继续看下去。&lt;br /&gt;// testswitch.c 这个文件实现的是和上述testif.c同样的功能&lt;br /&gt;int test_switch_performance(int i) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int rv = i;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; switch(rv) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 10:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv += 100;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 11:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv += 101;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 12:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv += 102;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 13:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 14:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 15:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv += 105;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; default:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv += 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return rv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;我们同样用-O2来得到switch的汇编代码：&lt;br /&gt;//gcc -S O2 testswitch.c&lt;br /&gt;//testswitch.s&lt;br /&gt;... ...&lt;br /&gt;_test_switch_performance:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;pushl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%esp, %ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;8(%ebp), %ecx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;-10(%ecx), %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ecx, %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;cmpl&amp;nbsp;&amp;nbsp; &amp;nbsp;$5, %edx&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ja&amp;nbsp;&amp;nbsp; &amp;nbsp;L2&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;jmp&amp;nbsp;&amp;nbsp; &amp;nbsp;*L10(,%edx,4)&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.section .rdata,&amp;quot;dr&amp;quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.align 4&lt;br /&gt;L10: &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.long&amp;nbsp;&amp;nbsp; &amp;nbsp;L3&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.long&amp;nbsp;&amp;nbsp; &amp;nbsp;L4&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.long&amp;nbsp;&amp;nbsp; &amp;nbsp;L5&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.long&amp;nbsp;&amp;nbsp; &amp;nbsp;L8&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.long&amp;nbsp;&amp;nbsp; &amp;nbsp;L8&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.long&amp;nbsp;&amp;nbsp; &amp;nbsp;L8&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.text&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L8:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;105(%ecx), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,15&lt;br /&gt;L2:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L3:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;100(%ecx), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L4:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;101(%ecx), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;.p2align 4,,7&lt;br /&gt;L5:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;102(%ecx), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;看完汇编码，第一感觉：cmpl少了许多，一个只读数据段中的L10的标签映入眼帘，以L10标签为起始的内存中依次存储了L3、L4、L5和三个L8的地址，看起来就像是一个地址数组，或者是一个地址表，访问这个数组中的元素实际上就是调用每个元素对应地址中的一段代码。我们继续往前看，来证实一下这个想法。代码不多，比对着汇编指令手册读起来也不甚难。&lt;br /&gt;&lt;br /&gt;pushl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%esp, %ebp&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 将栈帧地址存在%ebp中&lt;br /&gt;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;8(%ebp), %ecx&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 将rv值存储到%ecx中&lt;br /&gt;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;-10(%ecx), %edx&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 将rv值-10之后的值，作为地址偏移量存放到%edx&lt;br /&gt;movl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ecx, %eax&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 将%ecx中的rv值存储到%eax中&lt;br /&gt;cmpl&amp;nbsp;&amp;nbsp; &amp;nbsp;$5, %edx&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 比较5 vs. (rv - 10)，显然5是编译器经过代码扫描后，算出的一个最大偏移值&lt;br /&gt;ja&amp;nbsp;&amp;nbsp; &amp;nbsp;L2&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// jump if above ，如果5 &amp;gt; %edx中的值，则跳到L2继续执行&lt;br /&gt;jmp&amp;nbsp;&amp;nbsp; &amp;nbsp;*L10(,%edx,4)&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;// 如果5 &amp;lt;= %edx中的值，则jmp&amp;nbsp;&amp;nbsp; &amp;nbsp;*L10(,%edx,4)&lt;br /&gt;&lt;br /&gt;解析一下jmp&amp;nbsp;&amp;nbsp; &amp;nbsp;*L10(,%edx,4)，按照书中所说，*L10(,%edx,4)应该对应一个叫indexed memory mode的模式，格式一般是base_address(offset_address, index, size)，含义就是base_address + offset_address + index * size；这样似乎就一目了然了。我们拿i = 12为例，经过前面的计算，%edx中存储的是2，L10(,%edx,4)相当于L10 + 0 + 2 * 4，也就是起始地址=L10 + 8的那个内存区域，恰好是L5的起始地址，jmp&amp;nbsp;&amp;nbsp; &amp;nbsp;*L10(,%edx,4)，直接将代码执行routine转到L5了：&lt;br /&gt;&lt;br /&gt;L5:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;popl&amp;nbsp;&amp;nbsp; &amp;nbsp;%ebp&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;leal&amp;nbsp;&amp;nbsp; &amp;nbsp;102(%ecx), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ret&lt;br /&gt;显然这和前面的猜测是一致的，switch并没有使用性能低下的逐个cmpl的方式，而是形成了一个跳转表(以L10为首地址的地址数组)，并将传入switch的那个整型值经过已经的运算后作为offset值，通过一个jmp直接转到目的代码区，这样无论switch有多少个分支，实际上都只是做了一次cmpl，性能照比多if有很大提升。&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/21059037.html&quot;&gt;关于宏定义切换以及屏蔽的例子&lt;/a&gt; 2008-05-17&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20957793.html&quot;&gt;也谈C语言标识符的NAMESPACE&lt;/a&gt; 2008-05-15&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20468193.html&quot;&gt;也谈C语言变长参数&lt;/a&gt; 2008-05-07&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20147715.html&quot;&gt;也谈typedef&lt;/a&gt; 2008-05-02&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/16977930.html&quot;&gt;多行宏定义中的注释问题&lt;/a&gt; 2008-03-14&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F27859703.html&amp;title=switch%E8%AF%AD%E5%8F%A5%E6%80%A7%E8%83%BD%E8%80%83%E9%87%8F&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Mon, 18 Aug 2008 19:03:12 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/27859703.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/27859703.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007203/5013394</fs:itemid></item><item><title>无线路由设置也'疯狂'-续</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/27756475.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/27756475.html</id><description>刚搬家，由于新的小区不在中国铁通的势力范围之内，所以无奈下只好硬着头皮去安装网通宽带，与铁通宽带不同的是网通宽带套餐必须绑定一部固话，估计这就是固网电信运营商开拓市场的一个卑鄙伎俩吧。铁通就可以不安装电话，直接通过跳线做。还有更严重的一点就是网通宽带贵，包一年比铁通要贵上300块；另外已经习惯了铁通的免费电影网站，网通的收费电影网站让我很是不适应。我又不喜欢用bt，以后看电影还是需要另寻门路了。&lt;br /&gt;&lt;br /&gt;我的无线路由器也随着我一起搬到了新家，昨天网通人员来到我家，顺利的给我安装上了宽带。晚上回来后，我想测试一下卧室内的电话口，遂拔下电话线到卧室中尝试，一试居然不好用；拿回客厅连上线之后，居然也连不上了。打客服电话，告诉他们错误码，按照他们的指导重试也不成，自己又试了几次，依然无果，放弃。把电话单独拿到卧室试试电话线口，居然不可用，原来是电工没有给我接好电话线的缘故；但是厅里面的电话是可以用的啊，怎么搞的呢？今天早上我再次尝试看看是否可以上网，结果还是不行，我试探性的交换了分频器的插线，居然好用了。上班的时候和同事说了这件事，他告诉我分频器的两个口是有区别的，一个for phone，另一个for modem的，我顿恍然大悟。&lt;br /&gt;&lt;br /&gt;晚上回来，一看分频器，果不其然上面有提示字。我是讨厌一堆线的，立马拿出我的无线路由器。&lt;a href=&quot;http://bigwhite.blogbus.com/logs/16597416.html&quot; target=&quot;_blank&quot;&gt;第一次设置路由器&lt;/a&gt;是用网线连接路由器的WAN口进行设置的。取下modem的网线，连到我的本本和无线路由之间，尝试访问192.168.0.1，无果。无线路由器拒绝分配地址给我的本本。停下来想了想，是否是当初设置的时候设置了限制呢？那还有什么方法可以设置呢？&lt;br /&gt;&lt;br /&gt;突然灵光一闪，我通过无线访问设置无线路由不就可以了么。于是拔下网线，启动无线连接，果然很顺利的就连上了。通过admin登录到路由器上(差点忘记了当初的密码，这次一定要记下来，呵呵)，修改ISP的账户设置，重新激活。重新连接到无线路由，一切顺利，新浪体育顺利打开，中国已经得到了24金了，看来这回中国奥运代表团有可能创造历史啊，毕竟还有跳水、羽毛球、体操单项、兵乓球、皮划艇、刘翔等诸多夺金点没有开赛呢。加油！&lt;br /&gt;&lt;br /&gt;网通的网络的确要比铁通的快一些，也不容易瞬断。第一感觉吧，不知道以后会是什么样子。&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28329786.html&quot;&gt;装修的遗憾，其实不美&lt;/a&gt; 2008-08-30&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/25437849.html&quot;&gt;“撒哈拉大森林”&lt;/a&gt; 2008-07-24&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/20783112.html&quot;&gt;一分之差&lt;/a&gt; 2008-05-12&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/17141466.html&quot;&gt;装修博弈·主材选购&lt;/a&gt; 2008-03-17&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/16597416.html&quot;&gt;无线路由设置也'疯狂'&lt;/a&gt; 2008-03-08&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F27756475.html&amp;title=%E6%97%A0%E7%BA%BF%E8%B7%AF%E7%94%B1%E8%AE%BE%E7%BD%AE%E4%B9%9F%27%E7%96%AF%E7%8B%82%27-%E7%BB%AD&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Fri, 15 Aug 2008 20:26:38 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/27756475.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/27756475.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007204/5013394</fs:itemid></item><item><title>CHECKLIST的不实用之处</title><link atom:type="text/html">http://bigwhite.blogbus.com/logs/27753947.html</link><author xmlns="http://www.w3.org/2005/Atom"><name>Tony Bai</name></author><id xmlns="http://www.w3.org/2005/Atom">http://bigwhite.blogbus.com/logs/27753947.html</id><description>CHECKLIST多是类似如下的东西，举一个代码CHECKLIST的例子：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;- 参数的书写是否完整？不要贪图省事只写参数的类型而省略参数名字。&lt;br /&gt;&amp;nbsp;- 参数命名、顺序是否合理？ &lt;br /&gt;&amp;nbsp;- 参数的个数是否太多？ &lt;br /&gt;&amp;nbsp;- 是否使用类型和数目不确定的参数？ &lt;br /&gt;&amp;nbsp;- 是否省略了函数返回值的类型？ &lt;br /&gt;&amp;nbsp;- 函数名字与返回值类型在语义上是否冲突？&lt;br /&gt;&amp;nbsp;&lt;br /&gt;我们常常遇到的一个问题就是在进行source peer review的时候是根据每一个CHECK item去从头到尾看一遍代码(如果有50个CHECK items的话，那就从头到尾看50遍代码)还是记住所有CHECK items，然后只看一遍代码，显然我觉得后者在目前实施的可能性是最大的，也是实施最普遍的。&lt;br /&gt;&lt;br /&gt;但是效果呢？估计还是看50遍代码较好，但是的确不太具备可操作性，投入的工作量太大，很多人也不会接受。&lt;br /&gt;&lt;br /&gt;也有很多人采用折中的方式，比如说一共有10个人参与source peer review，每个人只关注其中的5项check item，然后一起walk through一遍代码。甚至在有些公司采取强制每个人必须能针对自己负责的check item提出问题，否则影响个人绩效之类的方法。&lt;br /&gt;&lt;br /&gt;以上是看到公司的一个文档的CHECKLIST时突然想到的，没想出更好的solution。我想可能更多的人是不去记忆Checklist的，而是直接凭经验对代码评头论足的:)&lt;!--sp--&gt;&lt;div class=&quot;relpost&quot;&gt;&lt;br/&gt;&lt;h3&gt;随机文章：&lt;/h3&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/28535954.html&quot;&gt;小议架构师&lt;/a&gt; 2008-09-04&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/27379836.html&quot;&gt;从座位调换看文化差异&lt;/a&gt; 2008-08-07&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/13942911.html&quot;&gt;再谈如何评价人的技巧&lt;/a&gt; 2008-01-15&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/13579704.html&quot;&gt;如何评价一个人&lt;/a&gt; 2008-01-09&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://bigwhite.blogbus.com/logs/13441383.html&quot;&gt;程序员与影视作品&lt;/a&gt; 2008-01-07&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;addfav&quot;&gt;收藏到：&lt;span class= &quot;delicious&quot;&gt;&lt;a href=&quot;http://delicious.com/save?url=http%3A%2F%2Fbigwhite.blogbus.com%2Flogs%2F27753947.html&amp;title=CHECKLIST%E7%9A%84%E4%B8%8D%E5%AE%9E%E7%94%A8%E4%B9%8B%E5%A4%84&quot;&gt;Del.icio.us&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;</description><category domain="http://bigwhite.blogbus.com/c/">未分类</category><pubDate>Fri, 15 Aug 2008 19:03:37 +0800</pubDate><guid isPermaLink="false">http://bigwhite.blogbus.com/logs/27753947.html</guid><dc:creator>Tony Bai</dc:creator><fs:srclink>http://bigwhite.blogbus.com/logs/27753947.html</fs:srclink><fs:srcfeed>http://bigwhite.blogbus.com/atom.xml</fs:srcfeed><fs:itemid>blogbus.com/bigwhite_blogbus_com/~6905475/111007205/5013394</fs:itemid></item></channel></rss>