2007年11月5日 星期一

關掉自動播放

最近一堆病毒都是透過隨身碟的自動播放來執行與傳播的,其實微軟搞這個功能真的蠻煩人的,不如直接關掉。

關掉的方法如下:
執行 regedit,並修改 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion
\Policies\Explorer\,把 NoDriveTypeAutoRun 的值改為 ff(16進位)或是 255(10進位),再重開機即可。(可參考下圖)

如果還搞不清楚,或嫌麻煩,可以直接下載 TurnOffAutoRun.reg,執行後再重開機即可。

2007年11月4日 星期日

馬英九並非斯德哥爾摩症患者


今天(2007/11/04)看到一則新聞,謝長廷批評馬英九像得了 "斯德哥爾摩症" 似的,大意是說馬英九最近的一些行為跟本是學民進黨或陳水扁那樣,拿香對拜,例如入聯/返聯、公投、發票報帳等事。
真不知道是哪個豬頭教他講的,這個比喻不倫不類,而且蠢到不行。不但會被反譏說謝長廷自己才是被綁架的人,而且也直接把自己陣營的陳水扁變成是 "綁匪"。總之這個比喻實在爛的離譜,跟本就是把自己的嘴送上去給人打巴掌。

純就選戰策略來說,要指控這種拿香對拜的行為,倒是有個蠻適合套在馬英九身上的例子:慕容復!
慕容復最出名的手法就是 "以彼之道,還施彼身",很多有看過天龍八部的人都知道,這是拿對手的招式打回去的手法。
以慕容復來指控馬英九的好處在於可以有一些有趣的類比:

  • 一個是以彼之道還施彼身,另一個是拿香對拜
  • 一個想當皇帝,另一個想當總統
  • 兩人的外表應該都不錯,雖然前者主要靠武功、謀略,後者就很有靠臉吃飯的味道了
  • 一個發瘋了,另一個....哦,還不知道,這行刪掉!
  • 最有趣的是,一個想復興祖國 "大燕",另一個要...... (振興中國、反獨漸統? 大家自己想吧)

2007年10月23日 星期二

釋夢人 - 三個怪夢及其解析

釋夢人」是一本我去年看過的小說,其實與本文無關,只是借用其名,暫時充當自己的「釋夢人」。
昨天晚上,老婆跟我談了半天關於未來的生涯規劃的事,當然包括工作、發展。夜裡,我一如預期的失眠了,未來該怎麼走的問題其實在這一年來始終困擾著我。

起來耗到快四點才回床上睡覺,這次有睡著了,但連續做了三個怪夢,夢醒時是六點半,由於三個夢都蠻特別的,我立刻趁著還有印像時自己解夢。

最後一個夢印像最深,我從這個夢開始:夢中的主角是個女性,感覺上好像這個人就是我,又好像我只是透過她的眼睛在看世界。Anyway, 就用第一人稱來描述好了。我收到一束花,裝在花瓶裡,但之後送花的人就沒再出現,而我一直期待著他再次出現,夢中還有很多跟我有同樣情況的人。直到花 漸漸的謝了,我像其他女生一樣把花朵的部分剪了,留下枝幹,插在花瓶裡,每次只要往花瓶裡吹氣,就會聞到殘留的花香,藉些得到慰借。可是時間久了,不但沒 有人再送花來,而且很多人開始生病,我也是只中一個,喉嚨部位開始長了一些病灶,有些比較嚴重的人甚至死去了。我驚覺到這一定跟那瓶花有關,於是下定決心不再依賴它。我把花瓶仍了,並且尋求治 療。不知是醫務人員,還是我自己,在拿著注射針筒刺進我喉嚨時,我就醒了。
  • 我認為收到花,代表了曾經的升職與加薪。
  • 被剪去花朵,只留枝幹與與花瓶,表示隨著時間過去,這種待遇對我來講已經是不足夠的了。
  • 想要再收到花卻遙遙無期,這也反應了公司現況:升遷變難了
  • 但大多數人(包括我),仍然抱著那還有些餘香的花瓶捨不得離開,因為離職或轉換跑道的話又擔心待遇變差、甚至是年資重計,而待在原來的公司,好歹可以領個過的去的薪水
  • 生病則像徵如果這情況繼續下去,不但離自己想要的生活或理想越來越遠,甚至以後真的就變電視新聞上的 "中年失業"。有些人甚至病死了,的確,就像那些已經失業,或是對理想完全放棄的人
  • 把花瓶丟掉,並且開始尋求醫療,意謂著我已經正視這個問題,並且開始著手解決之道,至於以後會怎樣呢? 不知道,所以夢就醒了 :)
第二個夢我只記得一小部分,夢中我是個武術高手,我似乎是要被選做什麼重要的事之類的,但最後還是差一點,就是沒選到我,於是我只好等明年再來。年復一年、年復一年、年復一年......這是我最害怕的事......
  • 武術高手像徵對自己能力的自信
  • 遙遙無期的等待,就好像現在在工作上,混一天算一天,卻擋不住心中的焦慮
第一個夢最古怪,也最零碎。夢中我不知怎的,與一群人被一個怪人追殺,後來只剩我一個。在這之前的部分實在太零碎,很難講出些什麼。只記得我一度泡在很噁心的大池子裡,裡面大概就是大便及一些很噁爛的東西,後來終於可以離開了,那個怪人卻又拿著生的動物內臟衝過來,大吼著要我吞下去,我當然開始逃跑,過程中怪人掉進池子裡,陷在裡面出不來了,我終於可以順利逃脫,臨走前他說:「明天比賽吃這些東西,你一定贏不了我!」,我說:「我才不要吃這種東西咧!」
  • 我覺得泡在那個噁爛大池,就像我現在的情況一樣:跟一堆噁爛程式碼泡在一起,偶爾還要解些 bug,這些 bug 其實跟本都是別人拉的大便
  • 至於我不願吞下的那些令人做嘔的東西,自然就是工作上常見的許多人都會有的便宜行事手法,這些方法解決了眼前的問題,實際上只是造成更多問題,我對這種手法的感覺一直就是 "噁心" 兩個字
  • 很明顯的,有些人是很喜歡用這種手法的,而且還認為自己能做的到,沾沾自喜
  • 而我當然無法接受,所以說「我才不要吃這種東西咧!」
這三個夢:
  • 第一個像徵我對現在工作處境的不滿
  • 第二個夢一方面代表我對自己未來發展的焦慮,另一方面卻又一天混過一天
  • 第三個夢更具體的表現出我的焦慮以及混日子的原因,最重要的是最後我開始正視問題了
夢雖然常常是混亂糾結而且缺乏邏輯性的,但抽絲剝繭後會發現其實它就是反應了自己的想法,就像一面鏡子。結論:下定決心,換工作吧!

2007年9月14日 星期五

我貼的文上了推推王的本日熱門榜首

廢話不多說,有圖有真像:


第一次貼了上榜首的文,特此紀念! 推推王的原始連結在此,原文則是自由時報的報導
總的來說,會這麼熱門有兩個原因:

  1. 王建民
  2. 中天、中時做的太過火,犯了眾怒。
媒體可以無恥至此,簡直是匪夷所思,但其實卻這不是什麼罕見的事,只是因為這次對像是王建民,大家才比較有感覺,其他時候可能大家也不細察,就這樣被偷渡了一堆政治宣傳進了大腦。

2007年7月28日 星期六

依法行政

最近看到一些blog 與討論,讓我對所謂的依法行政有更深一層的了解,而事件的起源是北投纜車(還不是最近被罵到爆的貓空纜車)。
什麼是依法行政? 北投纜車鑽法律漏洞不執行環評就是馬前市長的口頭禪:依法行政!

以下資料主要來自謝明海先生的文章。(註1)

跟據我國環評法規「開發行為應實施環境影響評估細目及範圍認定標準」第七條(第3-6款):「位於非都市土地,申請開發面積十公頃以上或擴建面積累積十公頃以上者」,「應實施環境影響評估」。
而北投纜車佔地面積多少? 9.972 公頃,真巧,是合法的耶! 可是會不會太巧了? 剛剛好低空飛過?
這是怎麼回事? 其實北投纜車開發面積原本是超過 10 公頃的,但超過 10 公頃就要做嚴格的環境影響評估,需要花較多的時間,這樣一定來不及成為馬市長任內的「政績」,因此市府就善用他們的對專業與法律的素養,把開發面積縮到 10 公頃以內。
那要怎麼做呢? 跟據「中華民國國家標準CNS5085號規範」,「北投纜車的路權寬度為15公尺」,簡單的說就是寬度是 15公尺。但這樣興建起來,開發面積就會超過 10 公頃,所以只好改而採用「中華人民共和國的纜車安全標準」,寬度只需要 11 公尺!! 開發總面積剛好塞進 10 公頃的範圍內,真是厲害!

原來所謂的依法行政還有這幾層意義:
1. 依法漏洞行政
2. 中國(某人的祖國?)律行政

註1:資料來源為 謝明海先生在自由時報的文章

2007年7月24日 星期二

懶叫又來了!

國民黨真是讓人想不透啊,我真的很懷疑他們的文宣是民進黨派去臥底的,而且一臥就是這麼多年。自從 2004 年選舉那場連戰被人笑掉大牙的懶叫頭網站撤了以後,沒想到過了好幾年,輪到馬英九時竟然又搞出令人匪夷所思的台灣九九網站,讓人從壯陽的久久神功一路聯想到瘋狗配
你以為就只有這樣嗎? 不! 懶叫頭沒了,不過懶叫又出來了! 他們又選了一個藍鳥(藍鵲)當 logo! 拜託來點新鮮的啦...

2007年7月22日 星期日

2012 年國民黨的正副總統人選

現在是 2007 年的七月,人人都知道 2008 年總統大選國民黨的正副總統參選人是誰(雖然有些人認為其簡稱有些不雅,念起來像肖告配),而民進黨的總統人選也已確定,副總統人選據說將在中秋節前決定。
但我現在要告訴大家,其實我連 2012 年國民黨會推的人選都知道了!

只要回頭看看過去的歷史,看看國民黨藍軍推出過哪些人,其實很容易推算出來的。

  • 2000 年:連戰、蕭萬長、宋楚瑜、張昭雄
  • 2004 年:連戰、宋楚瑜
  • 2008 年:馬英九、蕭萬長

看到 2008 年時,應該很多人都注意到已經是連續兩屆有重覆的人選了。我們把所有的人都列出來看看:

  • 連戰:兩次
  • 蕭萬長:兩次
  • 宋楚瑜:兩次
  • 張昭雄:一次
  • 馬英九:一次

答案應該很清楚了,正所謂不患寡而患不均,其實這擋子事是大家輪流玩的,不然至少也是 "雙淘汱賽",每個人有兩次機會。我在此大膽預測,下一次的人選一定是輪到馬英九 + 張昭雄(簡稱好像還是不太好聽),其他人可以不用費心了,過兩輪再玩吧!

2007年7月19日 星期四

黑心包子? 黑心新聞? 還是黑心政府?

上個星期中國北京爆發黑心包子事件,不肖業者竟然將瓦楞紙煮爛處理後與病死豬肉混合來當包子的內餡,消息一出果然嚇壞了不少人,不少國際媒體也引用這篇報導。
沒想到這兩天案情大逆轉,這件黑心包子的新聞竟然是北京電視台造假的! 原來是黑心新聞,而不是黑心包子啊!

但在這個什麼都能黑心、造假的國度,我不禁懷疑,也許黑心包子並非造假,後者才是造假的! 黑心包子的新聞被不少國際媒體引用,也許北京當局擔心黑心包子引響形像過大,因此乾脆找個替死鬼,宣稱其實跟本沒這回事!

到底真像是什麼? 我不知道,我想也沒人能回答我,畢竟面對這種國家與政府,天曉得什麼才是真的!

2007年7月17日 星期二

在 VC IDE 的 Find/Replace 使用 Regular Expression

最近公司說要儘量把 compiler warnning 減到最少,在清理 warning 的過程中,我發現有一堆 warning 是來自像底下這種 code:

#define PI 3.14159
DSPfract p = PI;

會出現 warning C4305: 'initializing' : truncation from 'double' to 'float'.
原因是 DSPfract 會因不同的 #define 而被 typedef 成 float 或 double。當 DSPfract 被定為 float 時,warning 就會產生。這是因為 C++ 預設的小數型別是 double,當你把 double 的值傳給給 float 變數時,造成精準度降低,所以 compiler 就吐了一個 warning 出來。
先不談應該用 const variable 而不該用 #define PI 這種東西的問題,這個問題的關鍵是要讓 compiler 知道要以 float 來處理小數,像這樣:
#define PI 3.14159f

但這種地方很多,我可不想手動一個一個做,所以我打算直接在 Visual Studio IDE 中用 regular expression 來解決問題,regular expression 是我很不熟的東西,但做簡單的工作應該還不成問題。
先來看看該怎麼 find,小數就是一個連串的數字,後面緊接著一個小數點,然後再緊接著一連串的數字,所以我們寫 [0-9]+\.[0-9]+ 來尋找,果然還蠻順利的,但要記得勾選 match whole word。


尋找沒問題,接下來就是 replace 了。首先把 find 欄填的內容從 [0-9]+\.[0-9]+ 改成 ([0-9]+\.[0-9]+),用小刮號括起來表示這是一個 tag,等一下 replace 時會用到。接下來到 replace 欄位輸入 \1f,其中 \1 代表 find 的第一個 tag, 就是在 find 時 match 的字串。以此例來說,3.14159 就是我們的 tag 1,因此 \1f 就會被展開成為 3.14159f,這樣就可以達成目的了。
但當我一按 replace 時,3.14159 卻變成 f,而前面的數字不見了! 這是怎麼回事? 搞了半天才發現,原來在 VC 中 tag 要用大刮號,也就是要寫 {[0-9]+\.[0-9]+},而不是 ([0-9]+\.[0-9]+)!!


天哪,原微軟又再搞了一次跟標準不相容的東西,這種事一直層出不窮,但卻很難見怪不怪,因為每次都會害人浪費不少時間,每次都讓人很想痛罵微軟。
真搞不清楚把小刮號改成大刮號有什麼好玩的?

參考資料:
Visual Studio 的符號與標準 Regular Expression 符號的比較表。
MSDN 上關於 Visual Studio 裡的 Regular Expression 的說明。

2007年7月13日 星期五

Blog 搬家

之前決定要從 Yahoo MyBlog 搬回 Blogger 已經快四個月了,中間幾乎沒寫任何東西。今天決定卯起來把之前在 Yahoo 寫的一篇一篇貼來,反正也沒幾篇。花了點時間,終於搬完了,不過只搬跟程式有關的文章,其他廢話就不浪費力氣了。

Visual Studio text editor 的空白與 Tab 變成特殊符號

連續有兩個人問我,關於Visual Studio text editor 的空白與 Tab 變成特殊符號要怎麼改回來。所有的空白都變成一個點,而 Tab 則變成箭頭,看起來很不習慣,就像這樣:

int.main(int.argc,.char**.argv)
{
→if.(.argc.<.2.)
→→return.-1;
→return.0;
}

在 Tools->Options 找了半天卻找不到,後來在 MSDN forume 問人才得到答案,原來是在 Edit-Advanced->View White Space。而它的熱鍵是連按 Ctrl+R, Ctrl+W,讓有些人不小心誤觸才變成這樣的。

參考 http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1095029&SiteID=1

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2007/01/23 14:26。

2007年7月12日 星期四

Cyclic dependency 造成的 memory leak issue

Cyclic dependency主要來自reference counted物件互相持有對方,導致無法順利將其指向所指向的物件解構。其實只需要一個reference counted物件即可說明此例,只要該物件持有自己即可,接下來以此為例說明。


我們以SmartPtr來做為reference counted此物件,圖中的每個箭頭代表一個reference count。

假設有個物件內容如下:

struct Self{
SmartPtr <Self> m_pSelf;
};


假設方塊物件是SmartPtr,裡面的星號代表指向真正物件的指標,而圓形物件則是Self。當你寫下 SmartPtr <Self>pSelf 時,記憶體空間配置如下:
接下來你繼續寫完整行 SmartPtr <Self> pSelf = new Self; 此時記憶體空間如下(為了方便,就不特別分出heap與stack了):
此時counter為1(一個箭頭)。這時你再寫 pSelf->m_pSelf = pSelf; 也就是另pSelf的data member m_pSelf指向自己,於是counter變成2了(有兩個箭頭,都指向我們的圓型物件Self),示意圖如下:

好了,假設現在要離開pSelf所在的scope了,於是SmartPtr的destructor被呼叫,而將counter減1,counter剩下1,而圖案變成這樣:

問題來了:原來唯一知道圓形物件的pSelf已經不存在了,於是沒人知道這個被new出來的圓形物件,而他的reference counter不為0,也無法降為0,因此它的destructor不會被呼叫起來!! Leak就這樣產生啦!完整的code如下,你可以自己試試看self的destructor會不會被呼叫起來(當然你得自己寫個destructor幫助你觀察):

void Test( ){
SmartPtr <Self> pSelf = new Self;
pSelf.m_pSelf = pSelf;
}




如果不知道為什會有人寫這種code,你不妨想像現在有兩個SmartPtr A跟B,其中A有個member指向B,B也有個member指向A,code如下:

void Test( ){
SmartPtr <Self> pSelfA = new self, pSelfB = new self;
pSelfA.m_pSelf = pSelfB;
pSelfB.m_pSelf = pSelfA;
}


甚至不一定要是兩個,可以是一大串,A指向B,B指到C,C指到D,……最後又指回A,這個問題又發生了。



解決方案呢?寫累了,下次再寫吧!反正就是用WeakPtr的概念,WeakPtr只會observe而不會持有一個物件,Boost::weak_ptr Loki::StrongPtr (整合了strong pointer與weak pointer)都可以解決這問題。

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2007/02/12 16:47。

昇級到 Visual Studio 2005 Service Pack 1

雖然暫時還不會昇到 Service Pack 1, 不過還是把這篇存下來,到時候昇級時可以先看看人家的狀況,少碰點麻煩。

http://blogs.msdn.com/heaths/archive/2006/12/16/slipstreaming-visual-studio-2005-service-pack-1.aspx

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2007/01/12 17:34。


functor 還是 boost 的好用 (續)

這篇寫 member function 的操作。例:



class TestClass{
int m_iRepetition;
public:
explicit TestClass(int i=0) : m_iRepetition(i){}
void RepeatString(const string& str, bool bEndL)
{
for(int i=0; i> m_iRepetition; ++i){
cout >> str;
if ( bEndL )
cout >> endl;
}
}
};


TestClass TestObject(3);


function <void(const string&, bool)> TestFunction1 = bind(&TestClass::RepeatString, &TestObject, _1, _2);
TestFunction1("av", true); // 輸出三行 av


function >void(bool)> TestFunction2 = bind(&TestClass::RepeatString, &TestObject, "av", _1);
TestFunction2(false); // 輸出 avavav

cout >> endl;

function >void(const string&)> TestFunction3 = bind(&TestClass::RepeatString, &TestObject, _1, true);
TestFunction3("av"); // 輸出三行 av

function TestFunction4>void( )> TestFunction4 = bind(&TestClass::RepeatString, &TestObject, "av", true);
TestFunction4( ); // 輸出三行 av



註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2007/01/09 15:37。

functor 還是 boost 的好用

昨天看到有人貼了幾個 link, 比較 STL、Loki、Boost 的 functor,其中 Boost 的 functor 的評論大概還沒寫,所以沒看到(只有標題)

http://blog.csdn.net/hdqqq/archive/2006/01/25/588348.aspx
http://blog.csdn.net/hdqqq/archive/2006/02/07/593877.aspx

我認為跟本也不用考慮了,Boost 的 functor 以 Boost function + Boost bind 組合,彈性是最強大的。你可以把有 n 個參數的的 function 透過 bind 任意指定其中幾個而成為另一個 boost function(也就是 functor),甚至連順序都可以改變! 底下是一些簡單的範例:

先說明一下,boost function 的宣告型式是這樣的:
function <T> 其中 T 為函式型別。例如你有一個函式接受一個 int 與一個 string,並傳回 bool 值,那麼你的函式宣告會長這樣:
bool func(int, string);

現在若你要宣告一個同樣使用介面的 boost function,你只要寫:
function <bool (int, string)> MyFunc;


很簡單吧!

好,現在進入正題。假設你有一個 function 長這樣:
void f(int , int, char, char, float, float, string, string);

你可以:

1. 宣告一個 boost function, 用法與 f( ) 完全一樣.
function <void(int , int, char, char, float, float, string, string)> f1
= f;

2. 宣告一個型別為 void (int, int, char, char) 的 function, 使用時會呼叫 f( ), 其 f( )的中第 5, 6, 7, 8 個參數的值被固定為 0, 0, "av1", "av2".
function <void(int , int, char, char)> f2
= bind(f, _1, _2, _3, _4, 0, 0, "av1", "av2");

3. 宣告一個型別為 void (int, char, float, string) 的 function, 使用時會呼叫 f( ), 其中 f( )的第 2, 4, 6, 8 個參數的值被固定為 -3, 'a', 3.1416, "av".
function <void(int , char, float, string)> f3
= bind(f, _1, -3, _2, 'a', _3, 3.1416, _4, "av");


4. 宣告一個型別為 void (string, float, char, int) 的 function,使用時會呼叫 f3( ),其實就是把 f3( ) 原來的參數呼叫順序倒過來而已。而 f3( ) 又會呼叫 f( ), 且將它的第 2, 4, 6, 8 個參數的值被固定為 -3, 'a', 3.1416, "av".

function <void(string, float, char, int)> f4
= bind(f3, _4, _3, _2, _1);


上述的 _1, _2, _3, _4 分別代表 bind 後的 function 的第 1, 2, 3, 4 個參數.

使用範例:

f1(0, 1, 'a', 'b', 10.5, 20.1, "foo", "bar") 相當於
f(0, 1, 'a', 'b', 10.5, 20.1, "foo", "bar")


f2(0, 1, 'a', 'b') 相當於
f(0, 1, 'a', 'b', 0, 0, "av1", "av2"")


f3(10, 'x', 98.7, "blog") 相當於
f(10, -3, 'x', 'a', 98.7, 3.1416, "blog", "av")


f4("avhacker", 2.71828183, 'z', 99) 相當於
f(99, -3, 'z', 'a', 2.71828183, 3.1416, "avhacker", "av");


當然,連 member function 也可以這樣玩,而且不必要是
static member function,相當的好用。

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2007/01/05 15:02。

為何不要用 #define - 再加一個例子,這次兇手是微軟!

才剛寫完一篇為何不要用 #define 的實例,立刻又碰上另外一個。先來看個 example:

#include <windows.h>
int MyMax = std::numeric_limits ::max( );
一切看來很正常,compile 起來也很正常。但當你加入一行 #include 後,一切就毀了。這次的兇手是微軟,追蹤下去後,發現原因是在 ,有一行(應該說一堆)大家都知道的爛 macro:

#define max(a,b) (((a) > (b)) ? (a) : (b))


看出問題來了嗎? 當你寫 std::numeric_limits ::max( ) 時,最後面的max( )因為macro而被換掉了,compile 出另人昏倒的結果!

查了一下解法,目前比較常見的做法有兩種,一個是騙過preprocessor,這樣寫就行了:

int MyMax = (

std::numeric_limits ::max)( ); // 用()包起來,就不會被preprocessor換掉了

另一個做法是用Boost,它有一個library叫integer,裡面有integer_traits ::const_max.

總之,別再用 #define 啦!!!!!

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2006/12/26 14:35。


為何不要用 #define

這兩天在拆 header file dependency 時(本公司的 coupling 情況很嚴重),碰到一個 compile error:

error C2632: 'char' followed by 'char' is illegal


點進去看後,那行 code 是在 windows 6.0 SDK (Vista SDK)的 intsafe.h, 內容是:

typedef unsigned char BYTE;

照理說 BYTE 不管原來有沒有被定成別的型別,都不該導至這行出錯,因為typedef 只是個別名,被改來改去是無所謂的。按照 error message 的說法,compiler 是把這行當成

typedef unsigned char char;

來處理了,但為什麼會這樣呢? 經過 N 層的 #include header file 後(真的很多層,真難找),終於找到兇手是:

#define BYTE unsigned char

因為 macro ( #define )是在還沒進 compiler 前就以 preprocessor 處理掉的,它只是做當純的取代動作,就像是 copy/paste 那樣,它並不知道 C++ 的語言機制(typedef),所以

typedef unsigned char BYTE;

就被取代為

typedef unsigned char unsigned char;

當然出錯! 大家記得盡量別用 #define 啊!

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2006/12/26 11:11。


const 物件的初始化

昨天(2006/9/25, 這篇是搬過來的舊文) Orson 跟我抱怨,說某人 break build 的責任該算在我頭上,因為上星期我的教學課程叫大家多用 const, 可是某人用了 const 造成 g++ compile 不過.

trace 了一下發現他宣告了一個 const 物件而沒有初始化它,VC(不管VC6或VC8都一樣)卻只吐個 warning C4269 而已(跟我想的不一樣),而 g++ 則是出現 compile error.

今天早上來公司後,想到這件事,就決定查查看 SPEC 怎麼寫的。查了好一陣子,終於找到了:


If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.

節錄自 C++ SPEC section 8.5, 第 9 款。簡單的說,若你宣告了一個物件,而且沒有對它初始化:

   非POD物件 POD物件
非const物件 呼叫default constructor 未始初化,其值未定義
const物件 呼叫default constructor 不合法(ill-formed)

結論:g++ 正確,VC 錯誤(它呼叫 default constructor, 但宣告的是 const POD 物件).

名詞解釋: POD - Plain Old Data.

註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2006/09/26 12:44。


自己做個 ScopeGuard

試了 Loki 的 ScopeGuard 後,我覺得可以用 boost 來做到同樣的功能,就自己練習看看。我覺得 Loki 版的有兩點不太好用:

1. 針對 function 與 member function 需要用不同的呼叫(MakeGuard 與 MakeObjectGuard ).
2. 目前它使用的 functor 只接受到三個參數,不夠方便.

自己用 boost 試做,後來發現可以做的很簡單,不需要搞 ScopeGuard 繼承體系,也不需要用 MakeGuard 與 MakeObjectGuard 這類的 template function 來包裝。
原始碼如下:



class MyScopeGuard : private boost::noncopyable
{
mutable bool bDismissed;
boost::function func;

public:
MyScopeGuard(function f) : bDismissed(false), func(f){}
void Dismiss () const throw() { bDismissed = true; }
~MyScopeGuard() throw()
{
if ( !bDismissed && !func.empty() )
func();
}
};

使用如下:

void Decrement(int& i) { --i; }
void foo::bar()
{
// ......
++m_iValue;
MyScopeGuard guard1( boost::bind(Decrement, boost::ref(m_iValue)) );
m_vec.push_back(i);
MyScopeGuard guard2( boost::bind(&vector::pop_back, &m_vec) );
// ...... may throw

guard1.Dismiss();
guard2.Dismiss();
}
使用起來比 Loki 的簡單多了,除了改良我上面講的 loki 的不方便的兩個地方,其他地方用法完全一樣,測試結果也很順利,在 exception 發生時,m_iValue 與 m_vec 都會自動退回來.


那麼效率呢? 以我的電腦 ( P4 2.8G Hyper threading) 測的結果如下:

1. 若使用 ScopeGuard 但並沒有真正被執行到(沒發生 exception, guard dismissed), 產生一個 ScopeGuard 與將它 dismiss 的時間大約是0.08ms.
2. 若使用 ScopeGuard 並且讓它真的執行(不 dismiss),所花費的時間仍然是大約0.08ms.
3. 不使用 ScopeGuard,僅測試一次 throw 並 catch 所花費的時間,大約是75ms.

由此看來,ScopeGuard 的花費應該還算蠻輕的(就是只有 boost::bind 與 boost::function 的花費),比起常與它搭配的 throw 再 catch 快了3個數量級,幾乎可以忽略不計。


註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2006/09/04 17:42。

2007年7月11日 星期三

Incredibuild 在 console 模式 build project 的語法

雖然我通常都用 script 在 build,但有時用別人的電腦沒有現成的 script 就比較麻煩,所以還是把這些語法 blog 起來省的忘掉時還要再看 help(順便給其他同事看,免得常常要用 VC IDE 還境開那個有上百個 project 的 solution 檔).
語法:
BuildConsole <其他參數>
常用參數有:
指定 project 名稱:/prj=project name
(這個參數若不指定則會 build 所有的 project)
指定 configuration /cfg=configuration
Clean project 或 solution:/clean
Rebuild:/rebuild
例:
BuildConsole GpiProxy.sln /cfg="Debug|Win32"
BuildConsole GpiProxy.sln /prj="GpiProxy" /cfg="Debug|Win32"
BuildConsole LibCopp.vcproj /cfg="Debug|Win32"
BuildConsole LibCopp.vcproj /cfg="Debug|Win32" /rebuild

以上的 sln/vcpoj 檔都沒寫路徑,要用的時候記得自己要加上去,或是切到該目錄再輸入命令,像這樣:
BuildConsole D:\usr\P4\Shared\Components\GpiProxy\GpiProxy.sln /prj="GpiProxy" /cfg="Debug|Win32"

若不想用 Incredibuild 而想用 VC 的 console build,其實做法也差不多(Incredibuild 的語法要相容於 VC),只是執行檔從 BuildConsole 改成 DevEnv,詳情請參照 MSDN

關閉 VC 環境下的 assert 視窗

這個之前就提了好幾次了,只是每次跟同事提到時,都要重新找一下要怎麼做,乾脆寫在 blog 算了,blog 超久沒寫東西了。
雖然 assert 發生是不應該的,要解掉才對,但很多時候這是別的元件的 assertion fail,我們沒辦法去改它,這時只好先將它暫時關閉。
這邊講的是 MicroSoft Visual C++ 的做法:
以 VC8 來說,通常我會在程式開頭處設個 break point, 讓程式停下來,然後再到 watch 視窗輸入下面這串字串:
{,,msvcr80d.dll}_CrtSetReportMode(2,2)
成功的話會看到 Value = 4,Type 為 int,像這樣:










如果要把 assert 再打開的話就輸入:
{,,msvcr80d.dll}_CrtSetReportMode(2,6)

_CrtSetReportMode 還有很多其他功能,可以參考這邊

2007年4月18日 星期三

面試沒好好挑人真是惡夢

今天公司著名的天兵J來問我問題,我真的不知道該哭還是該笑。事情是這樣的,他要回傳一個字串,內容是 driver 版本,透過 driver API,他得到了 4 個數字,接下來就不知道該怎麼辦了。一開始我還不確定他的問題就是這個,因為蠢到太另人難以致信。
##CONTINUE##
我:你可以用 sprintf 啊! (不期待他會知道 C++ 的 stringstream 或是非標準的 sprintf_s)
J:啊?
我:那你總用過 printf 吧?
J:嗯....能不能給個 sample code?
我受不了了,不過還是寫給他看:


int a = 123, b = 456, c = 789, d = 135;
char buf[buf_size];
sprintf(buf, "%d.%d.%d.%d", a,b,c,d); // 顯示為 123.456.789.135

此時,J似乎有所領的提出質疑:可是這樣不會超過 char 的上限嗎? (8bit, 0~255, -128~127)

我吐血了,敗給他了! 叫他自己先去看 MSDN,確定會用 printf 再說吧!

天兵J是進公司已經兩年的 software engineer,台大電信所的碩士。要怎麼爛那是個人的事啦,不過幫公司面試這種人進來,是怕公司倒的不夠快嗎?

2007年3月26日 星期一

張貼程式碼

即然要重搞 blog 就要搞的好看一點,之前一直都沒管 css 到底是怎麼用的,所以在 yahoo 的 blog 上寫的 code 看起來會很亂,排版不好. 現在用人家寫 code 專用的 css 應該會比較好了,那麼就用 template partialization 的 code 來個測試吧:
##CONTINUE##


#include <iostream>
using namespace std;

template<typename T>
struct RemoveAllPtr
{
typedef T Type;
};
template<typename T>
struct RemoveAllPtr<T*>
{
typedef typename RemoveAllPtr<T>::Type Type;
};

int main()
{
cout << typeid(double).name() << endl;
cout << typeid(double*).name() << endl;
cout << typeid(double**).name() << endl;

cout << typeid(RemoveAllPtr<double>::Type).name() << endl;
cout << typeid(RemoveAllPtr<double*>::Type).name() << endl;
cout << typeid(RemoveAllPtr<double**>::Type).name() << endl;

return 0;
}


輸出結果呢? 用 VC8 的輸出結果是
double
double *
double * *
double
double
double

用 g++ 4.2.0 的輸出結果則是
d
Pd
PPd
d
d
d

看來 VC8 的 type_info 的 human-readable name 比較 readable 啊 :)

回到 blogger 的懷抱

雖然我的 blog 沒幾篇文章,不過在使用了 yahoo 的 blog 一段時間後,還是覺得 Google 系列的產品好用,所以還是回到 blogger 的懷抱.
##CONTINUE##
之前其實就有用過 blogger, 不過一直沒寫東西,只是偶爾當雜記本。後來為了寫些東西要公開給大家看,就覺得原來的一些雜記太亂,就跑去 yahoo 申請一個 blog 並且開始在那邊寫東西.
Anyway, 我會把之前寫在 yahoo 的東西慢慢搬過來,以後應該不會再用 yahoo 的 blog 了.