2008年10月31日 星期五

程式碼是給人讀的

不是給機器看的。

Code Complete書裡面如是說。

這本書,繁體中文的書名叫做「軟體建構之道」,大陸那邊就照字面翻譯,叫做「代碼大全」。就像電影"The Day After Tomorrow”,一邊是比較有意境的「明天過後」,另一邊是標準翻譯的「後天」。

好,閒話不講。

最近玩了幾天反組譯工具程式,複習組合語言的時候,突然想到這句話。

然後想到我一直把它當作是程式碼的「文言文」的這個語法:

int a1=rand()%20;
int a2;
a2 = (a1>10)? (a1-10):(a1+10);

這段程式,我寧願把它寫的比較「白話」一點:

int a1=rand()%20;
int a2;
if (a1>10)
{
    a2=a1-10;
}
else
{
    a2=a1+10;
}

你說,為什麼一行可以寫完的東西偏偏要改成多了幾行? 我說,因為容易看懂。

另一個原因,容易Trace Bug。第一個code sample裡,你怎麼trace? 怎麼做中斷? 怎麼知道這個條件究竟有沒有成立?

更不要說我常常忘記究竟是問號還是冒號放前面,究竟是 true : false 還是 false : true。

第二個code sample裡,你就絕對不會誤解我要表達的程式意義,我也絕對不會懷疑我是不是又把 true, false寫反了。

至於給機器看的是什麼? 第一段程式編譯出來的結果是這樣:

; 50   :     a2 = (a1>10)? (a1-10):(a1+10);
  000d7    83 7d fc 0a     cmp     DWORD PTR _a1$[ebp], 10    ; 0000000aH
  000db    7e 0b         jle     SHORT $LN9@wmain
  000dd    8b 55 fc     mov     edx, DWORD PTR _a1$[ebp]
  000e0    83 ea 0a     sub     edx, 10            ; 0000000aH
  000e3    89 55 c4     mov     DWORD PTR tv69[ebp], edx
  000e6    eb 09         jmp     SHORT $LN10@wmain
$LN9@wmain:
  000e8    8b 45 fc     mov     eax, DWORD PTR _a1$[ebp]
  000eb    83 c0 0a     add     eax, 10            ; 0000000aH
  000ee    89 45 c4     mov     DWORD PTR tv69[ebp], eax
$LN10@wmain:
  000f1    8b 4d c4     mov     ecx, DWORD PTR tv69[ebp]
  000f4    89 4d f8     mov     DWORD PTR _a2$[ebp], ecx

 

而第二段程式碼編譯出來的結果,像這樣:

; 50   :     if (a1>10)
  000d7    83 7d fc 0a     cmp     DWORD PTR _a1$[ebp], 10    ; 0000000aH
  000db    7e 0b         jle     SHORT $LN8@wmain
; 51   :     {
; 52   :         a2=a1-10;
  000dd    8b 55 fc     mov     edx, DWORD PTR _a1$[ebp]
  000e0    83 ea 0a     sub     edx, 10            ; 0000000aH
  000e3    89 55 f8     mov     DWORD PTR _a2$[ebp], edx
; 53   :     }
; 54   :     else
  000e6    eb 09         jmp     SHORT $LN7@wmain
$LN8@wmain:
; 55   :     {
; 56   :         a2=a1+10;
  000e8    8b 45 fc     mov     eax, DWORD PTR _a1$[ebp]
  000eb    83 c0 0a     add     eax, 10            ; 0000000aH
  000ee    89 45 f8     mov     DWORD PTR _a2$[ebp], eax
$LN7@wmain:
; 57   :     }

 

仔細看,文言文跟白話文的兩段程式碼,是一樣的作用,所以編譯出來的結果當然也是一樣的。既然是相同的,那為什麼不寫得讓人容易看懂些?

2008年10月26日 星期日

住了一週的小鳥房客

陽台藤蔓上的不知名小鳥,已經待了一星期了。

小鳥每天早出晚歸,生活非常規律。早上不知到幾點離開的,反正是我起床以前。晚上回來,大約就是下午五點至五點半之間。

週末這兩天,趁著天色還沒完全暗下來,總算把小鳥拍了清楚一點。

DSC00313

2008年10月22日 星期三

藤蔓上的小鳥

陽台的九重葛藤蔓上,前天晚上來了隻小鳥。

牠攀在藤蔓上,一動不動,我們也不知道牠究竟怎麼了,不敢驚動牠。

隔天早上,小鳥不見了,看來是飛走了,我們擔心牠受傷還是怎麼的,顯然是白擔心了。

晚上下班,小鳥回來了。

好像是把陽台的藤蔓當成了棲身之所。

我看機會難得,拍了相片。

DSC00311

DSC00312

我知道我需要專業的相機,可以拍夜間特寫,但是光有專業相機,沒有專業技術還是不行,所以還是算了,拿個數位相機,就這麼拍吧。

(偏偏陽台外有一盞亮到不行的大路燈,數位相機的拍攝模式調來調去,好不容易才調出個能夠照出樣子的模式來)

今天早上,小鳥又飛走了,不知道晚上還會不會回來?

2008年10月8日 星期三

Proxy : 不只是設計模式

proxy

Proxy是一種設計模式。Wiki上是這麼說的:

A proxy, in its most general form, is a class functioning as an interface to another thing. The other thing could be anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

不過今天的內容跟這個沒太多關係。

最近碰到一個狀況。

我們在遊戲場景裡頭產生了很大量的物件,大約五千個吧。由於程式結構的關係,並沒有利用動態的方式管理這些物件,以致這五千個物件使用了很大量的記憶體,必須要想辦法節省下來。

第一個想法當然是把這些物件改成動態管理,需要的生成,不需要的就釋放掉。不過這麼一來,物件生成的順序、物件之間的關聯性、相依性,就造成了很大的困擾。我們必須從核心程式去調整,甚至在資料方面都必須一起修改。怎麼算,都是一個不小的手術,大概是半身麻醉的等級。

就在我塗塗改改,畫著結構設計圖,想著要怎麼調整程式結構的時候,突然間,Proxy出現了。

我將這些物件套用Proxy結構,把物件之間的關聯性和相依性,保留在Proxy物件中,占用比較大量記憶體的資料部分,就改用動態的管理。需要的時候,由Proxy物件來產生,用完了,也從Proxy物件去釋放。至於Proxy物件呢,就像原先的程式結構一樣,遊戲場景裡放了五千個。

於是乎,物件生成的順序不需要調整,物件之間的關聯性、相依性不需要調整,核心程式也不需要動大手術,只需要在這些場景物件上,把Proxy模式導入。

所以Proxy不只是設計模式,它還成了一種改善程式品質的手法。

不過,最後實做的結果又不太一樣了。

因為原來的物件裡面,早已經將資料部分分離出來,所以我只是修改了幾行程式碼,改成動態的取得資料以及釋放資料。

搞了半天,如此而已..

2008年10月7日 星期二

程式設計者的笑話

http://www.workjoke.com/programmers-jokes.html

這個網站裡頭,有一些關於電腦、程式以及程式設計者的笑話。會去找這種網站,主要是因為我在GDC的會議上聽了一場演講,演講還沒開始的時候,投影片就先撥放了一頁一頁的笑話,看得是台下數百個身為程式設計師的聽眾個個心有戚戚焉,也就博得了滿堂彩。可惜,雖然後來下載到了演講內容的投影片,但卻只有嚴肅的演講內容。

我不知道那位演講者究竟是哪裡收集來的,那麼多讓人會心一笑的笑話,我也就只好自己Google了。

網站裡頭的笑話,有些落落長可是卻不怎麼好笑的,有些呢,倒是滿經典。像是這個..

- "Have you heard about the object-oriennted way to become wealthy?"
- "No..."
- "Inheritance."

還有..

There are three kinds of lies: Lies, damned lies, and benchmarks.

(所以說,benchmark都不能信任啊..)

The programmer to his son: "Here, I brought you a new basketball."
"Thank you, daddy, but where is the user's guide?"

還有這一句..

Bugs in your software are actually special features.

微軟的名字是哪些字的縮寫?

MICROSOFT: Most Intelligent Customers Realize Our Software Only Fools Teenagers

有一段,標題是Software Development Cycle,雖然也是落落長,但卻是我們的辛酸血淚史..

網頁上你還可以看到一個表格,列出來Drug Dealers與Software Engineers有些什麼不同。Drug Dealers說,"The first one is free.”, Software Engineers說,"Download a free trial version”,是啊是啊,免費試用版就是吸引你上癮的啊!

2008年10月1日 星期三

VC中的系統符號檔

嗯,今天跟大家介紹個工具。

先來一段小程式片段。裡面有一個故意弄的Bug。

HANDLE hFile=CreateFile(…);

CloseHandle(hFile);
CloseHandle(hFile);

我把檔案關了兩次,所以在執行的時候,就會crash,call stack看起來像是底下的圖。

callstack_nosymbol

程式死在kernel32.dll, ntdll.dll 這些系統 dll 裡面,啊..束手無策..

接著我對VC做了點調整,加了些東西,crash 時候的 call stack 變成這樣,

callstack_withsymbol

咦? Kernel32.dll 裡的 CloseHandle() 當掉?

這個調整很簡單,打開 VC選單的Tools->Options,然後照著以下的設定,

vc8_symbol_setting

切換到Debugging裡面的Symbols項目,在symbol file locations填入 http://msdl.microsoft.com/download/symbols,接著在cache目錄的欄位,指定一個要存放pdb檔案的目錄。

設定好了之後,重新開始debug程式。第一次執行程式,會很花時間,因為這個時候,VC需要先下載程式用到的每一個系統dll檔的符號檔 (symbol file, *.pdb),放到設定的cache目錄中。

然後在程式當掉的時候,call stack就會多了這一些資訊。

要把這個功能關掉的話,就在上面的這個設定畫面,把symbol file locations的打勾選項都取消掉,也不要指定cache目錄。(硬碟裡面的檔案都還會留著,下次不用重新下載…)