2010年11月25日 星期四

莎士比亞的名言

1、 愛的最佳習慣是會說話
2、 現在握手,以手交心
3、 但凡言愛,須要輕聲
4、 真愛之路從來不平坦
5、 愛不表現則不存在
6、 亂石砸不滅愛火
7、 愛情舒心,猶如雨後朝陽
8、 找來的愛甜,不找自到的愛更甜
9、 如有真愛,當真心言說
10、可疑星星為火,可疑太陽西移,可疑真理不存,惟我愛不可疑
11、爾之面熟,不可謂之真俗
12、愛如溫泉,常新不止

時間會刺破青春表面的彩飾,會在美人的額上掘深溝淺槽;會吃掉稀世之珍!天生麗質,什麼都逃不過他那橫掃的鐮刀。 —— 莎士比亞

多聽,少說,接受每一個人的責難,但是保留你的最後裁決。 —— 莎士比亞

不良的習慣會隨時阻礙你走向成名、獲利和享樂的路上去。 —— 莎士比亞

青春是一個短暫的美夢,當你醒來時,它早已消失無蹤。 ----莎士比亞

母羊要是聽不見她自己小羊的啼聲,她決不會回答一頭小牛的叫喊。 ---莎士比亞

醜惡的海怪也比不上忘恩的兒女那樣可怕。 ---莎士比亞

道德和才藝是遠勝於富貴的資產,墮落的子孫可以把貴顯的門第敗壞,把巨富的財產蕩毀,可是道德和才藝,卻可以使一個凡人成為不配的神明。 ---莎士比亞

習氣那個怪物,雖然是魔鬼,會吞掉一切的羞恥心,也會做天使,把日積月累的美德善行熏陶成自然而然而令人安之若素的家常便飯。 ---莎士比亞

他們的莊嚴高貴。 ---莎士比亞

人世間的煊赫光榮,往往產生在罪惡之中,為了身外的浮名,犧牲自己的良心。 ---莎士比亞

質樸卻比巧妙的言辭更能打動我的心。 -----莎士比亞

多聽,少說,接受每一個人的責難,但是保留你的最後裁決。 ----莎士比亞

當我們膽敢作惡,來滿足卑下的希冀,我們就迷失了本性,不再是我們自己。 ----莎士比亞

一個驕傲的人,結果總是在驕傲裡毀滅了自己。
---莎士比亞

愛情不是花蔭下的甜言,不是桃花源中的蜜語,不是輕綿的眼淚,更不是死硬的強迫,愛情是建立在共同語言的基礎上的。 ----莎士比亞

忠誠的愛情充溢在我的心裡,我無法估計自己享有的財富。 ---莎士比亞

人的一生是短的,但如果卑劣地過這短的一生,就太長了。 ----莎士比亞

黑夜無論怎樣悠長,白晝總會到來。 ---莎士比亞

對眾人一視同仁,對少數人推心置腹,對任何人不要虧負。 ------莎士比亞

書籍是全世界的營養品。 ----莎士比亞

在命運的顛沛中,最可以看出人們的氣節。
----莎士比亞

愛和炭相同。燒起來,得沒法叫它冷卻。 ----莎士比亞

苦盡甘來。 ---莎士比亞

生命短促,只有美德能將它留傳到遼遠的後世。
---莎士比亞

真正的愛情是不能用言語表達的,行為才是忠心的最好說明 ---莎士比亞

愛比殺人重罪更難隱藏;愛情的黑夜有中午的陽光
---莎士比亞

不太熱烈的愛情才會維持久遠 ----莎士比亞

愛情裡面要是攙雜了和它本身無關的算計,那就不是真的愛情 ---莎士比亞

愛情不過是一種瘋 ----莎士比亞

當我們還買不起幸福的時候,我們絕不應該走得離櫥窗太近,盯著幸福出神。 ---莎士比亞

不要給百合花鍍金,畫蛇添足。 ---莎士比亞

美德是勇敢的,為善永遠無所畏懼。 ---莎士比亞

女人是用耳朵戀愛的,而男人如果會產生愛情的話,卻是用眼睛來戀愛。 ---莎士比亞

因為她生得美麗,所以被男人追求;因為她是女人,所以被男人俘獲。 --莎士比亞

聰明人變成了痴愚,是一條最容易上鉤的游魚;因為他憑恃才高學廣,看不見自己的狂妄。愚人的蠢事算不得稀奇,聰明人的蠢事才叫人笑痛肚皮;因為他用全副的本領,證明他自己愚笨。 ---莎士比亞

我沒有路,所以不需要眼睛;當我能夠看見的時候,我也會失足顛仆,我們往往因為有所自恃而失之於大意,反不如缺陷卻能對我們有益。 ---莎士比亞

懦夫在未死以前,就已經死了好多次;勇士一生只死一次,在一切怪事中,人們的貪生怕死就是一件最奇怪的事情。 ---莎士比亞

外觀往往和事物的本身完全不符,世人都容易為表面的裝飾所欺騙。
沒有比較,就顯不出長處;沒有欣賞的人,烏鴉的歌聲也就和雲雀一樣。要是夜鶯在白天雜在聒噪裡歌唱,人家絕不以為它比鷦鷯唱得更美。多少事情因為逢到有利的環境,才能達到盡善的境界,博得一聲恰當的讚賞。
----莎士比亞

黑暗無論怎樣悠長,白晝總會到來。 世界上還沒有一個方法,可以從一個人的臉上探察他的居心。
---莎士比亞

要是你做了獅子,狐狸會來欺騙你:
要是你做了羔羊,狐狸會來吃了你;
要是你做了狐狸,萬一騙子向你告發,獅子會對你起疑心;
要是你做了騙子,你的愚蠢將使你受苦,而且你也不免做豺狼的一頓早餐…… ---莎士比亞

魔鬼為了陷害我們起見,往往故意向我們說真話,在小事情上取得我們的信任,然後我們在重要的關頭便會墮入他的圈套。 ---莎士比亞

沒有什麼事是好的或壞的,但思想卻使其中有所不同。 ---莎士比亞

如果做好心理準備,一切準備都已經完成。 ---莎士比亞

你還能說『苦啊,最苦沒有了』你的苦,還不曾苦到底呢。 ---莎士比亞

天啊,男人不變心,他就是十全十美了。 ---莎士比亞
莎士比亞說:分手後,不可以做朋友,因為彼此傷害過。也不可以做敵人,因為彼此相愛過。

戀愛過的人,都覺得要不傷害多,要不愛的成分多。沒有兩個戀愛過的人還能作朋友。就相當於你丟了的歲月永遠也找不回一樣,愛情就是一種歲月 。把握好每一個進行時。別老想過去時。可以 設計一下將來時。

時間會刺破青春表面的彩飾,會在美人的額上掘深溝淺槽;會吃掉稀世之珍!天生麗質,什麼都逃不過他那橫掃的鐮刀。 —— 莎士比亞

多聽,少說,接受每一個人的責難,但是保留你的最後裁決。 —— 莎士比亞

不良的習慣會隨時阻礙你走向成名、獲利和享樂的路上去。 —— 莎士比亞

青春是一個短暫的美夢,當你醒來時,它早已消失無蹤。 ----莎士比亞

母羊要是聽不見她自己小羊的啼聲,她決不會回答一頭小牛的叫喊。 ---莎士比亞

1,愛情是嘆息吹起的一陣煙,戀人眼中有它淨化了的火星;戀人的眼淚是它激起的波濤,它有是最智慧的瘋狂,哽喉的苦味,沁舌的蜜糖

2,愛情不是花陰下的甜言,不是桃花源中的蜜語,不是輕綿的眼淚
更不是死硬的強迫,愛情是建立在共同上的基礎上的。

3,莎士比亞曾說過;TO BE OR NOT TO BE that is a question

4,Shakes beare 說;命運掌握在自己手裡!如果『受制於人』那麼錯不在命運『而在與我們自己』!

5,愛,和炭相同,燒起來,得想辦法叫它冷卻。
讓它任意著,那就要把一顆心燒焦。

6,要和一個男人相處的快樂,你應該多多瞭解他而不必太愛他,
要和一個女人相處的快樂,你應該多愛她,卻別想要瞭解她。

7,因為她生的美麗,所以被男人追求;因為她是女人,所以被男人俘獲。

8,我承認天底下再沒有比愛情的懲罰更痛苦的,
也沒有比服侍它更快樂的事了。

9,今天我要收回對你的全部的愛,因為我要慷慨地再給你一次。
忠誠的愛情充溢在我的心裡,我無法估計自己享有的財富。

10,如果女性因為感情而嫉妒起來那是很可怕的。

11,一個驕傲的人,結果總是在驕傲裡毀滅了自己。

12,草率的婚姻少美滿。

13,愛是一種甜蜜的痛苦,真誠的愛情永不是一條平坦的道路的。

14,我想愛情這東西只有自己體會才有所成功才!
兩個人誰也不瞭解對方才能有更美滿的婚姻!只有慢慢體會和發現才能過一生!!!

15,愛情從一誕生起,直到今天我們也沒有搞清楚愛一個人需要理由嗎?不需要嗎?需要嗎?不需要嗎?。。。。。。

倘若沒有理智,感情就會把我們弄得精疲力盡,正是為了制止感情的荒唐,才需要理智。

莎士比亞說:沒有身體的摩擦哪有愛情的火花!

真正的愛情是不能用言語表達的,行為才是忠心的最好說明

2010年11月18日 星期四

有關測焦 移焦 與 DIY調焦相關文章

APS-C片幅的機身...本身片幅小
所以每個對焦點的AF對焦感應器...相對的面積也比較小

所以APS-C機身有個無解的對焦問題
即使很準的機身與鏡頭
當用廣角焦段拍攝時...大約是50mm以下
近距離拍攝..對焦都很準

當距離拉遠到... 1.5~2公尺以上時
因為廣角 + 對焦距離拉遠 = 對焦物體變得很小
導致投射在很小的對焦改應器上面..更難分辨對焦
產生對焦精準度下滑的問題....常常都會對到後面的牆壁去

原文: http://www.ldsclub.net/forum/viewthread.php?tid=27845&highlight=

2010年11月15日 星期一

他馬的!趕羚羊!

他馬的!趕羚羊!LP! 國民黨盡出「羶」字經
2007年 10月 04日 12:03 ╱ 壹蘋果網絡

「羶」字經還真「煽」
高 雄市議會國民黨團在愛河邊高掛挺馬廣告「他,馬的」就是愛台灣,引起民進黨高雄市議員與高雄市民眾認為相當不雅,國民黨文宣遭批,沒水準!低俗!為了 「他,馬的」這個文宣,國民黨甚至還表示,心中只要沒邪念,所看的就沒有邪念,心中都是髒話的,看到的自然是髒話!其實在之前,國民黨就已經推出許多這種 引人爭議的文宣。

趕羚羊污辱母親
為了反制親綠的地下電台,國民黨在南部架設所謂的「趕羚羊之聲」,以嘲諷民進黨執政當局,不過後 來經過南部鄉親人士的抗議,認為「趕羚羊」這三個字相當不雅,民進黨婦女部也認為「趕羚羊」這三字,根本就是污辱「台灣母親」,經過國民黨文宣部研議後, 再將「趕羚羊」之聲改成為「LP」之聲,國民黨文宣部還表示,國民黨的LP,並非有些人常掛在嘴邊的「LP」。

「LP」蛋糕伺候婦女
為 了「趕羚羊」這三個字,民進黨還率領婦女們到國民黨部抗議,要求國民黨總統參選人馬英九為「趕羚羊」向全台灣母親道歉!為了民進黨婦女部的踢館,國民黨文 傳會甚至還特別訂製「LP」蛋糕,在綠營娘子軍抗議當天,擺出所謂「LP」蛋糕來伺候這些娘子軍,但事後國民黨黨工出面送了一本小王子《Little Prince》(LP),才平和收場。

人像拍攝, 測光

AV模式
1.決定好要拍攝的光圈。
2.將相機中央點移到要拍攝的物體上。
3.半按快門測光,就會得到曝光值;這時候半按快門不放,重新構圖。
   (如果對焦點不在同一個z plane,需要重新對焦,則建議用曝光鎖)
4.構完圖就可以全按快們拍下去。

M模式
1.決定好要拍攝的光圈。
2.將相機中央點移到要拍攝的物體上。
3.根據曝光尺調整想要的曝光值,通常也都是調到中間(除非刻意要曝光過度或是不足)。
4.從新構圖,構完圖就直接按快門拍攝。

至於測光模式,在依實際的場景,切換權衡式測光、局部測光、重點測光、中央偏重平均測光。
一般權衡式測光就足以應付大部分場景,遇到反差過大場景可以考慮用點測光,拍攝夜景部份可以考慮針對光源用局部測光.............這些測光模式多拍幾次,大概就可以體會出他的差別囉。

http://forum.canonfans.biz/forum.php?mod=viewthread&tid=33588&extra=page%3D1



用M模式測光後~~再對焦、構圖~~~
比方說以點測光~~大光圈設定1.4~~~中心點測MD臉的亮部(基本上拍MM就是要臉曝光正常),如所得正確曝光快門為1/400~~~就以此數據拍攝~~~

這時再重新構圖時,此時中心點因為偏離MD臉的亮部,快門即因此增加或減少,不用去在意~~因為臉部的正確曝光值是固定的 (F1.4  1/400S)   當夠好圖~~對好焦~~~喀喳~~~~美女照即完成正確曝光、對焦及構圖~~~

不要太拘限於9個對焦點或一定要大光圈,有時縮光圈是必要的(可參考觀 景窗預覽功能!!)

有時手動對焦是必要的(構圖時MD的眼睛總不可能剛好在9個點上吧!)

大光圈人像拍攝基本法則
http://forum.canonfans.biz/forum.php?mod=viewthread&tid=19540&fromuid=37114

2010年11月14日 星期日

為什麼不能「幹」、不能「卵葩」?/馬非白

撲浪上流行把「幹」字以注音寫成「ㄍㄢ四聲」來代替,其中所代表的現象除了網路文化之外,應該還有心靈禁錮的問題,值得討論。

中國黨殖民統治集團洗腦成功,他們貶低台語,你們也跟著認為台語罵人是下流,連個幹都要用注音的;他們可以說他媽的,台灣人為什麼不能罵幹?

他們說「扶卵葩」沒水準,你們就用英文諧音代表。如果陰莖、睪丸、陰囊是醫學名詞,為什麼台語的「卵葩」就不是醫學名詞,就是髒話?為什麼就要不好意思用台語說?眾多台灣人顯然需要進一步改造。

「卵葩」不是髒話,「幹」也不是髒話。中國黨殖民統治集團利用貶低文化語言的手法,遂行其殖民統治的目的。台灣人在這種文化語言束縛的箝制下,全都成了順民,這種文化語言的歧視甚至升高為無可違背的道德束縛,因而人人都變得卑下不知自己的尊嚴何在。

台灣人始終不了解這個深層的心靈禁錮,因此,奮鬥了幾十年還在原地繞圈子。

原文出處 http://www.news100.tw/modules/news/article.php?storyid=644

2010年11月13日 星期六

超短焦投影機/60公分可投百吋畫面 可隔空書寫

超短焦投影機/60公分可投百吋畫面 可隔空書寫

更新日期:2010/11/10 04:11
自由時報記者陳炳宏/台北報導〕全球DLP投影機賣得最好的明基(BenQ)又出奇招了,不但推出可隔空書寫的電子白板,還推出超短焦投影機,只要六十公分距離,就可投出一百吋大畫面。
為搶攻教育市場,明碁公司特別研發出PointDraw技術,在電腦執行「Q Draw」軟體後,所連接的投影畫面中會有暗藏的編碼,讓互動筆的鏡頭感應出筆頭所指的位置,投影的畫面搖身變成電子白板,互動筆可以隔空書寫、塗鴉、換顏色。
優點是不用事先以互動筆定位螢幕的大小,即可開始教學,且上課的小朋友,只要拿到互動筆,即可隔空書寫老師要求的答案。
明 碁也研發出網路投影機技術,透過「Q Presenter」軟體,設定好帳號密碼,遠端教室的投影機即可連線到辦公室的電腦,老師不用抱著電腦在校園裡奔波;利用短焦投影的特性,投影機固定在 講台上方,不但不會擋到同學視線,老師眼睛也不會被投影機的強光射成「青冥俠」,設計相當貼心。

2010年11月11日 星期四

typedef 知多少?

《教學》typedef 知多少?
很多寫 C/C++ 的人都把 typedef 當成#define 來使用。
誠然,像這樣的定義
typedef unsigned short WORD;
就相當於
#define WORD unsigned short
但就本義來說,#define 是字串的取代,例如
#define WORD Hello!
編譯器不會有任何的抗議就通過的,在程式任何使用到 WORD 的地方
編譯器會忠實的用 Hello! 取代 WORD

由於取代的字串可不限於一行且可代入參數,所以#define 可用於 Macro 的定義如
#define max(a,b) (((a) > (b)) ? (a) : (b))

回過頭來說typedef主題,從本義來說typedef是 C/C++ 型態的別名
所以若你想把
#define WORD Hello!
套在 typedef 的身上:
typedef Hello! WORD;
那麼編譯器會給你一個難堪錯誤訊息!因為 Hello! 不是一個合法的
型態,你不能為它取型態別名。

typedef看來不怎麼有用是吧!?非也,由於所謂 C/C++ 的型態是很廣義的,使用typedef
可以使程式看起來簡潔易懂且不容易出錯。下面是幾個typedef的應用例子:

簡單型態的別名
typedef unsigned char BYTE;//定義無號單字節的型態
typedef unsigned short WORD;//定義無號雙字節的型態
typedef unsigned long DWORD;//定義無號四字節的型態
//嗯!這三行沒什麼大不了,用#define也可以做

結構型態的別名
typedef struct StructTag{
int mA;
int mB;
}STRUCTTAG, *PSTRUCTTAG;
當要建立這個結構的物件時,就可以用別名 STRUCTTAG 和 PSTRUCTTAG,例如
STRUCTTAG StructObj;
PSTRUCTTAG pStructObj;
就相當於
struct StructTag StructObj;
struct StructTag *pStructObj;

函式型態的別名
如果你有一個 library 提供了字串轉整數的函式
int HexToInt(char *str);//十六進位字串轉整數
int DecToInt(char *str);//十進位字串轉整數
當你的程式要使用這些函式時,就必需include這些函式的定義,但用typedef會
更簡潔:
typedef int ToInt(char *str);
//上面這行定義了一個需傳入字串(char *)且返回整數(int)的函式型態別名
//叫 ToInt
ToInt HexToInt,DecToInt;//宣告HexToInt,DecToInt這兩個函式
現在你的程式可以呼叫HexToInt(...),DecToInt(...)了。

在Windows,通常是應用程式呼叫API來工作的,但由於某種需求,Windows API
會反過來呼叫應用程式的函式,這種函式稱之為 callback function
callback function 對API來說只有該傳入那些參數和返回值型態,沒有函式名稱而用函式
指標來呼叫(事實上Windows也不可能用程式的函式名稱來呼叫)。這時使用函式型態的別名
來宣告函式指標就特別好用了。
舉個例子吧!建立一個新的行程(Thread)的函式:
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc,
LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT
nStackSize = 0, DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

其中AFX_THREADPROC就是一個函式型態的別名
它的定義是
typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID);
//AFX_THREADPROC 是一個傳入一個指標參數返回UINT型態值的函式
//指標的名稱(AFX_CDEL是標明函式呼叫為 __cdecl(C style calling convention))

用這個宣告,不論API或應用程式本身都很方便,如應用程式可以這樣來
開啟行程:
CWinThread* pMyThread=AfxBeginThread(
(AFX_THREADPROC)MyThreadFunc,............
是不是很簡潔明瞭?嗯...MyThreadFunc算不算 callback function 有點疑義,但做為 typedef 的使用例子應沒問題的








 


原文引用:http://ehome.hifly.to/showthread.php?postid=332

洪蘭:別急,沒有「輸在起跑點」這回事

洪蘭:別急,沒有「輸在起跑點」這回事


好 幾位媽媽向我抱怨說放暑假反而比開學時更忙,每天忙著接送孩子上腦力開發班、潛能開發班、才藝班,接接送送,孩子還不感激,整天扳個臭臉給他們看。我問她 們何苦來哉,她們異口同聲說怕沒有及時找出孩子潛能,誤了他的前途,讓他輸在起跑點上。我聽了很詫異。這裡面有好幾個迷思。
巴特康納(Bart Conner)是一九八四年奧運美國男子體操第一面金牌的得主。他小時候並沒有什麼特別,有一次在家裡頑皮,倒立用手走路,他爸爸看見了,覺得很有趣,客 人來時,便叫他出來表演,這一點的鼓勵就使得他在家勤練倒立,用手上下樓梯。在學校裡,男生都希望引起女生注意,他沒有別的特長,便常在教室中耍寶、倒立 行走。有一天被體育老師看到了,覺得他有天份,便帶他去參觀體操訓練中心。他一眼看到平行桿、單桿和木馬就知道這是他將來安身立命的地方,便回家懇求母親 讓他去練體操,那天他十歲。
一開始,教練不收他,嫌他彈性不夠、骨頭不夠柔軟,但是他鍥而不捨的苦練,終於替美國拿到第一面男子體操的金牌(他的太太是一九八四年奧運羅馬尼亞女子體操金牌的Nadia Comaneci)。巴特自己說「一分天才、九分努力」,他是苦練出來的。
任何領域要成名都得下苦功,孩子如果有莫札特的能力,我們給他莫札特的環境,他會成為莫札特。他如果有莫札特的能力,但是沒有莫札特的環境,「生命自己會 找出路」,他的過程會坎坷,但是他還是會成為莫札特。我們最怕的是孩子不是莫札特,而我們一定要他變成莫札特,這時親子雙方都很痛苦:父母會很失望,覺得 孩子是扶不起的阿斗,孩子會很痛苦,知道自己達不到父母的標準。巴特的例子讓我們看到適性發展加上一點點的肯定,可以有很大的成就。
在神經學上沒有「腦力開發」這回事,大腦大約三磅,佔我們體重的百分之二,卻用到我們身體百分之廿的能源,當它用到十倍的能量時,它是不可能只有百分之十 在工作,其餘的百分之九十閒閒沒事幹的。大腦是用進廢退,盲人沒有用他的視覺皮質,在實驗上已發現,盲人在讀點字時,視覺皮質被觸覺徵召過去用了。連把正 常人眼睛矇住五天都會開始改變他的視覺皮質,去做聽覺、觸覺方面的事,大腦怎麼可能放任百分之九十不做事?
在神經學上也沒有「輸在起跑點上」這回事,實驗已找到終身學習的神經機制,一九九九年發現管記憶的海馬迴的神經細胞會長出新的神經元來,大腦不停因外界需求而改變內在神經迴路的連接。
教養孩子是順其天性即可,柳宗元說的好,「其根欲舒,其培欲平,其土欲故,其築欲密」,種下去了,不要時時挖起來看,耐心等待,它自然以茂盛的果實來回報你。
(作者為中央大學 認知神經科學研究所所長)

黃進明 《現代脈診圖譜學》

吳清忠 《人體使用手冊》
潘同菋 《解碼中醫》

藍委承認當初反軍購都是在玩政治

楊甦棣:藍委承認當初反軍購都是在玩政治
2009-06-26 16:03:42 中廣 董媛瑜
 
 
 
  美國在台協會AIT台北辦事處處長楊甦棣即將卸任,楊甦棣今天表示,在「台灣關係法」下,台美關係仍舊穩固,美國樂見台灣與大陸改善關係,也會持續與台灣合作、確保台灣的安全。
楊甦棣並說,讓台灣「不成熟的民主」能夠持續茁壯成長,是台美雙方人民共同的心願。

楊甦棣表示,在台灣關係法下,台美關係依舊穩固,日前AIT內湖新址的揭示典禮,就是再一次重新確認台美間的深厚友誼。
楊甦棣說,即使現在全世界經濟衰退,但台美經濟合作關係緊密,深信以台美經濟上相輔相成的關係,未來一定能繼續走下去。
而在兩岸關係方面,楊甦棣指出,華府與台灣美國商會都明確表示,馬總統在兩岸關係上的和解,是他們所樂見其成的,而台灣關係法的精神下,美國會持續與台灣合作、確保台灣的安全,讓台灣可以放心,去追尋跟中國這個強大的鄰國之間的進一步互動關係。
楊甦棣並說,讓台灣這個「不成熟的民主」能夠持續茁壯成長,也是雙方人民共同的心願。

而在對台軍售方面,楊甦棣表示,在台灣關係法架構下,美國總統歐巴馬上任後,對台軍售想法至今未有改變,即使兩岸關係和緩,但美國也理解中國不斷提升軍事實力,包括持續對台灣佈署飛彈,歐巴馬政府會考量種種情況,思考台灣需要何種防衛性武器,並於恰當時機公布。
楊甦棣並且透露說,雖然他過去催促立法院通過軍購預算,造成國民黨立委的反彈,但國民黨黨團高層日前已向他表示,他們的反彈是不該的,當初會那麼做是因為「政治就這麼在玩的」。

OnTimer是否沒有返回而重複執行

看到一篇blog,http://blog.pfan.cn/yuqiexing/40732.html
/////////////////
CxxxDlg::OnTimer(UINT nIDEvent)
{
  static int i = 0,j;
  j = i++;
  if (i==2) KillTimer(nIDEvent);
  MessageBox("!");
  i++;
  CString str;
  str.Format("%d,%d ",j,i);
  ::OutputDebugString(str);
}
以上代碼在執行的時候,會彈出2個messagebox。很多人都有1個疑問,那就是當第一個消息框彈出的時候,應該相當於是模態對話框,怎麼還會第二次進入OnTimer,並且再次彈出messagebox?
他的解釋是:
原來,當你在主消息循環的消息處理函數中彈出一個模態對話框,他阻塞了主消息循環,理論上,這時可以把主窗口關閉了!但是因為這個彈出的模態對話框還在, 它阻塞了winmain這個主消息循環,實際上你是關不掉的。注意,阻塞的實際意思是說:消息被模態對話框處理了,而沒有傳到後面的父窗口。而每次彈出對 話框,都是由最上層的那個消息框掌握著消息循環,其他的消息循環被阻塞了。

      所以,上面代碼運行的情況是:

(1)彈出第一個messagebox,然後後續代碼暫停執行。

(2)第二次進入OnTimer

(3)彈出第二個messagebox接替消息循環,第一個messagebox禁用。後續代碼暫停執行。

(4)用戶點擊第二個messagebox。此時顯示結果,i = 3,j=1;再次,點擊第一個messagebox,此時顯示結果,i=4 ; j=0
(測試顯示應該是: i =4, j=1);


我的疑問,當彈出第一個messagebox後,主消息循環被阻塞,OnTimer中後續代碼暫停執行,也就是說OnTimer沒有返回,是這樣嗎?那麼 怎麼能夠第二次進入OnTimer呢?這樣的話一個函數還沒有返回又第二次進入執行,有可能造成衝突啊,事實上的確是第二次進入OnTimer了。

以上說明:OnTimer沒有返回時,間隔時間到,可以重複進入該函數。又做了個測試
double fun(double i)//執行時間較長,大於100ms
{
double t = 1;
for(;i <100000000;i++)
{
t = t*i/(i+1);
}
return t;
}

void CMainFrame::OnTimer(UINT nIDEvent)
{
static double i=0,j=0;
fun(i);
j++;
if(j == 0)
{
MessageBox("jjjjjjjjjjjjjjjjjjjjjjjjjj");
}
CFrameWnd::OnTimer(nIDEvent);
}
在主窗口初始化時定義定時器

SetTimer(1,100,NULL);

結果沒有任何messagebox輸出;

也就是說在fun()正在執行,沒有返回時,間隔時間到,並沒有再次進入OnTimer(),而是一直等到fun()返回[b]。[/b]
這個和前一個測試有什麼區別?為什麼能導致不同的結果呢?

---------------------------------------------------------------------
樓主首先要明白,第二次進入OnTimer不需要在第一次退出OnTimer後才能發生,函數重入是非常常見的事情,尤其是有模態對話框的情況,wltg解釋的很好,希望你能懂
引用 6 樓 wltg2001 的回覆:
也就是說OnTimer沒有返回,是這樣嗎?那麼怎麼能夠第二次進入OnTimer呢?
======================
最主要的原因是MessageBox是模態對話框,而模態對話框內部是有消息循環的,當第一個MessageBox彈出時,由於模態對話框內部有消息循環,所以定時器消息還是可以被處理.
你的第一個例子,消息處理程序是阻塞在MessageBox上的,因為MessageBox內部有消息循環,所以消息還是可以被處理的.第二個例子卻是阻塞在fun()上,在這個函數內部卻沒有消息循環,當然要等它做完能繼續下去了.

C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較

http://www.cppblog.com/lingjingqiu/archive/2009/01/06/71363.html
最近用了一段時間的wxWidgets。
基本上主流的界面庫也就算用的差不多了。
這裡拿一個表格對這些界面庫做一個比較直觀的比較。

界面庫名稱 接口設計 界面編輯器 高級佈局功能 平面繪製 平台兼容性 語言支持 IDE兼容性 視圖-模型分離機制 運行時 其它
Windows Forms 接口優秀。C++下使用CLI擴展,其它語言為原生支持。 界面編輯器完整,包括佈局、屬性、消息關聯的完整設置。不可預覽。 Table Layout,Splitter Layout,Flow Layout等,Anchor和Dock機制。多分辨率界面下表現良好。 GDI+,面向對象的2D繪製接口,使用簡便。 需要.Net平台支持。WIndows或Linux(Mono,非官方支持),支持Windows CE C++/CLI, 支持.net的語言。 僅VS。 佈局和視圖方案建立在代碼中。部分組件支持Model-View架構。 需要部署對應的.net 商業協議
MFC 基於宏和虛函數,使用特殊格式註釋,使用自定義的RTTI系統。類接口設計優良。通過回調函數和虛繼承重載調用客戶代碼。 基於資源編輯器,僅能對空間基本佈局和少量屬性進行調整。不可預覽。 缺乏高級佈局功能,多分辨率需要是手工或程序中調整。 GDI及GDI封裝,可選GDI+ Windows,Windows CE C++ Only,
支持COM時可以實現Binary級別復用。
僅Visual Studio 使用資源保存控件的基本控件佈局,提供Doc-View機制和控件數據交換支持視圖分離。 需要部署MFC運行時庫。 商業協議
WTL 基於模板和虛函數。類接口類似於MFC。需要使用多重繼承。通過模板特化和回調函數與客戶代碼交互。 同MFC 同MFC 同MFC 同MFC 同MFC,對COM的支持比MFC完善很多。 Visual Studio,Windows下支持標準的C++編譯器。 使用資源文件保存空間佈局。 自由協議
wxWidget 宏,自定義RTTI。使用回調函數與用戶代碼交互。 無官方界面編輯器。可使用第三方界面編輯器。部分編輯器具有完整的所見即所得功能,且具有預覽能力。 使用Sizer實現多分辨率的佈局。功能偏弱。 wxDC等。 Windows,Linux,Unix,MacOS等 C++, .NET, Python,
Lua,
Ruby等
良好的編譯器兼容性,缺乏IDE繼承。 可以將界面屬性生成到代碼中,也可以使用XML格式保存。 wx的動態鏈接庫或靜態鏈接。 自由協議
Qt 使用宏和自定義的RTTI。使用Singal-Slot機制實現用戶代碼交互。可通過繼承實現擴展。 Qt Designer,具備完整的所見即所得編輯功能。可預覽界面。 具備完整的佈局功能。多分辨率/多平台下表現良好。 QCanvas等。 Windows,Linux,Unix,MacOS等。 C++,Python等 可集成到Eclipse和VS 使用資源文件保存界面信息。部分組件具備Model-View-Delegate架構 qt的動態鏈接庫。 開源協議+商業協議
GTK+ 使用signal-slot機制完成用戶代碼交互。 GLADE,具備所見即所得的界面編輯功能 Layout Containers,具備較完整的佈局能力。 GTK Graphics Context Windows,Linux,Unix,MacOS等。 C,C++,Python,.NET等。 (暫時未知) 使用代碼完成界面設置。部分組件具備Model-View架構。 GTK Runtime 開源協議

此外,除了WTL外,其餘各界面庫均有完整及時的文檔和手冊,因此比較項中不再指明。
回帖中有人指出國際化問題的比較,事實上MS的產品和開源對於國際化的解決方法是不同的。但是都可以比較方便的解決國際化問題。
posted on 2009-01-06 18:09 空明流轉 閱讀(3617) 評論(10)  編輯 收藏 引用



評論



# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-01-06 19:05 qtopia
Nokia 最近推了 Qt Creator,是較好的IDE環境  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-01-06 19:05 t
博主還可以增加一欄「國際化支持」  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較[未登錄] 2009-01-08 12:48 kenlistian
我覺得wxwidget是不錯的選擇。  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-01-11 20:25 www
wxwidget做簡單的還可以, 做複雜的界面,嘿嘿,那就麻煩了. win下還是MFC最爽.  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-01-19 00:49 ArenAK
有沒有哪一個是作者比較喜歡用的呢,及其原因?  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較[未登錄] 2009-01-19 16:35 六水
寫的好~  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-02-05 11:08 空明流轉
@六水
我就知道你是友情贊助的。。。  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較[未登錄] 2009-02-11 22:35 六水
這你也知道?  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-02-25 10:19 aladdina
wxWidgets的代碼質量不是很高,有一些比較初級的bug。我用過一段時間的wxWidgets,自己測試沒問題,但是用戶總會發回一些crash report。

另外,wxWidgets和Qt除了對於一些常見應用,比如窗口、DC的封裝之外,還提供了很多系統接口的封裝,比如clipboard, thread, socket等。

Qt有Qt Creator作為IDE,工程項目文件可以跨平台,另外,工程文件也可以用qmake轉成平台無關的makefile。準備最近有空試試Qt,個人覺得商業代碼質量還是要稍微好一些。

  回覆  更多評論

# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方綜合比較 2009-09-18 12:09 idol
gtk 哪有 signal-slot機制,用的明明是 callbacks

WTL---WxWidget---MFC 何去何從

WTL---WxWidget---MFC 何去何從
C++程序員打交道最多的就是MFC了,這個我不想多說,說來都是淚(C#年年更新,C++十年才出了一個featurePack還不是很好用)

現在另外兩支隊伍越來越龐大(所謂窮則思變,呵呵),一是WTL,關於它的種種傳說可以參考WTL中文教程,裡面講的很詳細,這裡我想說的是為什麼使用WTL:
傳 說WTL是微軟內部所使用的界面框架程序,原因是高效,簡潔,實際也是如此,WTL的程序內的內存佔用比MFC小的多,而且WTL內建了對於可縮放對話框 的支持(支持控件停靠哦),對於多文檔以及視類的支持更是MFC望塵莫及的,但是WTL也有其自身的缺點,比如開發文檔少,尤其是中文的,嚮導不夠聰明 (誰用誰知道,呵呵),換句話說,用WTL就意味著多敲一些代碼,不過這個可以有一些第三方工具緩解(還是那句話,窮則思變),如WTL helper,還有國產的WTL helper,還有國產的VFC,兩者都是開源軟件,放心使用,建議有意開發WTL的程序員先打好基本功,因為這個基於ATL的這個鐵娘子不是誰都可以駕馭的哦,如果對程序大小要求不是太苛刻的話,還是拿MFC將就吧

其二就是我最近很感興趣的WxWidget, 這款框架最大的優勢就是真正意義上的跨平台,其注意真正兩個字,因為在我看來所謂的java跨平台不過是幌子,有種連JVM也跨平台試試(JAVA擁護者 別拍我哦,其實JAVA還是在OO領域很強大的),那真正二字就是因為,WxWidget提供了在本機源碼級的跨平台,從此你在讓客戶使用你軟件的時候不 必再說:「你必須給我安裝×××虛擬機或×××Framwork」,在一個平台下編譯的代碼,不用做任何更改,在另一個平台下就可以編譯通過並且發佈,這 豈不美哉,而且WxWidget所使用的界面元素幾乎都取自本地計算機,就是說你的見面客氣來很有親和力,最終發佈的二進制代碼文件愛你無論是靜態還是動 態鏈接都要比GTK之流小很多(見圖表)。有興趣一試的可以看看WxWidget開發環境配置



說了這麼多,總結如下,三種平台各有所長,如果你是windows程序員,那麼WxWidget對你而言沒有多大意義,如果你剛開始接觸C++,那WTL這個高品位新娘也許會讓你忙的團團轉,呵呵,大家自己斟酌吧
posted on 2008-12-21 22:13 pear_li 閱讀(3381) 評論(22)  編輯 收藏 引用 所屬分類: C++


評論


# re: WTL---WxWidget---MFC 何去何從 2008-12-22 09:14 路人丁

樓主還搞不清VC++和C++?
「C++程序員打交道最多的就是MFC了……C++十年才出了一個featurePack還不是很好用」應該改為「VC++程序員打交道最多的就是MFC了……VC++十年才出了一個featurePack還不是很好用」
  回覆  更多評論    

# re: WTL---WxWidget---MFC 何去何從 2008-12-22 09:21 路人乙

和路人丁有同感,樓主說的只是VC或MFC這範圍的C++程序員,
我個人感覺做得比較好的C++庫,是QT、ACE。
QT與wxWidget等四類GUI庫作過比較,贏得過最佳設計與最具表達力的稱號。

# re: WTL---WxWidget---MFC 何去何從[未登錄] 2008-12-22 10:30 momor

QT固然好,除非你做開源,不然你沒看過QTwindow上開發的商業授權費用是多少。另外大家也不要過於對字眼上太過敏感,畢竟我們是程序員不是搞文字工作的,基本從事windows平台的程序員比較多,當然MFC這種現成的東西接觸自然比較多了。
我最近也在弄wxWidgets的東西^^

知名 GUI lib 簡評 (GTK+, Qt, wxWidgets)

GTK+

GTK+ 主要用在 X Window 上,入門門檻較高
特色是,他用不具有物件功能的純"C" 語言,模擬物件導向。 所以寫起來比較複雜艱澀,而且充滿大量巨集,使用和除錯都不是很容易,但優點則是可以用 C,不需 C++,如果和 Win32 SDK 比較,不會難學多少,缺點是不易上手使用,而且文件比較缺,架構又非常複雜,且提供的東西比起其他無所不包的 library,是簡陋了一點,函數命名又臭又長。 對於簡單的程式,GTK+ 會顯得太複雜,但是當你開始想擴充其他 library 也都沒提供的進階功能,就會開始讚嘆GTK+ 的架構嚴謹,還有超乎想像的高度彈性。 同樣的東西要用 MFC 來做反而會要人命並且多國語言的支援良好,內部也全面使用 UTF-8,相容性好,又是 unicode能夠習慣的話,GTK+ 值得推薦,但沒有很建議學,畢竟不好學,要用到熟會需要比較久,而且那樣很多 C++ 的功能會用不到。 GTK+ 有 C++ 版本叫做 GTK--,沒用過但看文件覺得,並沒有比 gtk+ 簡單到哪裡去。 因為 gtk+ 本來就是物件導向,所以即使換了 c++ 語言,寫起來架構還是差不多的。 另外,gtk+ 有 Windows 版本,但缺點是,執行緩慢,不穩定,而且介面是使用 gtk+ 自己的,不是使用 Windows 內建的"Native" 原生圖形介面,看起來會不太習慣。 Mac OS X 下可用 X11 來執行 gtk+但那樣出來的程式是長得像 UNIX 程式,而不是美美的 OS X Aqua 外觀

wxWidgets 和 MFC 最接近, 命名習慣或架構都高度相似,會 MFC 幾乎不用重新學習有十餘年歷史,此外,他的物件封裝比 MFC 要好,提供的功能也多上太多,又跨平台一般知名的 MFC 程式都會選擇用 wxWidgets 改寫,來快速移植原程式到其他平台例如 eMule 用 wxWidgets 移植出 aMule, xMule, 還在開發中的 Filezilla 3...等

而他最主要的特色是,他是"跨平台"的 "Native" GUI toolkit在各種平台上都可寫出使用該平台內建 Native 原生圖形介面的程式。 在 Windows 上就長得跟其他 Windows程式一樣,在 Linux 下就使用 gtk+ 的圖形介面,在 Mac OS X 下就可以使用華麗的Aqua 外觀風格,這點是非常強悍。 不像 gtk+ 到其他系統都還是只能用 gtk+ 自己的缺點是,中文支援在有些地方會出問題,例如剪貼簿的操作。 得自己 patch但仍然相當推薦,即使是個龐大的 library,效能依舊不會太差,尤其在Windows 上執行速度並不輸 MFC,與其學 MFC,不如學 wxWidgets。



Qt
的功能,應該是這三者加上 MFC 之中最強大的,文件也很完整,又有 RAD 工具可以輔助開發,並且有商業公司做強力後盾。不但有 Windows/X Window/Mac 版本,甚至還有嵌入式系統可用的版本,穩定性還不錯,物件封裝也算良好,資源比 GTK+ 或wxWidgets 多得非常多,而且發行公司提供了相當多範例,算是一家以開放原始碼成功營利的模範公司。 知名的 KDE 整個是用他開發,證明了他的穩定性和強大功能。

缺點是如果你用他開發非 GPL 開放程式碼的軟體,必須以極昂貴的金額,購買商業版本。 而他的圖形介面並不完全是 "Native GUI",只是透過 theme 去模擬系統上的標準 GUI,所以看起來很像,卻會有些地方可以明顯看出破綻。 執行速度緩慢還有過於龐大則是另一個問題。 雖然封裝得很良好文件也齊全,並不代表他就很容易學還有一個嚴重問題是,他寫的不是標準 C++,他使用的 signal/slot 機制必須透過 Qt提供的 preprocessor 處理過才可以轉送給編譯器,這部份可能被限定用 qmake,算是一個可惜的地方,不過瑕不掩瑜,還是很推薦。忘了說,他內部也是 unicode,多國語言沒問題。

Unicode, MBCS and Generic text mappings

http://www.codeproject.com/KB/cpp/unicode.aspx

Unicode, MBCS and Generic text mappings

By Chris Maunder

Introduction

In order to allow your programs to be used in international markets it is worth making your application Unicode or MBCS aware. The Unicode character set is a "wide character" (2 bytes per character) set that contains every character available in every language, including all technical symbols and special publishing characters. Multibyte character set (MBCS) uses either 1 or 2 bytes per character and is used for character sets that contain large numbers of different characters (eg Asian language character sets).
Which character set you use depends on the language and the operating system. Unicode requires more space than MBCS since each character is 2 bytes. It is also faster than MBCS and is used by Windows NT as standard, so non-Unicode strings passed to and from the operating system must be translated, incurring overhead. However, Unicode is not supported on Win95 and so MBCS may be a better choice in this situation. Note that if you wish to develop applications in the Windows CE environment then all applications must be compiled in Unicode.

Using MBCS or Unicode

The best way to use Unicode or MBCS - or indeed even ASCII - in your programs is to use the generic text mapping macros provided by Visual C++. That way you can simply use a single define to swap between Unicode, MBCS and ASCII without having to do any recoding.
To use MBCS or Unicode you need only define either _MBCS or _UNICODE in your project. For Unicode you will also need to specify the entry point symbol in your Project settings as wWinMainCRTStartup. Please note that if both _MBCS and _UNICODE are defined then the result will be unpredictable.
Adjusting your project settings

Generic Text mappings and portable functions

The generic text mappings replace the standard char or LPSTR types with generic TCHAR or LPTSTR macros. These macros will map to different types and functions depending on whether you have compiled with Unicode or MBCS (or neither) defined. The simplest way to use the TCHAR type is to use the CString class - it is extremely flexible and does most of the work for you.
In conjunction with the generic character type, there is a set of generic string manipulation functions prefixed by _tcs. For instance, instead of using the strrev function in your code, you should use the _tcsrev function which will map to the correct function depending on which character set you have compiled for. The table below demonstrates:
#define Compiled Version Example
_UNICODE Unicode (wide-character) _tcsrev maps to _wcsrev
_MBCS Multibyte-character _tcsrev maps to _mbsrev
None (the default: neither _UNICODE nor _MBCS defined) SBCS (ASCII) _tcsrev maps to strrev
Each str* function has a corresponding tcs* function that should be used instead. See the TCHAR.H file for all the mapping and macros that are available. Just look up the online help for the string function in question in order to find the equivalent portable function.
Note: Do not use the str* family of functions with Unicode strings, since Unicode strings are likely to contain embedded null bytes.
The next important point is that each literal string should be enclosed by the TEXT() (or _T()) macro. This macro prepends a "L" in front of literal strings if the project is being compiled in Unicode, or does nothing if MBCS or ASCII is being used. For instance, the string _T("Hello") will be interpreted as "Hello" in MBCS or ASCII, and L"Hello" in Unicode. If you are working in Unicode and do not use the _T() macro, you may get compiler warnings.
Note that you can use ASCII and Unicode within the same program, but not within the same string.
All MFC functions except for database class member functions are Unicode aware. This is because many database drivers themselves do not handle Unicode, and so there was no point in writing Unicode aware MFC classes to wrap these drivers.

Converting between Generic types and ASCII

ATL provides a bunch of very useful macros for converting between different character format. The basic form of these macros is X2Y(), where X is the source format. Possible conversion formats are shown in the following table.
String Type Abbreviation
ASCII (LPSTR) A
WIDE (LPWSTR) W
OLE (LPOLESTR) OLE
Generic (LPTSTR) T
Const C
Thus, A2W converts an LPSTR to an LPWSTR, OLE2T converts an LPOLESTR to an LPTSTR, and so on.
There are also const forms (denoted by a C) that convert to a const string. For instance, A2CT converts from LPSTR to LPCTSTR.
When using the string conversion macros you need to include the USES_CONVERSION macro at the beginning of your function:
Collapse
void foo(LPSTR lpsz)
{
   USES_CONVERSION;
   
   ...
   LPTSTR szGeneric = A2T(lpsz)
   // Do something with szGeneric
   ...
}
Two caveats on using the conversion macros:
  1. Never use the conversion macros inside a tight loop. This will cause a lot of memory to be allocated each time the conversion is performed, and will result in slow code. Better to perform the conversion outside the loop and pass the converted value into the loop.

  2. Never return the result of the macros directly from a function, unless the return value implies making a copy of the data before returning. For instance, if you have a function that returns an LPOLESTR, then do not do the following:
    Collapse
    LPTSTR BadReturn(LPSTR lpsz)
    {
        USES_CONVERSION;
        // do something
        return A2T(lpsz);
    }
    Instead, you should return the value as a CString, which would imply a copy of the string would be made before the function returns:
    Collapse
    CString GoodReturn(LPSTR lpsz)
    {
        USES_CONVERSION;
        // do something
        return A2T(lpsz);
    }

Tips and Traps

The TRACE statement

The TRACE macros have a few cousins - namely the TRACE0, TRACE1, TRACE2 and TRACE3 macros. These macros allow you to specify a format string (as in the normal TRACE macro), and either 0,1,2 or 3 parameters, without the need to enclose your literal format string in the _T() macro. For instance,
Collapse
TRACE(_T("This is trace statement number %d\n"), 1);
can be written
Collapse
TRACE1("This is trace statement number %d\n", 1);

Viewing Unicode strings in the debugger

If you are using Unicode in your applciation and wish to view Unicode strings in the debugger, then you will need to go to Tools | Options | Debug and click on "Display Unicode Strings".

The Length of strings

Be careful when performing operations that depend on the size or length of a string. For instance, CString::GetLength returns the number of characters in a string, NOT the size in bytes. If you were to write the string to a CArchive object, then you would need to multiply the length of the string by the size of each character in the string to get the number of bytes to write:
Collapse
CString str = _T("Hello, World");
archive.Write( str, str.GetLength( ) * sizeof( TCHAR ) ); 

Reading and Writing ASCII text files

If you are using Unicode or MBCS then you need to be careful when writing ASCII files. The safest and easiest way to write text files is to use the CStdioFile class provided with MFC. Just use the CString class and the ReadString and WriteString member functions and nothing should go wrong. However, if you need to use the CFile class and it's associated Read and Write functions, then if you use the following code:
Collapse
CFile file(...); 
CString str = _T("This is some text"); 
file.Write( str, (str.GetLength()+1) * sizeof( TCHAR ) ); 
instead of
Collapse
CStdioFile file(...); 
CString str = _T("This is some text"); 
file.WriteString(str); 
then the results will be Significantly different. The two lines of text below are from a file created using the first and second code snippets respectively:
Unicode strings
(This text was viewed using WordPad)

Not all structures use the generic text mappings

For instance, the CHARFORMAT structure, if the RichEditControl version is less than 2.0, uses a char[] for the szFaceName field, instead of a TCHAR as would be expected. You must be careful not to blindly change "..." to _T("...") without first checking. In this case, you would probably need to convert from TCHAR to char before copying any data to the szFaceName field.

Copying text to the Clipboard

This is one area where you may need to use ASCII and Unicode in the same program, since the CF_TEXT format for the clipboard uses ASCII only. NT systems have the option of the CF_UNICODETEXT if you wish to use Unicode on the clipboard.

Installing the Unicode MFC libraries

The Unicode versions of the MFC libraries are not copied to your hard drive unless you select them during a Custom installation. They are not copied during other types of installation. If you attempt to build or run an MFC Unicode application without the MFC Unicode files, you may get errors.
(From the online docs) To copy the files to your hard drive, rerun Setup, choose Custom installation, clear all other components except "Microsoft Foundation Class Libraries," click the Details button, and select both "Static Library for Unicode" and "Shared Library for Unicode."

Writing libraries with Generic-Text-Mapping

http://www.jeffhung.net/blog/articles/jeffhung/522/

Writing libraries with Generic-Text-Mapping

最近在設計某 library 的 API,所以就想順便來講講怎麼設計符合 generic-text-mapping 的 library。簡單講,generic-text-mapping 是一種利用 preprocessor 的技巧,用一個 define symbol 決定 application 程式裡用的 character,是指 char 亦或是 wchar_t。若是後者,就是我們常在說的 unicode 程式。
個人覺得 generic-text-mapping 實在是 Microsoft 當年偷懶後的結果。在那個年代,這個技術確實是讓眾多既存程式快速升級成 unicode 程式的好方法,但在 unicode 支援已經普遍成熟的現在,卻反而形成了脫褲子放屁的尷尬[1]
言歸正傳。尷尬歸尷尬,畢竟我們寫的 library,還是不免需要在 Windows 上執行,讓其他 windows developer 使用,因此入境隨俗,從「惡」如流,還是必須的。如何呼叫使用了 generic-text-mapping 技術的 library,已經有太多文章闡述了[2],因此以下簡述如何寫作 generic-text-mapping 的 library 供他人使用。
同時提供兩個版本,最後才用 macro 選擇
以下的範例程式,採用並擴充 Microsoft 的 convention,後綴字(postfix)為 W 時,表示是 wchar_t 的版本;後綴字為 A 時,表示是 ANSI[3],即 char 的版本;後綴字為 G 時,表示是 Generic 的版本,使用 C++ template 技術寫就;後綴字為 T 時,表示是 explicit generic-text-mapping 的版本,正常來說,generic-text-mapping 的版本無後綴字,但有些時候,我們會需要明確指明其為 generic-text-mapping 的 function[4]
要寫 generic-text-mapping 的 function,我們必須要認清的一點就是,使用我們 library 的程式 (客戶程式,client code),會在 compile-time 的時候,利用我們提供的 macro,自動選擇其中一個版本。因為我們無法確定,client code 會使用哪一個版本,所以我們必須要同時提供 charwchar_t 兩個版本。
這個遲至 client code 的 compile-time 才發揮作用的 macro,存在於提供給 client code 使用的 header file 裡,寫法如下:
int StrToIntA(const char* str);int StrToIntW(const wchar_t* str);#ifdef _UNICODE#   define StrToInt(str) StrToIntW(str)#else#   define StrToInt(str) StrToIntA(str)#endif
這個 macro 很簡單,就是依據 _UNICODE 存在與否,對應到 WA 的版本。後面的文章,筆者就不再重複。
只維護一份程式邏輯
通常來說,我們應該盡可能地讓程式的邏輯,只在一個地方出現,否則,同樣的程式碼有兩份,便會有維護上的麻煩,需得時時確認兩個版本的程式邏輯,是一樣的。
因此,比較好的寫法,是以其中一個版本為主要版本,另外一個版本則即時將參數,轉碼後呼叫主要版本。例如:
bool PathExistA(const char* path){    struct stat sb;    if (stat(path, &sb) == 0) {        return true;    }    else {        switch (errno) {        case ENOENT:            return false;  // no such entry, path not exists        case EACCES:            return true;   // path exists, though we have no right to access it        default:            assert(false); // die for other errors, for demo only        }    }    assert(false); // NOT_REACHED    return false;}

bool PathExistW(const wchar_t* path){    char mbs_path[MAXPATHLEN + 1];    memset(mbs_path, 0, sizeof(mbs_path));    wcstombs(mbs_path, path, sizeof(mbs_path) - 1);    return PathExistA(mbs_path);}
依靠將參數轉碼以便「只維護一份程式邏輯」,有個問題就是,這些「細碎繁多」的轉碼動作,在有些系統上,會造成明顯的執行時間成本。如果速度是很重要的考量的話,您應該小心地調整您的程式的配置方式,盡可能地減少轉碼動作。
另外,不同 OS 所提供的系統 API 也有所不同,好比說 WinNT 是 unicode 核心,若呼叫上例的 PathExistW(), 反而等於是我們自行轉碼後,OS 又會再轉碼回 unicode,多做了無謂的轉碼動作,反而降低了效能。這其實是個兩難的問題,不同的 OS 之系統 API 皆不一樣,WinNT 是 unicode 核心,Win 95/98 是 MBCS 核心,而大部分的 Linux,若 encoding 有影響的話,據我所知,很多都是以 UTF-8 為主。因此,究竟要以哪一種版本為主,端視您的 library 的使用情形而定。
但小心函式行為的正確性
除了效率的問題之外,函式行為的正確性,也應該仔細思量。這點尤其發生在 byte string 與 character string 的差異上。前者是以 byte 為單位所串成的字串,後者則是以 character 為單位所串成的字串。兩者之間,關鍵的差異在於 character 的定義。舉例來說,假使我們用的是 UTF-8,UTF-8 字元的長度,從 1 個 byte 到 6 個 bytes 不等,並非固定是 1 個 byte,因此,strlen(utf8_string) 所抓出來的字串長度,實際上的意義為,「碰到 null byte 前的 byte 數」,而非「碰到 null utf-8 character 前的 character 數。」
所以,若我們要寫計算字串長度的函式,就必須先確定,我們要算的是 character 數,還是 byte 數。如果是要計算 byte 數,而通常來說,一串 byte 我們不會設計成用 null byte 結尾,所以一般我們要算的是 character 數。如此一來,我們應該要把 multi-byte string 先轉碼成 wide-character string,再來使用 wcslen() 計算 character 數,而不能直接使用 strlen() 計算[5],否則會造成函式行為的錯誤。程式寫法如下:
size_t StrLengthW(const wchar_t* str){    return wcslen(str);}

size_t StrLengthA(const char* str){    wchar_t wcs[4096]; // assume big enough, for demo only    memset(wcs, 0, sizeof(wcs));    mbstowcs(wcs, str, ((sizeof(wcs) / sizeof(wcs[0])) - 1));    return StrLengthW(wcs);}
在此例中,我們一改 PathExistW()PathExistA() 為主的作法,改成以 StrLengthW() 為主,為的就是函式行為的正確性。在決定以何者為主,何者為輔時,函式行為的正確性應優先考量,次之才是效率問題。
盡可能地使用系統 API
不過,也有可能,我們的 API 所要提供的功能,有直接的系統 API 對應,且該系統 API 有支援 generic-text-mapping。此時,我們應該盡可能地呼叫系統 API,而捨棄自行轉換(碼)的方式,因為通常這樣執行效率較快。例如:
int StrToIntW(const wchar_t* str){    return _wtoi(str);}

int StrToIntA(const char* str){    return atoi(str);}
由於這樣的函式,通常內容極其簡單,如上例都只有一行而已,故「只維護一份程式邏輯」這句話,我們可以忽略之。
使用 C++ template 自動產生版本
或者,我們寫的是 C++,可以用 template,只寫一份程式邏輯,而讓 compiler 來幫我們自動產生 charwchar_t 的兩個版本。例如:
/** * Find the position of the first occurrence of character @p c in string @p s. * * @param[in] s string to search for @p c * @param[in] c character to search for * @return Returns pointer to the position of the first occurrence of character *         @p c in string @p s.  If character @p c is not found in string @p s, *         returns @c 0. */template <typename CharT>CharT* StrFindCharG(CharT* s, CharT c) // the postfix G stands for Generic.{    while (*s) {        if (*s == c) {            return s;        }        ++s;    }    return 0; // not found.}

wchar_t* StrFindCharW(wchar_t* s, wchar_t c){    return StrFindCharG<wchar_t>(s, c);}

char* StrFindCharA(char* s, char c){    return StrFindCharG<char>(s, c);}
使用 C++ template 確實是比較好的方式,既不會有前述的效率問題,程式邏輯也還是只有一份,沒有 duplicated code 的維護問題。請大家多多投靠 C++ 吧,不要再過茹毛飲血的原始生活了。
使用 C++ template 還有一個好處就是,我們可以利用 specialization、partial specialization 甚至是 policy-based-design 等等技術,僅將會影響效率的部份,予以分開撰寫,而在主要函式裡,維持原本完整的程式邏輯[6]。如此一來,即可兼顧程式的維護性,也可以取得最佳的執行效能,而且這些利用 C++ template 技術所作的 optimization,還可以 reuse 供其他程式使用。
不過,在這裡必須強調的是,通常我們不會讓 template code 露出 DLL 外,因為這樣就失去了使用 DLL 的意義。因此,StrFindCharW()StrFindCharA() 還是有存在的必要,以確保 compiler 有確實產生兩個不同版本的 StrFindCharG()
別忘了 template 產生的是不同的實體,小心 side-effect
但是,正如前面所述,compiler 依據 template 所產生的,是兩份不同的函式實體,因此,我們必須要小心 side-effect 的問題。什麼意思呢?舉例來說,假設我們有個函式,是用來取得 accumulated access count,通常我們會這麼實做:
typedef unsigned int count_t;

count_t GetTagAccessCount(const char* tag){    // lock omitted, for demo only.    static map<string, count_t> tags_count = 0;

    // use map.insert() to ensure the count exist    pair<map<string, count_t>::iterator, bool> r        = tags_count.insert(make_pair(string(tag), 0));    ++(r.first->second);    return (r.first->second);}
但如果配上 generic-text-mapping 的話,char 要代換成 template parameter CharTstring 要代換成使用 CharT 為參數的 basic_string<CharT>,程式就會變成這個樣子:
typedef unsigned int count_t;

template <typename CharT>count_t GetTagAccessCountG(const CharT* tag){    // lock omitted, for demo only.    static map<basic_string<CharT>, count_t> tags_count = 0;

    // use map.insert() to ensure the count exist    pair<map<basic_string<CharT>, count_t>::iterator, bool> r        = tags_count.insert(make_pair(basic_string<CharT>(tag), 0));    ++(r.first->second);    return (r.first->second);}

count_t GetTagAccessCountW(const wchar_t* tag){    return GetTagAccessCountG<wchar_t>(tag);}

count_t GetTagAccessCountA(const char* tag){    return GetTagAccessCountG<char>(tag);}
此時,GetTagAccessCountW()GetTagAccessCountA() 分別 instantiated 各自的 GetTagAccessCountG<>(),template function 裡面的 static 變數 tags_count 便會有兩份。因為 client code 會利用 GetTagAccessCount() 這個 macro 選擇出適用的版本,而我們又無法確保所有的 client code 都是使用 charwchar_t 版本[7],因此他們所使用的 tags_count 是不同的,造成函式的行為錯誤。
碰到這種情況,我們也許必須退而求其次,放棄 template 法,改用「以一個版本為主,另一個版本即時轉碼後呼叫主要版本」的方法來實做。或者,將可能造成 side-effect 的程式片段,以另一個共用的 class 包裝起來之後,讓 template 使用。以我來說,會選擇使用第二種方法,C++ 強大的彈性,不好好利用,實在是太可惜了。
除了程式邏輯只要保留一份就好以外,最好文件也只有一份,但是...
筆者慣用的文件產生工具是 doxygen,doxygen 是一個強大的文件產生工具,讓我們得以使用如 javadoc 的方法,產生 C、C++、Java、PHP、Python、... 等語言的 API 文件。然而,使用 generic-text-mapping 技法時,doxygen 產生的文件,其長相卻不太理想。
理想上,最好是如 MSDN 的作法一般,將 StrLength()StrLengthA()StrLengthW() 甚至是 StrLengthT()StrLengthG() 等函式,集結於同一個頁面描述,並以 StrLength() 為名;至少,要做到把其他版本濾除掉,只做 StrLength() 即可。可是,因為 doxygen 實在是太聰明了,能夠看穿 StrLength() 實際上不是 function,而是 macro,所以我們根本無法把 StrLength() 的文件,作成像 function 一樣,並歸類在 function 類。
我們可以使用 @copydoc[8],讓 StrLengthA() 使用 StrLengthW() 的那一份文件源碼。但是,使 StrLength() 為主,並以 function 的方式呈現,筆者就真的找不到解法了。因此,目前筆者所能想出來的,最好的 doxygen 文件寫法如下:
/** * Count the length of given string @p str, in number of characters. * * @param[in] str string to count length * @return Returns the length, number of characters, of string @p str. */size_t StrLengthA(const char* str);

/** * @copydoc StrLengthA * @note This is the @c wchar_t version of StrLengthA(). */size_t StrLengthW(const wchar_t* str);


/** * @see Expand to StrLengthA() or StrLengthW() according to current *      generic-text-mapping configuration. * @hideinitializer */#if (defined(UNICODE) || defined(_UNICODE))#   define StrLength StrLengthW#else#   define StrLength StrLengthA#endif
由於我們根本不需要讓 StrLength() 如 macro 般呈現,且 doxygen 會做 C/C++ pre-processing,根據設定,會在文件上顯示 StrLength 會被展開成為 StrLengthW 或是 StrLengthA,因此使用 @hideinitializer 把 macro 的右邊隱藏起來。
總之,上面的寫法,是筆者目前可以想到的最好寫法,如果有人有更好的解法,筆者很想知道。要不然,看到這樣的文件,實在是覺得太醜了啊。
總結
本文介紹了在撰寫具備 generic-text-mapping 的 library 時,可以使用的手法,應該要注意的事項。為了「只維護一份程式邏輯」,我們可以有許多種的作法,如「以一個版本為主,另一個版本即時轉碼後呼叫主要版 本」,或是使用 C++ 的 template 語法。然而,我們也必須要注意到函式行為正確性的問題、程式的效率,以及可能因 side-effect 而存在的潛藏危機。最後,敬祝大家 happy coding,程式只寫一套最好。

  1. 既然都要用 generic-text-mapping 了,就表示知道了 i18n 的重要;而既然知道 i18n 很重要了,幹嘛還留個洞,留下使用 single-byte-character 的機會,而且還是預設值。
  2. The Code Project 的這篇《Unicode, MBCS and Generic text mappings》,有非常詳細的講解。
  3. 這個名字有其歷史包袱在,嘆。請參見《轉換 BIG5、GB2312、UTF-8、Unicode 與 wchar_t》這篇裡,「轉換工具:Windows API」這一段的說明。
  4. 例如會依據目前的 TCHAR 選擇是否要呼叫 mbstowcs()TcsToWcs() 這類的函式。這類函式,筆者將另行撰文說明。
  5. 實際上,C99 有定義 mbslen() 可用,不過我沒有測過 mbslen() 與先轉碼再 wcslen() 的速度何者較快就是了。
  6. 相關技巧有機會的話,筆者再另行撰文說明之。
  7. 想像一下不同參數編譯出來的 DLL,都來呼叫 GetTagAccessCount() 的情況。
  8. 筆者還是習慣使用如 javadoc 一般以 @ 開頭的文件指令,而不是 Doxygen/Qt 用的 \。這純粹是個人美感作祟的緣故。

【心得】Generic Text Mapping

http://www.programmer-club.com.tw/ShowSameTitleN/vcdotnet/2115.html

【心得】Generic Text Mapping


【一個常見的錯誤與錯誤的解決方法】

很多初學者從 VC++ 6.0 升級到 VC++ 2005 的時候, 經常發現到原本在 VC++ 6.0 版順利編譯並執行的程式突然無法編譯了. 像以下這個簡單的例子:

char ch[80];
CString str("Hello World");
strcpy(ch, str);

當用在新產生的 VC++ 2005 專案裡的時候, VC++ 2005 會發出類似以下的錯誤訊息:

error C2664: 'strcpy' : cannot convert parameter 2 from 'CString' to 'const char *'

有些初學者不明白這個錯誤訊息的原因, 也不去深入研究, 認為 typecasting 可以解決這個問題, 就做了這個更改:

strcpy(ch, (const char*)(LPCTSTR)str);

改了之後, 錯誤沒有了, 取而代之的是個警告:

warning C4996: 'strcpy' was declared deprecated

建議程式員應該用 strcpy_s() 這個安全的函式. 這個暫且不管它, 至少程式是可以編譯了.

但 typecasting 有解決到問題嗎? 答案是沒有, 上面的 typecast 叫編譯器不出聲, 把真正的問題隱藏了起來.

寫 C 程式幾乎完全沒有必要用到 typecast. 而大部份的 C++ 程式也不需要用到 typecast. 初學者的程式用到 typecast 幾乎等同於有潛在的錯誤或邏輯上的問題.


【編譯器的字集設定】

不管那個版本, VC++ 一共有三種字集的設定: ANSI, MBCS, 及 Unicode. 前兩者合稱「非-Unicode」設定.

C 及 C++ 語言有兩種字元類型, 一個就是我們常用的 char, 另一個是 wchar_t. 為了區分這兩者, 一般把 char 稱為「窄字元」, 把 wchar_t 稱為「寬字元」. 從程式語言的角度來看, char 跟 wchar_t 純粹是語言的類型, 跟 ASCII 或 Unicode 是兩回事. ASCII 及 Unicode 是編碼, 跟類型無關.

在 VC++ 裡, char 的長度是 8 位元, 使用 ASCII 編碼. wchar_t 的長度是 16 位元, 使用 Unicode 編碼.

【視窗系統的 API】

在視窗系統上, 大多數有字串或字元作參數的 API (如 MessageBox()) 都是有兩個版本的. 一個是窄字元版, 一個是寬字元版. 實際上, 視窗系統裡根本沒有 MessageBox() 這個 API, 它有的是 MessageBoxA() 及 MessageBoxW() 這兩個版本的 API.

以 MessageBox() 為例, 這兩個版本的宣告如下:

MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);

xxxA() 用的是 LPCSTR, 既 const char*, 一個「窄字元指標」.
xxxW() 用的是 LPWSTR, 既 const wchar_t*, 一個「寬字元指標」.

同時, 視窗的頭檔裡也有這個定義:

#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif

所 以當專案的字集設定是 Unicode 時, VC++ 會自動的設定兩個 preprocessor 的符號: UNICODE 及 _UNICODE. 在編譯時, preprocessor 會自動把 MessageBox() 變成 MessageBoxW(), 所呼叫的是 Unicode 的版本. 反之, 則呼叫 MessageBoxA(), 一個 非-Unicode 的版本.

MFC 的 CString 也是這樣子的. 在 Unicode 設定的專案下, 在編譯時, CString 會變成 CStringW, 一個寬字元的 CString; 如果是在 非-Unicode 的設定下, CString 則變成 CStringA, 一個窄字元的 CString.

從這個角度來看, MessageBox() 跟 CString 是「中性」的. 它可以變成「寬」, 也可以變成「窄」, 視專案的字集定義而定.

所以在使用 MessageBox() 或 CString 時, 要留意到專案的字集設定. 因為如果字集設定跟參數的類型不符, 如呼叫 MessageBoxW() 但傳給它的是窄字元, 那編譯器當然會發出錯誤訊息.

從這裡我們就可以知道上面的程式在 VC++ 6.0 可以正常編譯, 但在 2005 的專案裡卻發生錯誤的原因:
1. 因為程式裡「寬/窄」混合在一起,
2. 專案對字集的預設在 6.0 版跟 2005 版不同.

在 6.0 版上, 專案對「字集」的預設是 MBCS (Multi-Byte Character Set). 在 2005 版上, 專案對「字集」的預設是 Unicode.

混合式的寫法, 在轉換字集設定時一定會遇到問題. 所以這種寫法要避免.


【純「窄」或「寬」的程式】

當然我們可以不用管編譯器字集的設定, 而全用單一「寬」或「窄」的類型, 函式來寫我們的程式. 上面的例子用窄字元來寫的話是這樣子的:

char ch[80];
CStringA str("Hello World");
strcpy(ch, str);


用寬字元則是:

wchar_t ch[80];
CStringW str(L"Hello World");
wcscpy(ch, str);

wcscpy() 是 strcpy() 的「寬」版本.

但 是如果我們要用同一個專案來產生 Unicode 及 非-Unicode 的執行檔, 用這種比較極端的寫法就不是很方便. 同時, 大部份人都熟悉 CString 及 MessageBox() 而不是 CStringW 或 MessageBoxA(). 另一點, MSDN 上的資料大部份是 MessageBox() 而不是 MessageBoxA(). 原因很簡單, Microsoft 希望我們用「中性」的寫法而不是寬或窄的寫法.


【Generic Text Mapping】

像 MessageBox() 或 CString 這樣的函式定義或類型, 會依據專案字集的設定而自動選擇寬或窄版本的機制, 在視窗上有個專有名詞, 叫 "Generic Text Function" 或 "Generic Text Type". 因為它們是根據專案裡字集的設定來 map 到寬或窄的真實函式或類型, 它們也叫 "Generic Text Mapping".

同樣的, C 及 C++ 函式庫裡以字元, 字串為參數的函式, 結構也有兩個版本. 本文一開始例子裡的 strcpy() 是個「窄字元」版本的函式. 它相對的「寬字元」版是 wcscpy().


【C 標準函式庫】

雖 然語言標準並沒有提供 generic text mapping 的機制, 但 Windows 的頭檔 <tchar.h> 有提供 C 函式庫的 generic text mapping. strcpy()/wcscpy() 的 generic text function 是 _tcscpy(), 它是這樣定義的:

#ifdef UNICODE
#define _tcscpy wcscpy
#else
#define _tcscpy strcpy
#endif

該頭檔也定義了一系列的 generic text 類型:

http://msdn2.microsoft.com/en-us/library/se784sk6(VS.80).aspx

常數:

http://msdn2.microsoft.com/en-us/library/z94kex77(VS.80).aspx

函式:

http://msdn2.microsoft.com/en-us/library/tsbaswba(VS.80).aspx


所以除了之前所講的「全寬」, 「全窄」的寫法外, 多了一個叫「全 generic text mapping」的寫法:

_TCHAR ch[80];
CString str(_T("Hello World"));
_tcscpy(ch, str);

這也是微軟建議的做法. 因為在 Unicode 的專案設定下, preprocessor 將它們變成:

wchar_t ch[80];
CStringW str(L"Hello World");
wcscpy(ch, str);

而在 非-Unicode 專案的設定下, preprocessor 後, 編譯器所看到的是:

char ch[80];
CStringA str("Hello World");
strcpy(ch, str);

這樣同一個專案就可以以 Unicode 或 非-Unicode 來產生兩種不同的執行檔.

當然, 只要明白這個原理, 程式員並不一定要用 generic text 的做法. 如果專案只用單一種字集, 那混合式的寫法也是可以的.


【C++ 標準函式庫】

可惜的是微軟並沒有提供 C++ 的 generic text mapping. 如果你不想自己寫的話, 這裡有一個可以用:

http://www.codeproject.com/string/tstl_h.asp



【「寬」-「窄」之間的轉換】

並不是每個 API 都是用 generic text mapping 的, 有些 API 只有寬字元版本. 所以有時, 寬-窄字元/字串之間的轉換有其必要.

視窗有寬-窄字串轉換的 API - MultiByteToWideChar() 及 WideCharToMultiByte().

MFC/ATL 的使用者有一系列非常簡單的 macro 可以用 (頭檔是 <atlconv.h>):

http://msdn2.microsoft.com/en-us/library/87zae4a3(VS.80).aspx

上面的 A2W(), W2T() 等自 6.0 起就有了, 但它們有潛在的 stack overflow 的問題. 7.0 版的 ATL 用了新的 class 來做, 更正了之前的問題:

http://msdn2.microsoft.com/en-us/library/awt7k7f5(VS.80).aspx

Rules of memory management of openCV

Original page: http://www.andol.info/hci/993.htm

Rules of memory management of openCV
After several weeks’ hard working, finally, the memory leaking problem is fixed.
In the last post which listed nearly all kinds of variaties declare and delete methods, here i add several tips for memory check while it is leaking:
1) int, double, float … : these kinds of variaties don’t matter so much;
2) IplImage* : this really matters, especially when cvCloneImage is conducted, if the destination variaty was not cleared, the memory would fly up.
3) CvMemStorage: be careful, to delete this data you have to use not ‘cvReleaseData’ but ‘cvReleaseMemStorage’, one declaration, one delete operation.

OpenCV memory leaking management in C/C++

Original page: http://www.andol.info/hci/963.htm

OpenCV memory leaking management in C/C++

If you’re new to OpenCV, you need to know exactly how to manage all the huge amounts of memory you’re using. C/C++ isn’t a garbage collected language (like Java), so you need to manually release memory as soon as its use is over. If you don’t, your program could use up hundreds of MBs of highly valuable RAM… and often even crash (out-of-memory errors?)
It can be a daunting task to hunt exactly where memory needs to be released. So I’ve compiled this short list of places where you should look out for memory leaks.
Create it, then Release it
 
If you create something, make sure you release it before “returning”. This is probably the very first thing you should check when fixing memory leak problems with OpenCV. For example, if you do a cvCreateImage, make sure you do a cvReleaseImage. There are many things you can create. Here are some functions that “create” and their corresponding “release” functions
cvCreateImage cvReleaseImage
cvCreateImageHeader cvReleaseImageHeader
cvCreateMat cvReleaseMat
cvCreateMatND cvReleaseMatND
cvCreateData cvReleaseData
cvCreateSparseMat cvReleaseSparseMat
cvCreateMemStorage cvReleaseMemStorage
cvCreateGraphScanner cvReleaseGraphScanner
cvOpenFileStorage cvReleaseFileStorage
cvAlloc cvFree

One warning though: If you create something and want to return it, don’t release it. Lets say a function that creates a checkerboard image and returns it. If you release the image before returning it, you’re freeing all memory that stores the image data. And when you try accessing memory that isn’t yours, you get a crash.
Release returned structures
This is the second thing you should check for. Often, once you return a structure (say, an image).. you forget about it.
Multiple Memory Allocations
This is the third thing you should check for: Allocating memory, and then changing the pointer itself. Here’s some example code:
IplImage* image = cvCreateImage(whatever);
image = CreateCheckerBoard(whatever);

cvReleaseImage(&image);
This function creates a memory leak. First, you allocate some memory for image. Then, you call the function CreateCheckerBoard. This function itself creates new memory. And image now points to this new memory. The memory created in the first step is lost forever. No variable points to it. A memory leak. To fix this, you need to modify the code like this:
IplImage* image = NULL;
image = CreateCheckerBoard(whatever);

cvReleaseImage(&image);
If you return a sequence, release its storage
There are many instances where you use the CvSeq data structure. And often you might want to return this structure for further use. If you release its storage (a CvMemStorage structure) within the function itself, you’d free the memory where the sequence is stored. And then you’d try and access it in the calling function. Again, crash.
A temporary fix would be to just erasing the cvReleaseMemStorage statement… but that would mean lots of memory.
To fix this, you don’t release the memory in the function itself. You release it in the calling function like this:
cvReleaseMemStorage(&thesequence->storage);
storage is a member of the CvMemStorage structure that always points to the memory where its stored.
Again, this is just an example. There are more structures where a similar situation could arise.
Dependence on other structures
I quite recently discovered this memory leak. To explain this, I’ll use an example: Lets say you find out the contours of an image. OpenCV would return a “linked list” type structure calledCvSeq. You decide to access the third element of this linked list. OpenCV returns a pointer to the third element. All going great till this moment.
Now you decide to save all the points of this contour (the third element) in a data structure of your own. Since this is an array of points, you do something like:
mystructure->points = thirdcontour->points;
You set the pointer to equal to the thirdcontour. This is the bug. If you release the storage of the sequence (which you should), mystructure has a bad pointer. To fix this, allocate new memory to mystructure->points and then copy contents ofthirdcontour->points… something like this:

mystructure->points = (CvPoint*)malloc(sizeof(CvPoint) * thirdcontour->total);
memcpy(mystructure->points,thirdcontour->points,sizeof(CvPoint)*thirdcontour->total);
This creates new memory for your structure and then copies each element there. Once you’ve done this, you can release the storage of the sequence without fear.

Visual C++中調用DLL

摘 要:介紹了動態鏈接庫這種模塊復用方法及在VC中對它的調用,並給出了一個通過復用來實現數據加密的具體實例。

關鍵詞:VC DLL 模塊復用 數據加密

引言

模塊化思想貫穿於軟件工程各個發展階段,模塊復用是構建大系統的一種重要思想。模塊復用方法有:函數、函數庫、動態鏈接庫、COM。其都是基於模塊化的 基本思想。函數是最簡單的模塊化思想,也是後面方法的基礎,甚至是一個應用程序的基礎。函數庫是函數的組合,一般將一些功能相似的函數放在一起作為函數 庫,這種函數庫通常叫做靜態庫,其鏈接方式是靜態的。COM即組件對象模型,是一種集成技術,可以使程序在運行時把各種不相關的軟件程序混合在一起,而不 必考慮這些不相關的程序是用什麼語言編寫的,它也是一種標準或者稱為協議,負責將一個軟件模塊和另一個軟件連接起來。動態鏈接庫DLL(Dynamic Link Library)是一個可以被其它應用程序共享的程序模塊,其中封裝了一些可以被共享的例程和資源,其鏈接方式是動態的。動態鏈接庫文件的擴展名一般是 dll,也有可能是fon、sys和dry,它和可執行文件(.exe)非常相似,區別在於DLL中雖然包含了可執行代碼卻不能單獨執行,而應由 Windows應用程序直接或間接調用。Windows操作系統包含大量動態鏈接庫,其中最主要的是KERNEL32.DLL、USER32.DLL、 GDI32.DLL 。

DLL的調用

調用DLL,首先需要將DLL文件映像到用戶進程的地址空間中,然後才能進行函數調用,這個函數和進程內部一般函數的調用方法相同。Windows提供了兩種將DLL映像到進程地址空間的方法:

1、隱式的加載時鏈接

這種方法需要DLL工程經編譯產生的LIB文件,此文件中包含了DLL允許應用程序調用的所有函數的列表,當鏈接器發現應用程序調用了LIB文件列出的 某個函數,就會在應用程序的可執行文件的文件映像中加入一些信息,這些信息指出了包含這個函數的DLL文件的名字。當這個應用程序運行時,也就是它的可執 行文件被操作系統產生映像文件時,系統會查看這個映像文件中關於DLL的信息,然後將這個DLL文件映像到進程的地址空間。

系統通過DLL文件的名稱,試圖加載這個文件到進程地址空間時,它尋找DLL 文件的路徑按照先後順序如下:

·程序運行時的目錄,即可執行文件所在的目錄;

·當前程序工作目錄

·系統目錄:對於Windows95/98來說,可以調用GetSystemDirectory函數來得到,對於WindowsNT/2000來說,指 的是32位Windows的系統目錄,也可以調用GetSystemDirectory函數來得到,得到的值為SYSTEM32。

·Windows目錄

·列在PATH環境變量中的所有目錄

VC中加載DLL的LIB文件的方法有以下三種:

①LIB文件直接加入到工程文件列表中

在VC中打開File View一頁,選中工程名,單擊鼠標右鍵,然後選中"Add Files to Project"菜單,在彈出的文件對話框中選中要加入DLL的LIB文件即可。

②設置工程的 Project Settings來加載DLL的LIB文件

打開工程的 Project Settings菜單,選中Link,然後在Object/library modules下的文本框中輸入DLL的LIB文件。

③通過程序代碼的方式

加入預編譯指令#pragma comment (lib,"*.lib"),這種方法優點是可以利用條件預編譯指令鏈接不同版本的LIB文件。因為,在Debug方式下,產生的LIB文件是Debug 版本,如Regd.lib;在Release方式下,產生的LIB文件是Release版本,如Regr.lib。

當應用程序對DLL的LIB文件加載後,還需要把DLL對應的頭文件(*.h)包含到其中,在這個頭文件中給出了DLL中定義的函數原型,然後聲明。

2、顯式的運行時鏈接

隱式鏈接雖然實現較簡單,但除了必須的*.dll文件外還需要DLL的*.h文件和*.lib文件,在那些只提供*.dll文件的場合就無法使用,而只 能採用顯式鏈接的方式。這種方式通過調用API函數來完成對DLL的加載與卸載,其能更加有效地使用內存,在編寫大型應用程序時往往採用此方式。這種方法 編程具體實現步驟如下:

①使用Windows API函數Load Library或者MFC提供的AfxLoadLibrary將DLL模塊映像到進程的內存空間,對DLL模塊進行動態加載。

②使用GetProcAddress函數得到要調用DLL中的函數的指針。

③不用DLL時,用Free Library函數或者AfxFreeLibrary函數從進程的地址空間顯式卸載DLL。


http://dev.xuezhishi.net/program/VC/2007-06-20/17543.html

外遇…心乾涸 還是性飢渴

外遇…心乾涸 還是性飢渴
【元氣周報/記者王昭月/報導】
老黃結婚30多年,晉階歐吉桑後,男人味愈走下坡。一次女兒帶名身材火辣的死黨回家,老黃眼底宛如浮現「再世情人」,腦中竟上演與少女敦倫的浪漫。

他居然…愛上女兒同學
女兒同學常來家中作客,婀娜身影不時縈繞老黃腦海。不久,老黃的生活開始轉變,他勤於健身,重視衣著,見到女兒同學,聲調變得溫柔,甚至邀約用餐、送禮,讓小女生備感呵護,不覺墜入情網。
老黃妻子察覺到丈夫異樣,懷疑他在搞什麼鬼。夫妻倆本來就常口角,現在更爭吵不斷。
有心理學家說,很多情感的「保存期限」大概只有兩年,明顯的,老黃碰上青春貌美的辣妹,乾涸心靈起了微妙變化,即使年紀足以當爹,仍想「偷」他個新鮮刺激。講白了,老黃是犯外遇,從精神上的出軌,逐步走向肉體的解放。

犯了錯…都是一時迷失?
國內外最近爆發幾例轟動的外遇事件,男主角身陷漩渦。立委吳育昇被狗仔拍到帶香奈兒女郎進住高檔汽車旅館,消息踢爆後,吳坦承自己「一時迷失,犯了錯」。
老虎伍茲的婚外情讓人眼花撩亂,虎女郎從2、3個連環爆到2、30個,伍茲為此付出極大代價。
以新聞專業、愛家著稱的前主播李四端,也被拍到摟著女人吞雲吐霧,儘管尚不構成「外遇案」,卻讓李主播「冏很大」。

好老公…怎麼也會外遇
「外遇」,望文生義是在「外面遇到」的意思,但婚姻之外,遇到是性、愛、安慰,還是桃花劫?
許多大家公認的好老婆或好老公,為何還會搞外遇?廣川醫院性治療室主任童嵩珍發現,多半是因為婚姻關係出現無法說的秘密,為了逃避,有人選擇外遇。
「有對夫妻性事喬不攏,老公就診時百思不解,他和老婆做愛時就不舉,和別的女人卻不會。他坦承和情人互動不單為了性,重要是個性合得來」。

性不性…影響婚姻關係
童嵩珍說,以前的人結婚會先合八字,看命理,慎重其事,不過現在外遇理由千百種,很多人婚姻觸礁,各自向外發展,原因就是「性」出問題。
「性」喬不來,要緊抓另一半的心,恐怕困難;外遇,往往是這類怨偶尋求情欲出口的理由。
「性並非單方面的事,而是雙方相合度不足。」童嵩珍舉例,一個陰冷的女人碰到陽萎的男人,兩人半斤八兩,誰也怨不得誰;但正常女人遇見性欲弱的男人,相處可難。

她整形…丈夫仍沒性趣
性是原因之一,個性亦是,男女會搞外遇,不見的是外頭那個「功夫」了得,很可能是夫妻相處起了變化,彼此煩了、膩了,讓「外」人有機可乘。
童嵩珍說,一名太太無助地說,她為挽回外遇老公,花錢減肥、隆乳、整形,連陰道都做緊縮術,結果丈夫還是不碰她。

【2010/01/03 元氣周報】

美研究:一周嘿咻兩次 有益男人心臟健康

美研究:一周嘿咻兩次 有益男人心臟健康

更新日期:2010/01/10 10:00 國際中心/綜合報導
性行為有助身「心」健康,有了最新的醫學根據。一項由美國麻州新英格蘭研究中心所做的研究顯示,每周有兩次性行為,可以降低男性罹患心臟病的機率。
這項研究歷經16年之久,研究對象是1000名中年以上的男性(40歲到70歲),結果顯示定期有性行為的男性,可降低罹患心臟病機率高達45%,也就是每周至少「嘿咻」兩次的男性,罹患心臟病機率比久久「炒一次」的,幾乎少了一半。
研究人員也表示,性行為頻繁的男性,可能處於一段固定的親密關係,因而有助減少身心壓力,得以改善健康。研究人員建議醫師,當評估中老年男性有無心臟病徵兆時,除了考慮年齡、體重、血壓和膽固醇指數之外,也可評估性生活是否頻繁。
這項研究發表在《美國心臟科醫學期刊》,不過,該研究沒有針對女性,也就是不能證明性生活頻繁的女性是否也能減少心臟病。
另外,美國國家癌症研究所發現,男性每周至少射精5次,可減低罹患攝護腺癌的機率。美國賓州威爾克斯(Wilkes)大學的研究也顯示,冬天一周性交一到兩次,可能提升免疫力,減少感冒和流行性感冒機率。

女博士 大陸婚戀市場滯銷品

女博士 大陸婚戀市場滯銷品

  • 2010-02-25
  • 旺報
  • 【文/艾恩繼(自由作家)】

     大學裡常年流傳這樣的順口溜:大專生是趙敏,本科生是黃蓉,碩士生是李莫愁,博士生是滅絕師太。
     大陸女生向來比台灣女生結婚早,女博士的婚姻問題在大陸更為棘手,一直存在較大的偏見。「高年齡」和「高學歷」使大陸的女博士們,處於高處不勝寒的境地,常常讓人誤解,讓男性望而生畏。
     女博士在大陸被稱為是UFO(即Ugly、Foolish和Old三個英文單詞的縮寫)。類似這樣的刻板印象,還有很多,大學裡常年流傳 這樣的順口溜:大專生是趙敏,本科生是黃蓉,碩士生是李莫愁,博士生是滅絕師太。這些,還是仁慈的,至少它將女博士劃為女性的行列。更厲害的是,將女博士 強行拉出「男人、女人」的類別,另起門戶稱為:男人和女人之外的「第三類人」。
     女博士 是第三類人
     對社會公眾來說,「第三類人」是神秘的一群。大多數人對女博士的想像在於:長得醜,EQ低,沒有女人味;穿著老土,生活乏味;思維僵化,迂腐不堪,張口閉口都是學術問題;最重要的:年齡偏大,一般博士的年齡,平均在28到35歲之間,在早婚的大陸,早過了談戀愛結婚的黃金年齡。
     以上這些,可能是公眾對女博士的刻板印象。也許,有失公允,有失全面。但也多多少少指出了女博士族群的現實問題:「高年齡」加「高學歷」使其在婚戀市場上,成了滯銷品,被稱為「剩女」。
     女生在成為博士的那天起,就開始在婚戀市場上跌價。
     怕男方有壓力 隱瞞學歷
     曾有某名牌大學的女博士,在婚介所徵婚時,怕自己的博士頭銜嚇壞對方,在學歷一欄只填了「大學本科」。與男友交往一年後,她才將自己的博士身分告知對方。令她驚訝的是,原本感情穩定的男方毅然提出分手,並責怪當初婚介所沒有把好關,直呼上當受騙。
     像上述案例,因怕男方有壓力而隱瞞學歷的女博士,不在少數。華東師範大學研究生會調研部,曾對上海市5所知名大學的662名在校女研究生(女碩士生、女博士生)進行了調查。結果顯示,有23.7%的女研究生,連一次戀愛也沒談過。
     某位中國人民大學的文科博士,愛打扮,有品味,有女人味,很時尚,更重要的是,她性格開朗活潑,能和大家打成一片。男生很容易對她產生好感,但令她苦惱的是,當對方得知她的女博士身分後,反應都很騖訝,有的甚至將嘴巴張成了O型。
     白天愁論文 晚上愁嫁人
     「白天愁論文,晚上愁嫁人」的順口溜,成了人們對女博士生的調侃。女博士生的日常生活,或許應對了這樣的順口溜。
     食堂、宿舍、圖書館、實驗室構成了女博士的主要生活空間。武漢大學的某女博士生描述她同院系的女博士生活:「早上起床後,有課就上課,沒 課就去自習室或者泡圖書館,準備課堂發言和論文資料。中午12點左右到食堂吃飯,上上網、睡睡午覺後,重複上午的事情。5點左右吃完晚餐,依舊是泡泡圖書 館,查期刊、論文資料,或者上上網,看看當季的美劇。」如果是真的喜愛學術,還好說;單純為了博士學位而來,常年過這樣周而復始、百般聊賴的生活,需要很 大的勇氣。
     女博士生活 單調無聊
     特別是工科女博士,她們的生活,比起文科女博士,又單調很多。理科博士生的大部分時間在實驗室中做實驗,每天實驗室、宿舍兩點一線,生活雖然簡單,但發表論文的壓力也讓他們欲哭無淚。
     女博士單調無聊的學術生活,雖不能阻擋女生攻讀博士的步伐,只是,不少女生,考慮到女博士在婚戀市場上的滯銷狀況,怕錯過了戀愛婚姻的黃金時間,多半先解決個人婚姻,再考慮念博士。
     在擇偶文化上,中國人大都充滿了傳統的「男強女弱」的觀念,不管是在學歷還是在年齡上,觀念都是如此。如果將男人和女人都分成甲、乙、丙、丁四等,按照「男強女弱」來進行配對,男甲對女乙,男乙對女丙,男丙對女丁,剩下來的,是基本上不能配對的男丁和女甲。
     男尊女卑 流水無情
     而女博士,基本上都是女甲。女博士向上看,合乎條件者人少得可憐,就算有也已是名草有主。所以,不得不降低身分,好將自己「銷」出去。
     很多女博士坦誠自己要求不高,但「一要有內涵,二要對我好,三要有一定經濟能力,相貌身高都無所謂……」
     就算要求不高,但是落花有意,流水無情。大多男生都表示,女生學歷太高會讓自己沒面子,而且,博士畢業起碼28、29歲,到結婚生子,就成了高齡產婦了。
     解放後的大陸,中共政府總是在各種場合中,強調男女平等。但事實上,男尊女卑的傳統觀念,在現實生活中,比比皆是。就業市場上,雖然不說明,但人人均知,男性要比女性吃香;尤其高管職位,男性更是具絕對優勢。
     大陸女博士成為婚戀市場的「滯銷品」,短期間恐難改變。很顯然地,解放超過60年的大陸,性別要解放,仍有一段長遠的路要走!

李家同:不要再講創新 要做好基本技術

李家同:不要再講創新 要做好基本技術          自由電子報2010年2月25日‧星期四 

〔中央社〕暨南大學榮譽教授李家同今天在工業局40周年慶上表示,希望政府「不要再講創新,要看台灣技術到底好不好」,因為基本技術不夠好,講創新沒有意義,希望台灣走回古老科技。

李家同是當時工業局推動主導性新產品開發計畫技術審議會總召集人,是這項政策推動20年來的靈魂人物。他今天在工業局40周年慶典禮上,再度對產業政策方向提出建言。

經濟部工業局今天歡度40周年慶,10任局長中除已經過世的第一任局長韋永寧,以及現任經濟部長施顏祥因到監察院報告無法出席外,包括現任局長杜紫軍在內,總計有 8位工業局長到場,共同為工業局40歲生日慶生。

歷任局長中,久未露面的前政務委員楊世緘也到場,他說「工業局是一輩子的事業投資,工業局人不能隨隨便便到外面找工作,要找也要找好一點的工作」。

特別代表施顏祥到場的經濟部政務次長林聖忠說,經濟部長很多都是工業局出身,包括現任部長施顏祥、前任部長何美玥、尹啟銘等,他很高興分享工業局的榮耀。

工業局第 3任局長徐國安說,「今天非常高興回到娘家」,工業局成立目的就是要發展工業,但不是管理機構,目的就是要提供產業界良好投資環境、興利除弊,讓產業在台灣發展而且茁壯。

不過,整場慶祝會中,李家同發言最讓現場省思。他表示,法國總統沙柯吉每到一個地方就會簽署一個工業產品合約,到中國大陸簽署新台幣9000億元的合約; 而現在連韓國也可以打敗美國奇異 (GE)與日本日立(HITACHI),拿到阿拉伯國家400億美元的核能計畫合約,但台灣呢?

因此,李家同呼籲,不要再講創新了,要看台灣的技術好不好。他舉一家磁鐵廠商為例,要做出磁力絕對均勻都做不到,但國科會不會補助支持廠商進行磁鐵研究,但能夠把磁鐵做好,對產業貢獻很大。李家同也說,半導體元件放大器同樣也有技術問題。

李家同說,台灣如果基本技術不夠好,就不要再講創新,因為這是沒有意義的。他並且用開玩笑的口吻說「希望局長(杜紫軍)聽懂我說的話」。

李家同還說「真正同情我的人很少,我知道尹啟銘(政務委員)同情我,希望你更加同情我」,砲火猛烈中還帶點幽默,讓現場氣氛緩和不少。

男人太少做愛 易罹患攝護腺結石

男人太少做愛 易罹患攝護腺結石
NOWnews 更新日期:"2010/08/09 16:36" 生活中心/綜合報導

縱慾過度固然不妙,但太少行房也很傷身!醫界指出,有許多男性兩、三周甚至數月沒有性生活,導致精液無法宣洩,造成攝護腺長結石,腰痛、解尿不順暢。台灣男性學醫學會理事長王起杰建議,男人要適度做愛或適度自慰,預防攝護腺結石。

高醫泌尿科醫師王起杰指出,射精不足是攝護腺長結石的最主要原因,因為攝護腺分泌攝護腺液、蛋白質、礦物質等,如果精液沉積在攝護腺,就容易生成結石。在泌尿科門診的案例裡,大約半數都有攝護腺結石,四、五十歲的熟男如果超過兩、三周沒射精,就會出現結石的沉積物。

王起杰建議男人應適度做愛或自慰,不要強忍不射精。他更提出一套以年齡的十位數乘上9,得出做愛的次數,例如40多歲的男性,以4乘以9得36,就是3周做愛6次,50多歲的男性,以5乘以9得45,即4周做愛5次。

濁水溪八年浩劫

調查篇 乾涸的河床 消失的生命之泉 溯溪百里 直擊濁水溪八年浩劫

更新日期:2010-08-17 記者:/撰文/燕珍宜 /攝影/吳東岳
台灣的大地之母、也是台灣最長的河流「濁水溪」,沖積出台灣最大面積的嘉南平原,如今,卻面臨斷流的危機。數十公里處處 都是龜裂、裸露的河床,沿岸的生態環境丕變,農民生活受到巨大影響,未來甚至所有的台灣人都會受到波及,一條無水可流淌的河,透露出台灣社會什麼樣的問 題? 「小時候的濁水溪,滔滔流水,極為洶湧壯觀,同學的媽媽還因為在溪中撈魚,不小心被水沖走。」濁水溪溪畔長大的媒體人謝金河回憶兒時,溪水壯闊的印象仍然鮮明,再回到故鄉,濁水溪卻已是黃沙一片。
「現 在,濁水溪像一條溝仔(水溝)在流,以前,濁水溪水量寬闊,有現在的十多倍闊!」雲林縣崙背鄉鄉長李永茂伸開雙臂,拚命想用身體來形容印象中濁水溪的巨 大。但這一切卻因八年前一項人類的決定而改變,這個改變不僅影響濁水溪的面貌、下游的生態、甚至影響到台灣這塊土地上的每個人。
濁水溪全長一八六公里,是台灣最長的河川,濁水溪的黑水,曾經孕育台灣這塊土地無數個世紀,滾滾大水,沖積出台灣最大面積的嘉南平原,養出粒大如豆、晶瑩飽滿、富含礦物質的濁水米,養活了這座海島上無數代子孫。
這條養育台灣上千年的河流,卻在八年的短短時間內失去了生命,原本豐沛的河流變成乾涸的枯溪,未來甚至可能面臨斷流的危機,這條生養台灣子民的母親到底發生了什麼事?受到了什麼傷害?
浩劫一:「沙塵暴」/半年枯水期 何處不飛沙
為了深入了解濁水溪的危機,《今周刊》採訪團隊今夏特別由濁水溪下游往上追溯,一路親眼觀察、親身體會、親手觸摸濁水溪發生的巨大改變,以及改變帶來的影響。
來到濁水溪下游處,站在西螺大橋 上,黑色的溪水已失去往昔的氣勢,如果是冬季枯水期時,這裡又是另一種樣貌,漫天的沙塵吹得行人走避,無法睜開眼睛,可以用遮天閉日來形容。這就是濁水溪乾涸的後果──沙塵暴。
「濁水溪」顧名思義,因為河水中含有大量的細泥沙,以致呈現混濁的狀態。河水被人為攔截後,濁水溪中下游乾涸裸露的河床,四處可見。
每年十月至翌年三月的枯水期,再加上強勁的東北季風,濁水溪中下游兩岸的居民,往往自嘲是「呷飯配沙」、「目睭會吐沙」。李永茂跟我們描繪那種情景:「就算門關起來,風飛沙還是跑進來,桌子永遠就是一層沙,目睭攏嘛紅唧唧。」
跨 過濁水溪,採訪團隊走到中游附近的農田,放眼望去,每一畝田,也都樹立至少一口以上的沉水馬達抽水井,住在二崙鄉的農民廖勇智說:「灌溉圳的水位不夠,我 們根本引不到水。」彰化農田水利會灌溉股股長陳炳耀說,彰化的農業用水越來越少,甚至出現一期稻作必須輪流灌溉的情況。
濁水溪水流大減,八年來,溪水減少開始對農民產生衝擊,地下水層由於缺乏表面溪水的補充,地下水位一路往下劇降,雲林縣西螺鎮的農民余坤城無奈地 說:「以前地下水只要用一般馬達,挖十公尺就已足夠;但是現在都必須用沉水馬達,深度要打到四、五十公尺。」也就是說,八年來,地下水位下降了至少四十公 尺以上,而且情況還在惡化中。
浩劫二:「地層下陷」/水源不足 地下水越抽越深
有一句 流行語:「生命會自己找到出口」,農民在水源不足的情況下,只好抽地下水,淺層的抽不到,就往深層抽,越抽越深。然後導致地下水超限使用,進而造成地層下 陷、海水入侵地下水層,進而成為土壤鹽化等等的問題,這環環相扣的系統危機,是否會有蝴蝶效應般的後果,令人不敢想像。
濁水溪為何變成今日 滿目瘡痍的景象?我們的疑問越來越巨大,越往上游走,濁水溪的面貌越令人憂心,往日的河道成了永久道路、大片的菜田,河床的面貌更為猙獰,灰白的岩石幾已 完全裸露,原來的河道中間甚至因僅存細流的下切侵蝕作用,切割出近十公尺深的灰白色大峽谷,令人震驚。
驚駭之餘,抬起頭,橫在眼前的,是一 條巨大的人工建築,冰冷的站在濁水溪的身體上,這個人為的建築,不僅擋掉了濁水溪每年平均約四十九.五億噸的溪水,也擋掉了濁水溪的生命,這就是「人定勝 天」的里程碑||集集攔河堰 ,花了十年時間、二三八億元建立,二○○一年底試運轉,開始發揮整體攔水的功能。
浩劫三:「改變地貌」/河堰兩邊 宛若兩個世界
當登上攔河堰 堤,眼前的景象令人五味雜陳,河堰上游的濁水溪流域,是鬱鬱蒼蒼的湖光山色,因為水氣的潤澤,色調就像油畫般清晰鮮豔,充滿生命的光澤。
河堰下游卻是幾乎完全裸露的岩岸,沒有任何生氣,就像失去生命之泉的乾枯屍體。
州 里社區理事長陳朝焚向我們解答濁水溪大峽谷形成的疑問:「我們這邊都叫集集攔河堰 為集集攔沙壩,因為它把大石頭、小石頭、泥沙統統都攔起來了。」通過攔河 堰的濁水溪溪水因為少掉石頭泥沙的緩衝,雖然僅存細流,但水流流速加快,因此一直往河床中間下切,也因水量變少,兩岸的岩石壁就裸露出來,因而形成大峽谷 的景觀。
對遊客來說,大峽谷景觀或許讓人驚豔,但是對當地居民來說,卻是憂心忡忡。因溪水下切、側切及溶蝕,將可能導致濁水溪的堤防被淘空,進而潰決。
集集攔河堰 的建立目的是為了「更有效率」的利用水資源,只不過,是站在人類的角度,而非整體自然環境的角度。
廖冠貿帶領我們來到林內淨水場的出水口,他解釋,集集攔河堰 所攔下的水就是在這裡經過初步淨化後,開始分流為工業用水、農業用水與民生用水。十多年前,為了供應台塑六輕的工業用水,中水局規畫在濁水溪上游興建了集集攔河堰 。攔河堰 ,顧名思義,就是將河水攔截,然後用人造暗管,輸送至目標使用區。換言之,濁水溪的水其實是被人造的攔河堰 ,從上游強硬把水劫走了!
根據集集攔河堰 管理中心的統計數據,集集攔河堰 所攔下來的水量,平均每天為一三五六.二萬噸,其中,工業用水主要是供應位於濁水溪出海口南岸的台塑六輕使用。每一天,六輕六十六座廠,總計須消耗掉約三十五萬噸的濁水溪水。
集集攔河堰 自○一年底試運轉以來,濁水溪九四%的水,就統統被抽走,輸往別處,只留給濁水溪自己,少得可憐、只有原本總水量不到六%的尾水。原來,濁水溪欲哭無淚的原因在於─人為劫水。
「人為劫水」是證明人定勝天,可以全權掌控水資源,以人類的角度重新分配大自然的資源,一切看似完美的計畫,但在「攔劫」濁水溪八年之後開始產生衝擊,衍生出許多讓人意想不到的自然反撲後果,全體台灣人開始承受苦果。
我 們懷著沉重的心情繼續往上走,河流旁的鄉間小路上傳來轟隆的巨大轟鳴聲,走近才看到漫天揚塵中出現巨大的沙石車怪獸一輛輛呼嘯而過,彰化縣環境保護聯盟總 幹事廖冠貿不滿的說:「最高紀錄,一秒鐘就一台沙石車。」跟在沙石車後面的我們發現,高大而笨重的沙石車竟然蛇行起來,原來是為了要閃躲路面上的坑坑洞 洞。一路跟在沙石車的後面,看著它閃躲自己所造成的凹凸路面,既可氣又可笑...(精采完整內文請見《今周刊》712期,各大便利商店及連鎖書店均有銷 售)
http://tw.news.yahoo.com/marticle/url/d/a/100811/9/2aycs.html?type=new&pg=1