本文的前身〈純手工安裝msys〉內容過時且凌亂無章,這裡重新以 mingw-get 為基礎重寫。
對於只是單純想要有個 Win32 版 GCC 的使用者,使用官網或TDM的圖形界面安裝程式即可。官網的圖形界面安裝程式也能順便安裝 MSYS,但使用命令列界面有比較大的彈性,我使用mingw-get的原因是:
本文的前身〈純手工安裝msys〉內容過時且凌亂無章,這裡重新以 mingw-get 為基礎重寫。
對於只是單純想要有個 Win32 版 GCC 的使用者,使用官網或TDM的圖形界面安裝程式即可。官網的圖形界面安裝程式也能順便安裝 MSYS,但使用命令列界面有比較大的彈性,我使用mingw-get的原因是:
去年底有很長一段時間沒在這裡寫東西了,部分原因是我在 wikibooks 發起《CMake 入門》一書。雖然距離完成還很遠,但我已經漸漸失去動力,日後應該只是偶爾加些內容而已。如果網友對這方面有所涉獵,不妨幫忙補充或修正錯誤。
最初我只打算寫幾個範例在這裡發表,不過寫著寫著卻覺得部落格真不是發表這種東西的地方,後來想到 wikibooks 或許是個合適的發表點。但等到我把內容轉到維基教科書時,卻發現內容不停的擴充,超出我的想像。畢竟在部落格可以隨便亂寫,給自己備忘、讓其他人亂猜,不過寫成詳細的教學卻不得不加入細節。或許過一陣子有空,我會考慮濃縮成精華版回貼到部落格上(我對這點不掛任何保證)。
在去年初玩了一下 Google Test,雖然我還蠻喜歡他的簡潔性,不過仍然繼續用 Boost.Test,一來是因為在我使用的電腦 Boost 可得性比較高,二來是因為當時只能在 Visual C++ 下面使用,用 MinGW 編譯有點問題。
虧我個人的 MSYS 和 MinGW 工具裝得相當齊全,但是執行 configure、make 卻不太成功,我也沒有閒功夫去追原因為何。
在程式撰寫過程中,有時候我們會希望輸出一些內部的資訊,例如某某變數值是多少、有沒有進入某某函式等等,讓 debug 有線索可循。很多人的做法是直接在程式碼當中插入 printf 或 cout,到正式 build 的時候再手動將這些資訊移除,這種做法只適用於小規模的程式,並且在 GUI 程式比較難用。比較巧妙一點的做法是將相關的功能用 macro 包裝,靠 NDEBUG 或類似的 flag 來決定是否輸出這些除錯資訊。我記得 VB6 有個類似的功能叫做 Debug.Print,正式建置程式的時候這些指令將會被編譯器忽略。
以前我的做法是把一些常用的 debug 和 assertion 功能用 macro 包裝好塞在一個標頭檔裡面,依照現實需求略做修改,通常這樣就已經很夠用了,所以未曾在此多留心。後來我在《Applied C++: Practical Techniques for Building Better Software》讀到了一種複雜許多的 debug output 方法,才知道原來小題也可以大作到這種地步。複雜帶來的是功能上的彈性,例如在書中介紹的機制只要切換一個叫做「Debug Sink」的組件,就可以將蒐集到的資訊全部倒到 console、檔案、訊息視窗甚至是網路。不過這些額外的好處還不夠吸引我,所以我還是繼續使用自製的 macro 工具。
最近 survey 了一些 debug sink 實作,其中最原始的應該是 dprintf。用函數實作的dprintf有一些缺點,例如 releas build 時編譯器仍然無法去除額外的函式呼叫。另一方面我們希望能夠自動收集 __FILE__、__LINE__ 的資訊,節省機械化的打字。
要解決這個問題其實很簡單,這裡提供一種做法
先聲明,這不是教學,只是將個人見聞記錄下來,希望對其他人有用,也希望有高手能針對錯誤的地方 給予指正,沒有經驗的人應該先去找個真正的教學來看。
這裡以 MinGW 4.5 建置其他 GCC 4.x toolchain 為範例,GCC 3.x 雖然步驟差不多,但有些小地方應 該要修改。我選的 target 是 arm-elf,因為我對這個比較熟,其他目標有的需要 target system header 比較麻煩。
用 GCC 4.5 編譯 Boost 1.44 遇到第一件感到猶豫的事,就是 runtime-link 該用 static 還是 shared。在 VC 通常想都不用想就選 shared,然後發動坊間熱賣的白癡念力術,妄想其他電腦都出現正確版本 VC runtime。
在 GCC 4.4 之前,MinGW 對標準程式庫都是預設為 static,而且 libstdc++ 還在可接受的體積內,所以我也沒有太關心這個選項。動態連結 libgcc 和 libmingw32 似乎沒甚麼道理,靜態連結可以省掉一堆鳥事。然而見識過靜態連結libstdc++ v3 所帶來的肥大程式碼:直接 cout 出 hello world 就直逼驚人的 1 Mb,就算 strip 過還是大於 500k,如果常撰寫小程式可能得好好考慮動態連結。
2011/6/5 補充
原文的內容已經過時而且過於雜亂無章,一些朋友無法依照原文指示完成安裝,因此最後決定刪除。有用的資訊已經併入〈 使用 mingw-get 安裝 MinGW 和 MSYS〉一文。
我一直沒試過在多緒環境下使用 rand() 或 strtok() 這類函數,因為古有明訓,早在我對 thread 都還沒有什麼概念之前,就已經知道 rand() 或 strtok() 最初設計時對多緒環境完全盲目,所以這種用法對我來說是根本都不用考慮的愚蠢行為。另一方面是因為手邊有比 rand() 和 strtok() 更強而有力的工具,所以甚至是普通的單緒程式我都不太喜歡用 rand() 和 strtok()。
這些函數在多緒環境的問題很容易理解,例如 rand() 通常用線性同餘法實作,內部要維護一個長期存在的種子以產生下一個數。麻煩的地方在於,在多緒環境下呼叫這些函數,可能導致於同時競爭讀寫這些記憶體。同樣的問題也發生在 strtok 上。
C/C++ 當中有一派人士認為,當一個東西不該出現負值的時候,應盡可能以 unsigned 修飾。舉凡標準程式庫當中與記憶體大小相關的數值,像 sizeof 運算、size_t、還有STL容器的 size_type 都是某種 unsigned 整數類型;其他像 strlen 的回傳值以及 malloc 的輸入值也都具有 unsigned 性質。
除此之外,有些人更進一步主張像年齡、人數之類的,既然永遠不可能為負值,那麼也應該要加上 unsigned 關鍵字。這麼做最主要的好處之一是可以在宣告當中表明意圖,另一方面既然 unsigned 不可能為負,所以檢查有效範圍會比較簡單:
本文不打算包含:如何從頭撰寫一個 DLL、如何用某某牌編譯器編譯 DLL、如何在某某牌編譯器使用DLL..... 等等議題。基礎 DLL 教學在網路上非常豐富,有需要的人應該很容易可以得到所需資源,在此先假設讀者都有一定的熟悉度。這裡只打算提供一些能稍稍增加彈性及可維護性的小經驗,特別是 DLL 的 header 方面。或許對很多人來說可能都是常識,只是我發現網路上比較少這方面的整合資訊,所以做了一點綜合整理。
以下我拿自己常用的 DLL header 範本為例
會有這個程式,是因為聽一位朋友說,他光是寫井字遊戲的AI就用掉近千行。
然後當時我就宣稱不用一百行,我就能做出含視窗介面、AI 和流程控制的井字遊戲。
下一代的 C++ (之前的0x,現在已經變1x了)有一項我很喜歡的功能,雖然不會增加 C++ 能做的事,不過讓 C++ 更具易用性。這裡要說的是 initializer_list 和一致的初始化語法。
這份提案已經通過 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2531.pdf
最近看到某位網友的問題:「template 的函數的指標要怎麼傳給 template的函數?」由於沒有額外的說明,所以我不太確定他遇到的困難點在哪裡。
先來看看熱身題,假如存在下面程式片斷,要如何傳遞 Output1() 給 Call() 呢?:
一直以來我都是用 Boost.test 做為測試工具,這是到目前為止我唯一在現實中使用的測試工具,雖然我也試過其它的 test framework,不過僅止於跑跑簡單的範例而已。
這倒不是因為 Boost.test 有多出色,而是因為我的開發環境都灌了 Boost,所以 Boost.test 對我而言是最容易取得的選擇,而且還不算太難用。