『程式設計師調程式碼訪談』是 Karim Hamidou 發起的一個程式設計師訪談系列,受訪者分享他們遇到的最難/最有意思的Bug,以及如何解決。
本文的受訪者是 James Hague,一位程式設計師,遊戲設計師,也是 Programming in the 21st Century 的博主。
你是誰
我是一個早在8位機(紅白機遊戲機)時期就學習程式設計的遊戲設計師,所以我有能力實現自己的想法。最終我意識到自己因為程式設計的原因而在程式設計這條道路上走得太遠,於是轉變角色成為一個全職遊戲設計師。但是我仍然喜歡為自己的專案寫程式碼,在我的大腦沒有被各種技術完全佔據的時候,使得我可以發掘方法來致力於開發過程中最有創作性的部分,我從2007開始便一直在 Programming in the 21st Century 上發表部落格,這是我的twitter@dadgumjames。
你解決過的有意思的bug有什麼
在PlayStation 2(PS2)的遊戲Summoner 2有兩次編譯:開發時期編譯,即每個檔案分開儲存,隨後是打包編譯,即相關的檔案都會被壓縮到一個檔案中。每個壓縮檔案在前端有一個小型的目錄,之後是那些被壓縮的檔案內容。壓縮檔案中的每個單個檔案都會被填充到2048個位元組,因為那是一個DVD扇區的容量。DVD比硬碟速度慢很多,所以設計壓縮檔案的初衷就是避免在順序讀取資料的時候遇到任何定址問題。
通常情況下每個人都能夠進行開發時期編譯因為這一步比較簡單,但是偶然地我會編譯了一版打包檔案來確認檔案沒有問題。大多數情況下是沒有問題的。
然後有一天遊戲在讀取壓縮檔案的時候崩潰了。我需要檢視很多資料來確保沒有犯任何錯誤,所以從程式碼版本管理器上下載了所有的程式碼,編譯,一切執行良好!直到幾周之後有一個不同的壓縮檔案出現了使遊戲崩潰的問題。同樣的結果:當我嘗試用新的資料重現這個問題的時候,問題就消失了。
最終我寫了一個Perl工具來驗證壓縮檔案的整合問題。下一次當這個神祕的崩潰問題再次出現時,我執行了這個工具,發現目錄與實際資料到中途的時候已經沒有對齊了。更奇怪的是,在這個問題中,被壓縮的檔案中有一個大小恰好就是2048
位元組,用不到額外的填充。
問題就出在用來填充的程式碼上。演算法類似於如下
1 2 3 4 |
int padded_size(int size) { return size + (2048 - (size % 2048)); } |
如果被壓縮的某一個檔案大小是2000,那麼padded_size返回2048,這是正確的。但是如果size已經是2048的倍數,那麼返回4096,所以這個檔案就還需要另外一個扇區。
我把方法換成了如下的程式碼
1 2 3 4 |
int padded_size(int size) { return (size + 2047) & ~2047; } |
有什麼要補充的?
我把這個問題作為面試問題使用了一段時間,但是疲憊於解釋為什麼要問這樣瑣碎的問題。但是,最起碼在我問過的人中有一半寫出了與第一版填充程式碼相似的程式碼,沒有意識到這個邊界問題。