發表文章

目前顯示的是 2008的文章

Cast a type with a small memory space to a bigger one

這是一個很常見的錯誤,可是我還是犯了 (...sigh) 我當然不是在下面的程式碼犯錯囉,但因為犯錯的程式是工作上的程式,不能貼出來,所以稍作整理,寫出下面的那個「錯誤」程式碼,以資提醒... (為甚麼我有再犯的預感 ...) 下面的程式哪裡有問題: #include "stdio.h" #include "stdlib.h" struct test { unsigned char a; unsigned char b; unsigned char c; }; int main() { struct test tmp; printf("Please enter three number.\n"); printf("Each number should be 0~255\n"); scanf("%d %d %d", &(tmp.a), &(tmp.b), &(tmp.c) ); printf("%d %d %d\n", tmp.a, tmp.b, tmp.c); return 0; } 當我們輸入 1 2 3,顯示也是正常的 1 2 3,看起來一點問題也沒有。 真的嗎???? 讓我們改一下程式碼如下: scanf("%d %d %d", &(tmp.c), &(tmp.b), &(tmp.a) ); printf("%d %d %d\n", tmp.a, tmp.b, tmp.c); 簡單來說,只是把讀取順序反過來,然後一樣輸入 1 2 3,結果答案是 3 0 0 而不是 3 2 1。到底發生了什麼事情??? 首先,當我們用 scanf 進行讀取的時候,是以 int 的方式讀入,也就是說總共讀入了 4 個 byte,所以第一段程式碼可以用下面的那張圖來表示: ----------------------- byte -------------------- +--------+-------+--------+ -------------------- |---a-----|---b---|---c

The difference between Array and Pointer

Array 和 Pointer 有什麼差別呢? 最常聽見的說法是 Array 是 Pointer 的一種特例,是在宣告的時候就已經將大小 allocate 出來的一種 pointer。本來我也是這麼認為的,可是看看下面的那個範例: #include "stdio.h" #include "stdlib.h" int main() { unsigned char test[6]; test[0] = 0; test[1] = 1; test[2] = 2; test[3] = 3; test[4] = 4; test[5] = 5; printf("test: %X\n", test ); printf("&test: %X\n", &test ); printf("*test: %X\n", *test ); printf("*(test+1): %X\n", *(test+1) ); printf("*(&test): %X\n", *(&test) ); return 0; } 顯示的結果如下 test: 76A21CA0 &test: 76A21CA0 *test: 0 *(test+1): 1 *(&test): 76A21CA0 其中 test, *test, *(test+1) 都沒有問題。有問題的是另外兩個。如果 array 和 pointer 是一樣的話,那為甚麼 &test = test 而不是等於 pointer 的 pointer 呢??本來想從 C99 來找答案,但實在不知道從何找起,結果發現網路上有一個很棒的網站: Frequently Asked Questions in comp.lang.c 這個網站用一張圖來解釋其間的差異: +---+---+---+---+---+---+ a: | h | e | l | l | o |\0 | +---+---+---+---+---+---+ +-----+ +---+---+---+---+---+---+ p:

Function Pointer in C

Function Pointer 是C語言最重要的高等特色之一,最常見的例子就是 State Machine 的實作以及排序演算法的 compare function 輸入。下面的程式碼只是要記錄一個基本的用法,方便之後使用參考,畢竟從來沒用過(雖然知道很久了)。 #include < stdio.h > int sum( int, int ); int sub( int, int ); int mul( int, int ); int mod( int, int ); int (*op[4]) ( int, int ) = { sum, sub, mul, mod }; int main() { .... int a, b, i; .... a = 5; .... b = 3; .... for( i = 0 ; i < 4; i++ ) ........ printf("Operation %d result: %d\n", i, (*op[i])(a, b) ); .... } .... return 0; } int sum( int a, int b ) { return a+b; } int sub( int a, int b ) { return a-b; } int mul( int a, int b ) { return a*b; } int mod( int a, int b ) { return a%b; }

exec() family

這只是一件小事,特此記錄用以提醒 在 Google 上面搜尋 exec 系列的 example code,常常會看到下面的寫法: #include < unistd.h > int main() { .... char * argv[ ] ={ "ls","-al","/etc/passwd",0}; .... execvp("ls",argv); .... return 0; } 這是一個很簡單的範例,很可以編譯執行,但卻暗藏危險 Why? 首先,來問問看「男人」 The exec() family of functions replaces the current process image with a new process image. 這句話的意思是「 將外部程式(ELF image)取代掉原來的 process 」 所以,一般來說,在程式裡面要使用 exec 系列的 functions 時, 不能在 parent process 裡叫用 exec system call 來跑外部程式;否則 parent process 會消失 。正確的作法應該是 先 fork 一個 process,並於那個 process 裡面進行 exec 的呼叫 。而上面的範例之所以沒問題只能說是「剛好」沒問題而已,為什麼剛好沒問題... 自己看囉~ 一個可以看出錯誤的例子 #include < unistd.h > #include < stdio.h > int main() { .... int a = 0; .... char * argv[ ] ={ "ls","-al","/etc/passwd",0}; .... execvp("ls",argv); .... a++; // 你會發現這裡不會執行唷~ .... printf("a = %d\n", a); // .... return 0; } 正確的範例 #include < unistd.h > #include < stdio.h > #include < sys/t

Linux Multicast Routing Cache

圖片
在 Linux 裡面,Multicast 的 Routing 會不同於一般的 Routing 方式,在公司實驗的時候,明明 Routing Table 都已經進行設定了,封包卻始終不按照自己所想的方式來轉送,於是跟同事進行研究後,得到下面的結論。 首先,先來看一張圖 當然,這張圖有點小,請按照連結去觀看原始大小 當網卡收到封包以後,處理順序會是 netif_receive_skb -> ip_rcv -> ip_rcv_finish -> ip_route_input -> ip_route_input_slow ... 在 ip_route_input 和 ip_input_route_slow 裡面會進行 routing 的動作 但其實在 ip_route_input 裡面有多加了一段判斷,是圖中所沒有的 /linux/net/ipv4/route.c if (MULTICAST(daddr)) { ... return ip_route_input_mc(skb, daddr, saddr, tos, dev, our); } 很明顯的可以看到 multicast 是被例外處理的 而 MULTICAST 的定義如下: /linux/include/linux/in.h #define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000)) 很明顯的,可以看出是 Class D 的區段 總之,要 Linux 進行 Multicast Forwarding 的條件如下: 1. /proc/sys/net/ipv4/conf/all/mc_forwarding 要設成 1 請注意,這邊直接使用 echo 來設定是沒有用的 MRouterFD = socket( AF_INET, SOCK_RAW, IPPROTO_IGMP ); setsockopt( MRouterFD, IPPROTO_IP, MRT_INIT, (void *)&Va, sizeof( Va ) ); 這是直接抄自 smcroute 的 code (當然我拿掉了 error protection 的部分) 2. /proc/net/ip_mr_cache 裡面要有資料 簡單來說

當信任瓦解,社會也就崩潰

圖片
我很少在看我媽轉寄的文章,因為大部分都是網路流言、風景、音樂之類的, 今天接到一封信,裡面有下面的文章, 看完以後,覺得感觸很深, 其實自己現在在資策會的工作不也是如此嗎? 在處理很多不合理的要求跟任務時,都有前輩所教授一套「應付」的方法 要求不合理,卻老是要應付要求而沒人群起反對。 這就叫做「上下交相賊」吧 引用地址: http://ahan.ahan.net/trackback.php?tbID=170&extra=s1covs4c26 當信任瓦解 , 社會也就崩潰 楊蕙如幾年前與信用卡公司鬥智大勝,獲得社會某些人士的稱許,各媒體也封她為「卡神」。楊蕙如最近開了一家網路顧問公司,並頻頻上媒體打知名度。 筆者認為,一個是非不分、道德低落的社會,才會把類似楊蕙如的行為,視為英雄之舉。 在美國,你去商店買東西,事後不論任何理由,都可去退貨還錢。因此,有一些人(一些台灣人和更多的大陸人)過幾天要出席重要宴會,就去「買」一套名牌衣服,穿去赴宴之後,再去退錢。 美國商店還有一樁好康的事:買貴了,可退差價。於是有些人就趁平時不打折但尺寸、顏色較齊全的時候,把貨品買回來,等到大減價的時候,再把收據拿去退差價。 這些人對自己的行為洋洋得意,還到處宣揚自己的聰明,甚至納悶為何眾多的別人那麼「愚蠢」,不會利用這個「漏洞」。 把占人家便宜看成「聰明」,把奸巧看成「能力強」,把挑撥族群看成「和解共生」,真的是價值錯亂了。 從卡神,筆者想到了股神巴菲特。此地許多股友在討論巴菲特的選股標準,往往忽略了他一再強調的:他非常重視一家公司CEO的誠信,不夠正派的公司他絕不考慮。 今天你會鑽法律漏洞,明天你掌權了,就會去修改法律,讓自己的違法變合法。這幾年來,我們看了太多這種例子了。 一個像楊蕙如這種心態的人,在記者會上還以稱讚現任雇主的方式,貶損曾拒絕錄用她的人,就不會讓人太奇怪了。 十年前,我帶年僅三歲多的兒子到美國旅行,寄宿親戚家。 親戚拿個全新的兒童汽車安全座椅給我,說: 「這裡規定兒童一定要坐汽車安全座椅,這個給你用,因為是借來的,請儘量不要弄髒,我還要還人。」 兩週後,我不再開車,他拿著半新不舊的安全座椅到量販店辦退貨。 店員一聲不吭,錢全數奉還。 親戚得意地對我說: 「美國的商店,兩週內都可憑發票退貨,所以我們常來這裡『借』東西。有些大陸人甚至連電視都『借』哩! 你說,

TCP K.O. UDP?? Really??

要懂「網路」真的很難呢~ 除了一堆冒出來的網路協定, 當網路出現奇怪現象時,還要找出各種可能的原因 這篇記載了一個辦公室發生的故事: 同事A:我正在測設備的 Throughput,結果跟我想像的不太一樣ㄟ 我:一定是設定錯誤啦(睡眼惺忪,不想理會) 同事A:設定沒錯,而且 TCP 的流量正常,但 UDP 很不正常,TCP的流量比 UDP 還大 我:(持續昏迷中)怎麼可能,根據網路基本理論,TCP 的頻寬應該會被 UDP 整個打壓啊,而且以前用 NS2 也是同樣的結果啊... 進到實驗室~ 實驗軟體:iperf 網路環境簡化版: MS --- BS---ASNGW 其中 ASNGW 是 iperf 的client,同時產生TCP跟UDP(15Mbps)的封包,在MS端進行接收... (15Mbps 是 MS~BS的bottleneck) 結果... TCP 的 throughput 大於 UDP,近乎兩倍 why?? 希望下一次,我在看到這裡的時候,就可以說出答案了 後來找同事B討論,經過千辛萬苦的實驗(由同事B做的~),得到下面的結論: 1. iperf 有對 UDP 動過手腳。iperf 根據官方網站的說法,他是 用來測 bandswidth 的軟體,而不是產生封包的軟體 !!所以他有針對UDP進行修改,當封包調的時候,他會自動把UDP的傳送速率降低。(TCP則不會進行這件事,因為TCP自己有congestion control 的功能) 2. 當我們把那段 UDP 動手腳的部分(delay_loop)註解調時,發現傳輸比例為 1:1,居然還是沒被打壓~ 3. 其實,真正會打壓的情況,是指下面的狀況: 硬體配置 三台 PC 以 Hub 連接, 稱為 PC1, PC2 與 PC3. Hub 為 100M 軟體設置 iperf version 1.7.0 PC1 跑 iperf server for TCP traffic 與 iperf server for UDP Traffic. PC2 跑 iperf client for TCP traffic. PC3 跑 iperf client for UDP traffic, data rate 為 100Mbps. 實驗結果 TCP traffic 被 UDP traffic 打壓. TCP traffic 之 t

十大豪門不買阿爾沙文的理由

Euro2008 結束了,雖然很遺憾地,我支持的球隊終究無法走到最後, 但以後再來分享心情吧 本屆 Euro2008 最搶眼的新秀(?)無疑是 Russia 的 Arshavin,大賽結束後自然引起不少俱樂部追逐。下面是一篇在網路上看到的笑話~ 利物浦 記者:請問您會買阿爾沙文嗎? 貝帥:是西班牙人嗎? 記者:不是 貝帥:那你還問! 切爾西 記者:請問您會買阿爾沙文嗎?你祖國的耶! 阿布:他值多少錢? 記者:不能太貴吧。肯定不超過1000萬鎊。 阿布:靠,在支票上寫這麼小的數字我都不好意思下筆! 阿森納 記者:請問您會買阿爾沙文嗎? 教授:他多大了? 記者:27了。 教授:靠,你要我買老頭子啊? 曼聯 記者:請問您會買阿爾沙文嗎? 爵爺:沒聽說過這個人! 記者:怎麼會?最近他這麼紅! 爵爺:靠,以為都像你們有心情天天看歐洲杯啊,老子現在被C-羅這個狗日的整的 連鹽都吃不下! 米蘭 記者:請問您會買阿爾沙文嗎? 加利亞尼:他幾歲啊? 記者:27吧。 加利亞尼:小伙太年輕了,恐怕經驗不足啊。 皇馬 記者:請問您會買阿爾沙文嗎? 卡爾德隆:你看弗格森被我整的,哈哈,你看弗格森被我整的,哈哈哈哈。 記者:對不起,我是問阿爾沙文。 卡爾德隆:哈哈,你看弗格森被我整的。 巴薩 記者:請問您會買阿爾沙文嗎? 拉波爾塔:他是支持小羅-德科-梅西系,還是支持普約爾-哈維系,還是法語幫? 記者:這個目前恐怕還難說。 拉波爾塔:哎,他人是不錯,就怕來了之後站錯隊啊。 尤文 記者:請問您會買阿爾沙文嗎? 塞科:不便宜啊,不好搞啊。 記者:你們是尤文咧!轉會出了名牛B啊! 塞科:說來慚愧,我比老莫遠了。 國米 記者:請問你會買阿爾沙文嗎? 莫拉蒂:他是米蘭尤文看上的人嗎? 記者:好像不是。 莫拉蒂:等米蘭尤文看上了再芊吧! 拜仁 記者:請問你會買阿爾沙文嗎? 魯梅尼格:這得讓我跟赫內斯討論過後再決定 記者:請問你想買阿爾沙文嗎? 赫內斯:這發讓我跟貝肯鮑爾討論過後再決定 記者:請問你認同買阿爾沙文嗎? 貝肯鮑爾:這讓我跟魯梅尼格討論過後再決定 克林斯曼:...........

printf 要注意的小細節

先看看下面的程式碼,非常簡單 #include int main() { int a = 28; int b = 4; double x = 2.8; double y = 0.4; printf( "a/b = integer~ %d\n", (a/b) ); printf( "a/b = float~ %f\n", (a/b) ); printf( "a/b = double~ %lf\n",(a/b) ); printf( "a/b = float~ %f\n", (double)(a/b) ); printf( "a/b = double~ %lf\n",(double)(a/b) ); printf( "x/y = integer~ %d\n", (int)(x/y) ); printf( "x/y = float~ %f\n", (x/y) ); printf( "x/y = double~ %lf\n", (x/y) ); return 0; } 很簡單吧,但是顯示出來的結果可能出乎一些人的意料~ a/b = integer~ 7 a/b = float~ 0.000000 a/b = double~ 0.000000 a/b = float~ 7.000000 a/b = double~ 7.000000 x/y = integer~ 6 x/y = float~ 7.000000 x/y = double~ 7.000000 呵呵,為什麼呢~ 太簡單了,不想回答~ 但在這裡留下一個記錄,提醒不要犯下這種愚蠢的錯誤。

在 Header File 中定義所要注意的細節~File Scope

請先看看下面的程式: test.h #ifndef _TEST_H_ #define _TEST_H_ int AAA( void ) { printf("Hello!!\n"); return 0; } int BBB( void ); // defined in test1.c int CCC( void ); // defined in test2.c #endif test1.c #include #include "test.h" int BBB( void ) { AAA(); printf( "Hello~ test1!!\n" ); return 0; } test2.c #include #include "test.h" int CCC( void ) { BBB(); printf( "Hello~ test2!!\n" ); return 0; } int main() { CCC(); return 0; } 使用下面的指令進行編譯 gcc -c test1.c gcc test1.o test2.c 結果看到下面的錯誤信息: /tmp/ccSQ7VRf.o: In function `AAA': test2.c:(.text+0x0): multiple definition of `AAA' test1.o:test1.c:(.text+0x0): first defined here collect2: ld returned 1 exit status 很吸引我注意的是「 multiple definition 」這字眼,因為在整個程式裡面,其實明明就只定義一次。 問題出在哪裡呢?恩,File Scope 在編譯 test1.o 的時候,因為 test1.c 中引入了 test.h,所以 test1.c 的程式展開後會包含 AAA 的定義。而當 test2.c 再去引入 test.h 並連結 test1.o 時,當然會發生重複定義的問題。 要避免這問題的方法,就是在 AAA 的定義裡面加上 static ,這個以限制該 Function 的 file scope 只在

信仰與理性

很多基督徒是不逛 PTT 的基督信仰版的,因為覺得裡面太多非基督徒肆意攻擊的言論(而且大部分還旁徵博引、滿腹經綸),所以覺得討論那些信仰的問題是毫無意義的,離這種會動搖人心的地方越遠越好。 其實我還挺喜歡看他們的文章的,每一次看他們的文章,就可以對自己的信仰進行一次反思。 演化論,一直被拿出來吵的議題,我想大概不會有吵完的一天吧。那些攻擊基督教信仰的人,他們拿出一篇一篇的學術論文,一樣一樣的考古證據,來證明人是從猴子演化來的,宇宙是能經過大爆炸產生的,他們堅持,要談神話再主日學談就好,課堂上不要講這些怪力亂神的東西。well ... 連教會中念人類學的人也是採用相同的論調。 我呢?我對於到底該不該把智慧設計論列在科學裡面一點興趣的沒有,我在意的是基督徒該如何看待演化論對神創造主權所進行的挑戰。 科學,講究證據、推導,這是我們從小學的,但,科學能構築所有的一切嗎?我認為「不」。人的理性根本不可能理解上帝奇妙作為。所以,無論證據有多少、推導是不是正確,我覺得以人的理性為根基來進入真理的領域根本就是錯誤的!對基督徒來說,信仰才是這個根基!在信神的根基上,來建構自己對這個世界的瞭解,而科學,不過就只是在信仰的根基上朝真理邁進的道路。 學術?學術不過就是信仰的僕人(不管你的信仰是什麼) 基督徒是以信求知,而不該是以知求信! 因為到神面前來的人必須信有神,且信他賞賜那尋求他的人。 的確,有不少基督徒有崇高的夢想,希望在神所賜下的理性所構築的平台上,與非基督徒對話,試圖向他們證明一些信仰的真理。從過去的經院神學,安瑟倫、阿奎納等眾多大師,到今天為數不少的神學家...但是,這在我看來是不可能的,儘管他們的心志令人敬佩。從伊甸園以來,亞當選擇「分別善惡樹」的果子開始(可別被尼采騙了,那可不是什麼智慧樹),人的理性就已經墮落了,墮落的理性是無法導出真理的本體。 主耶和華如此說。聽的可以聽,不聽的任他不聽,因為他們是悖逆之家 。 在以科學、理性為基本信仰的現代,基督徒當走的,不是跟他們一樣轉變自己的根基,乃是要持守那顆神所賜下的信心。 因為知道我所信的是誰

C 語言新手十二誡

這篇文章來自於 PTT 的 C_and_CPP 看板 原文在 http://www.lysator.liu.se/c/ten-commandments.html 很有趣的是,原作者這篇文章是用古英文書寫,大概是為了模仿 KJV 的聖經吧 下面是用 潘科元(Khoguan Phuann) 的翻譯版本,一來中文比較好讀,二來還加上了範例 第十一、十二誡為 ptt 網友 nowar100 新增,一併增加如下。 一、你不可以使用尚未給予適當初值的變數。 錯誤例子: int accumulate(int max) /* 從 1 累加到 max,傳回結果 */ { int sum; /* 未給予初值的區域變數,其內容值是垃圾 */ int num; for (num = 1; num <= max; num++) { sum += num; } return sum; } 正確例子: int accumulate(int max) { int sum = 0; /* 正確的賦予適當的初值 */ int num; for (num = 1; num <= max; num++) { sum += num; } return sum; } 二、你不可以存取超過陣列既定範圍的空間。 錯誤例子: int str[5]; int i; for (i = 0; i <= 5; i++) str[i] = i; 正確例子: int str[5]; int i; for (i = 0; i < style="color: rgb(255, 0, 0);">三、你不可以提取(dereference)不知指向何方的指標(包含 null 指標)。 錯誤例子: char *pc1; /* 未給予初值,不知指向何方 */ char

選舉過後

今天早上出去投票前,我特地把選舉公報拿出來看一下,想說就算不太在意政治,好歹看一下候選人的政見吧...結果...我居然找不到... 一份沒有選舉政見的選舉公報...某種程度上來說,就跟現在台灣的政治狀況一樣,沒有政見,只有口號;沒有思考,只有謾罵。很多人喜歡拿學術當作盾牌,來證明自己講的很有道理,殊不知,「學術」,不過就是一個各說各話的平台。本來在學術的殿堂中討論也不錯,但很容易加上情緒性的謾罵字眼,表明瞧不起對方...最明顯的大概非我老爸的那群同學吧,每個都是台大經濟出身,每個地位都非常顯赫(除了我老爸之外),有藍有綠,兩邊打死互不相往來...同樣都是經濟高手,同樣都能引經據典,但永遠不能對談的一群人(更可憐的是那些引用這些高手言論卻又毫無思想而進行批判對方的那些人),難怪...有人只要「一隻手」的經濟學家了... 遺憾的是,選舉的撕裂,竟然也燃燒到了教會。我永遠不會忘記那年華神的二二八事件...那些抗議的基督徒,那些所謂追求公義的基督徒,根本只是在追求賠償,把對方視作死敵,卻忘了聖經告訴我們說:「若是能行,總要盡力與眾人和睦」...可憐的華神老師,就因為一些研究疏失而被犧牲了... 行公義、好憐憫、存謙卑的心...每次選舉我都會在論壇報上看到,殊不知,最重要的是下一句話:「與上帝同行」。基督徒的精神,應當是「寧叫天下人負我,不叫我負天下人」才是,但...每到選舉,基督徒永遠都在審查別人、對方的候選人,而不會一視同仁的對待己方的候選人(沒有針對哪一邊,因為兩邊都一樣) 我很討厭選戰這兩個字,選舉,不是戰爭;對手,不是仇敵。 選舉,不過是人民對於一些議題呈現的選擇...以政治來說,這樣的說法很天真,但是,卻是民主真正的價值,雖然,我一直認為由神主到民主是一種退步... I have a dream that one day this nation will rise up and live out the true meaning of its creed: "We hold these truths to be self-evident: that all men are created equal." I have a dream that one day every valley shall be exalted, every hill a

GNU Multiple Precision Arithmetic Library

在開發程式的過程中,程式設計師不一定每一個原件都會純手工打造,事實上,很多東西會直接使用現有的工具。一來可以節省開發的成本,二來自己實作可能也比不上現有工具的功用跟效能(或許還會產生不少BUG)。所以在這裡也會介紹一些好用的工具或是函式庫。當然,前提這些東西都是自由或是能免費取得的。 名稱:GMP~GNU Multiple Precision Arithmetic Library 網址:http://gmplib.org/ 功能:提供大數運算 大數運算是一個很重要的功能,特別是在處理數學問題、密碼學演算法上面。傳統C語言所能提供的數字運算,最多是到 double (以 32-bit 的機器來說,通常是 64-bit),但這對動不動就要 128 bit 的密碼學演算法來說,根本不敷使用。今天介紹的這一套 GMP,就是一套提供大數運算的函式庫。這套函式庫很有意思,他還把計算RSA的速率跟 Openssl 進行比較,結果呢,當然是樂勝囉~ 這套函式庫提供了整數、分數、小數的型態,下面「稍微」看一下人家是怎麼設計的。我們只看看整數的部分,並且看一下人家的加法是如何處理的。 typedef struct { int _mp_alloc; /* Number of *limbs* allocated and pointed to by the _mp_d field. */ int _mp_size; /* abs(_mp_size) is the number of limbs the last field points to. If _mp_size is negative this is a negative number. */ mp_limb_t *_mp_d; /* Pointer to the limbs. */ } __mpz_struct; mpz 就是GMP中的整數型態。簡單來說,他是拿一串 limb 串起來來當作大數, limb 就是一般程式中所使用的數學型態。(根據平台不同,可能是 unsigned int or unsigned long),然後他還會記錄 size。 我認為,mp_

改程式的掙扎

在工作上,如果遇到前人所留下的難看程式,到底該怎麼辦? 所謂的難看程式,指的是會動,能正常運作,但是架構混亂、難以閱讀,甚至還很容易隱藏潛在的危機。本來嘛,這種程式不動它也就是了,可是偏偏又要在上面提供新的功能,這時候,身為接手人員,到底應該怎麼做呢?是大破大立,還是在危樓上持續建造呢? 目前在資策會工作這兩年,總共遇過兩次(其實也才遇過兩年,也就是一年一次囉)。這兩次,我的作法都是~砍掉重練。第一年,因為是科專計畫,只要呈現給長官和經濟部的官員看,再加上整個計畫的人力不過三個,在達成一致決議後,花了幾個月的時間將東西完工。雖然做的沒有很出色,但穩定性已經大幅提昇(當然是跟之前的東西比),而且也在過程中學到了不少東西(感謝當初的另外兩位同仁)。去年的計畫,我也做了同樣的決定,但這次不一樣了...這次不但是科專的呈現,還有廠商的產品要交付,互通性測試要通過,無止盡的「死線」...而且整天還要面對測試人員的壓力。對測試人員來說,他們不會看到程式碼,他們只在乎外在的功能,他們在意功能是否完善,特殊的CASE是否能安然度過,新的功能運作如何,但卻不會在意程式的維護性如何、還有程式內有多少的隱藏危機... 打掉重建,我自認將程式改的更容易閱讀,也更容易維護或是加上新功能,但是這段改程式的陣痛期,卻是測試人員所無法瞭解的(當然了,他們也有自己的時程壓力)。反而,原先會動的功能,可能因為程式重建過程中一些粗心大意的疏漏(還不少),反而會無法運作。他們只會無法理解的問說:「為什麼?為什麼要這樣改,這樣怎麼測試?」。還好,因為另外一個團對正好再進行大規模的更動,我獲得喘息的機會...今天,大部分的問題已經解決了...甚下就是開始進行新功能的加添、原有 BUG 的修正,還有客制化的動作。但我一直在問我自己,如果時間往前推幾個月,我會做出這樣的決定嗎? 幾個禮拜以前,我到簽約廠商那裡,進行程式碼的講解。講解的程式碼,是舊的那一份。坦白說,我講得很膽戰心驚。我一向不害怕報告,但是我害怕報告自己都無法理解的東西。原有的程式碼,其實架構設計的很...我很擔心廠商問我架構的問題,以及這樣設計的緣由,所以我隨便找了一個理由就帶過去了,好險他們似乎只要東西會動就好(感覺他們根本沒在研究那一塊程式,看來他們的產品出貨後,有可能會被一堆客戶罵吧)交那樣的程式過去,我很羞愧,而且因為接手了,還要掛我的名字

為什麼程式不會動

這是一篇轉貼文章,來源...忘了 老實說,要怎麼分類這文章我很頭痛,要是幾個月前,我一定會把他丟到 Joke 裡面去,但後來我發現,在這段程式趕工的時間,這些話也快要變成我的口頭禪了。來吧,程式設計師們,自己摸著良心說,有誰沒有說過下面這些話的? 第 20 名:這很奇怪喔。 第 19 名:以前從來不會這樣啊! 第 18 名:昨天明明會動的啊! 第 17 名:怎麼可能~ 第 16 名:這一定是機器的問題。 第 15 名:你到底是打了什麼才讓程式當掉的? 第 14 名:一定是你的資料有問題。 第 13 名:我已經好幾個禮拜沒碰那一段程式了。 第 12 名:你一定是用到舊版了。 第 11 名:一定是巧合!為什麼這種壞運氣只讓你碰上。 第 10 名:我不可能什麼功能都測試到吧,有 bug 是正常的! 第 9 名:這個不可能是那個的原始碼! 第 8 名:這程式應該是會動的,只是我寫好後還沒做測試。 第 7 名:可惡!一定有人改了我的程式。 第 6 名:你有檢查過你的電腦有沒有病毒嗎? 第 5 名:儘管這功能還不能動啦,你覺得他如何? 第 4 名:在你的系統不能用那一個版本的程式啦! 第 3 名:你幹嘛要那樣操作,都是你的問題。 第 2 名:程式發生問題時你在哪裡? 第 1 名:在我的機器明明就可以動啊!

有趣的「對」

在中國文學裡面,「對」一直是一個很有趣的東西。當然囉,嚴謹的對仗除了要詞性工整之外,還又考慮讀音的問題。不過,因為個人對讀音實在沒有研究(我怎麼會知道古時候的讀音嘛),而且詞性也不是非常熟,所以任何記錄在這裡的「對」,都是我覺得有趣但不保證嚴謹的。 BTW,所有的對都是看來的,絕對不是我寫的~ 太極兩儀生四象 春宵一刻值千金 相當有趣的對聯,更好玩的是,這兩句都不是原創句。第一句是道家的恢弘的宇宙觀念,第二句卻變成新婚之樂。渾然天成,卻又帶有詼諧的語氣。 寸土為寺,寺旁言詩,詩云:明日揚帆離古寺 兩木成林,林下示禁,禁曰:斧斤以時入山林 這個對相當難對,頭兩句計有各自的意思,又都可以形成一個字。而第三句的開頭跟結尾,還必須用上第二句跟第一句的字。「明日揚帆離古寺」出自哪首詩我不知道,但是「斧斤以時入山林」可是出自於孟子唷~ (我還在網路上看到下面的對法: 十言成計,計中人許,許諾:後世鼎足三分計 ) 二舟並行,櫓速不如帆快 八音齊奏,笛清難比簫和 乍看之下還好,但其實裡面暗藏四個古時候的人名唷,分別是...自己看。更好玩的是,如果把所有的官職分成文官、武官兩類,呵呵,這兩句可是互有諷刺意味呢! 琴瑟琵琶,八大王一般頭面 魑魅魍魎,四小鬼各自肚腸 很常見的趣對,但還是記錄一下。(網路上還看到另一個對: 妹妲姒姬,四美女非凡容貌 )

Linux Process 2 ~ Hash

上一次有提到說,在 Linux Kernel 裡面找尋特定 PID 的 task 不是使用 sequential search,而是使用 hash 的方式,所以現在就來看看它的 hash 到底是怎麼做的! Kernel: 2.6.23 透過 PID 找尋 task 的 API 是下面那一支( kernel/pid.c ): struct task_struct *find_task_by_pid_type(int type, int nr) { return pid_task(find_pid(nr), type); } type? type 是什麼呢?幹嘛要有 type? 先來看看宣告( include/linux/pid.h )吧: enum pid_type { PIDTYPE_PID, // pid PIDTYPE_PGID, // pgid PIDTYPE_SID, // session PIDTYPE_MAX // 用來擔任 enum 的最大值(也許是作為檢查用) }; 後面的註解是我自己加上去的。簡單來說,Linux Kernel 不是單單建立一個 hash table,而是多個,所以要給一個 type 來說明要找哪一個 hash table。接下來就繼續看 pid_task 和 find_pid 到底是幹嘛囉~ struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type) { struct task_struct *result = NULL; if (pid) { struct hlist_node *first; first = rcu_dereference(pid->tasks[type].first); if (first) result = hlist_entry(first, struct task_struct, pids[(type)].node); } return result; } struct pid * fastcall find_pid(int

好用的 Search Script

這是由我同事所寫的小 script,還蠻好用的。經過作者同意後放入自己的 Blog 中。本 script 可以在程式碼中進行關鍵字的搜索。因為簡單明瞭,所以就不加以解說了。 附帶廣告他的 Blog: http://parrotshen.blogspot.com/ #!/bin/bash if [ $# == 0 ]; then echo "Usage: $0 " echo " : $0 " echo "" exit fi dir=. if [ $# == 2 ]; then dir=$2 fi echo "--------------------------------------------------------------------------------" echo "Processing ..." echo "" #list=`egrep -rwl "$1" $dir | egrep "\.(c|h|cpp)$"` list=`grep -rwl "$1" $dir | grep "\.\(c\|C\|h\|H\|s\|S\|cpp\)$"` for x in $list do echo "[[30;47m$x[[0m" grep -wn "$1" $x echo "" done echo "--------------------------------------------------------------------------------"

Linux Process 1 ~ Tasks Lists

圖片
Process,在一般作業系統的教科書給它的定義是「an instance of a program 」。在 Linux 裡面,對 Process 的 Descriptor 是定義在 include/linux/sched.h 裡面的 task_struct。要注意的是, Linux 裡面是採用 lightweight process 的實作概念,換言之,每個 thread 都有一個 task descriptor,而且每個 task 的 pid 都是獨一的。可是,在 POSIX Thread 的標準裡面規定,一個 process 裡面所有 threads 的 pid 都必須相同,所以在 task_struct 裡面多導入了一個變數,叫做 tgid( task group ID ),在同一個 process 裡面不同的 threads 都有不同的 pid,但他們的 tgid 是相同的(這個事實也告訴我們,當我們在應用程式裡面呼叫 getpid() 的時候,其實回傳值是 tgid 而不是 pid 喔)。 接下來要慢慢研究這個 structure。這個 structure 有點複雜,我們先集中在 Task List 的部分。首先我們來看下面的 Macro~ #define next_task(p) list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks) #define for_each_process(p) \ for (p = &init_task ; (p = next_task(p)) != &init_task ; ) 顧名思義,這個 Macro 會將所有的 Process 掃過一遍。每一個存在的 Porcess 都是透過 structure 內部的 tasks( struct list_head )所彼此串起來的。可是有一件很神奇的是,當我們執行 multi-thread 的程式時,我們發現無法透過這個 Macro 來找出除了主線程以外的其他 thread 資訊。對作業系統來說,一個 Process 開再多的 threads 也還是一個 Process,所以在那隻 Macro 裡面是找不到的。那那些被創造出來的 thread descriptor

一次得救,永遠得救

最近被問到關於「一次得救、永遠得救」的看法。就想說趁這個機會,在 Blog 裡面在多開一個分類~「信仰」,包含了自己在神學上的看法、靈修心得、屬靈書籍分享或是聽道的收穫。 「一次得救,永遠得救」之所以這麼令人難以接受,就是因為它太簡單了。為什麼呢?一次得救就可以永遠得救?這不是太便宜了嗎?只要相信、受洗,就可以拿到天堂的入場卷,那麼人又何必如此辛苦奮鬥,勉勵行善呢?相較之下,佛教講求作好事、積功德,在人世間不是更可以散發出美好的人性光輝嗎?而儒家傳統思想裡面,「士,不可以不弘毅,任重而道遠。仁以為己任,不亦重乎,死而後已,不亦遠乎。」這種堅持向善,至死奮鬥的精神,更是令人敬佩。無怪乎 ... 「一次得救、永遠得救」這樣的宗教說法實在是太令人難以相信,或是說太不值得尊重了嗎? 先說我的結論,我相信「一次得救、永遠得救」。 我們來瞭解一下,到底什麼是「一次得救、永遠得救」。並且也看贊成的理由、反對的理由,並且為什麼我會如此信。 加爾文五要義 首先,我們來看看贊成方的說法,在這裡我們以加爾文的理論做為代表,並不是說他是第一個提出這個論點的神學家,而是他整理的比較清楚。加爾文,一位偉大的系統神學家,在他著名的著作「基督教要義」裡面對相關的問題有清楚的介紹,因為著作份量太重了,後人把他在這方面的論點歸納成最著名的「加爾文五要義」 完全無能力(Total inability)或全然敗壞(Total depravity) 從亞當、夏娃墮落以來,人類喪失了向善的本性而抵擋上帝,人類不是沒有自由,但那是作惡的自由(隨己意行做各樣的惡事),而無法認識神、遵行上帝的旨意。 無條件選擇(Unconditional election) 上帝揀選人施行拯救,不是因為有好行為、也不是出於人的信心。乃是憑著上帝永恆的預旨及祂無可測度的智慧來揀選。 有限的代贖(Limited atonement) 基督釘十字架,是為那些在創世以前預先蒙揀選的百姓,而不是為所有的人。 不可抗拒的恩典(Irresistible grace) 人類無法因為任何理由拒絕上帝的救恩。 聖徒永蒙保守(Perseverence of the saints) 凡神所揀選的,神必保守直到永恆,一個也不失落。 這就是著名的鬱金香(Tulip)。很明顯的,所謂的「一次得救、永遠得救」,是屬於「聖徒永蒙保守」的範圍。不過因為這是一整套的理

Variant Arguments

在C/C++(C89)中,有所謂的variant argument(變動引數)這東西。說穿了,就是讓使用者可以輸入不定長度的參數,最著名的例子就是 printf 這個大家都會用的函式。下面就來看看實際上的用法。 首先,在宣告函數上,在所要帶入的參數部分用「...」來表示,如下所示: void func(int, ... ); 這樣就可以讓編譯器不檢查所輸入的參數型態跟數量(但為什麼在 ... 前面還要在多一個參數呢?容後在述)。但是,比較大的麻煩是,我們要如何將所要的參數取出來呢?在 stdarg.h (在 C++ 則是 cstdarg ) 有提供一個好用的型態以及一些巨集,分別列在下面: type: va_list : type for iterating arguments macros: va_start : Start iterating arguments with a va_list va_arg : Retrieve an argument va_end : Free a va_list va_copy : Copy contents of one va_list to another(這是 C99 的標準) 我們先來看看一個實際的例子。下面的函式,第一個參數代表的是總共有 n 個參數(不含他自己),然後把後面所有的參數都印出來(並且假設後面所有的參數型態都是 int ) void func(int n, ...) { va_list args; va_start(args, n); while(n>0) { printf("%d\n", va_arg(args, int)); n--; } va_end(args); } 讓我們看看實際的定義: In stdarg.h ... typedef __builtin_va_list __gnuc_va_list; typedef __gnuc_va_list va_list; #define va_start(v,l) __builtin_va_start(v,l) #define va_end(v) __builtin_va_end(v) #define va_arg(v,l) __builtin_va_arg(v

Linked List in Linux Kernel

Linklist 是最常被使用的一種資料結構,當然在 Link Kernel 中也不例外。下面會介紹在 Linux Kernel 中所使用的 Link List。 當然,按照慣例,排版會按照自己喜歡的格式來進行排 版。 Kernel: 2.6.17 在 Linux 裡面,List 的相關定義函式是放在 linux/include/linux/list.h,而最主要的定義如下: struct list_head { struct list_head *next; struct list_head *prev; }; 很明顯地可以看出,這是一個 double linked list 的架構,但是看起來跟一般我們寫程式所實作的方式並不相同。如果是我們設計的話,我們可能會設計成這個樣子: struct my_list { void *myitem; struct my_list *next; struct my_list *prev; }; 其中 myitem 就是用來存每個 list node 的 Data ,而且為了要泛用,所以使用了 (void *) 這樣的資料型態。 這樣的設計跟 Linux Kernel 的設計到底有什麼差異還不清楚,或許是個人風格吧~ (我同事有發表相關的意見,他認為用 Linux Kernel 的那種作法可以將 list 跟 data 完全的切割,而使用我一般的作法,固然可以達到 list 的效果,但是在參數傳遞上,變數名稱將會是 struct my_list,而無法直覺的看出來實際的資料型態...well ...見仁見智囉) Linux Kernel list 的使用方式,我們看下面一個範例: #include &lt stdio.h &gt #include &lt stdlib.h &gt #include "list.h" struct kool_list { int to; struct list_head list; int from; }; int main(int argc, char **argv) { struct kool_list *tmp; struct list_head *pos, *q; u

平敦盛

平敦盛,生於1169年,死於1184年3月20日(一之谷戰役)。會特別記錄這個人是因為下面這首歌曲: 思へばこの世は常の住み家にあらず。          草葉に置く白露、水に宿る月よりなほあやし。      きんこくに花を詠じ、栄花は先つて無常の風に誘はるる。 南楼の月を弄ぶ輩も月に先つて有為の雲にかくれり。   人間五十年、下天のうちを比ぶれば夢幻の如くなり。   一度生を受け、滅せぬもののあるべきか。 留念今生並非無法忘懷生前之事 有如置於草葉上之露水 寄宿於水中之月 詠嘆京國之花,於榮華之前誘於無常之風 玩弄南樓之月,此輩則似浮雲消逝於黃昏之中 人生五十年 與天下相比,如夢似幻 既一度有此生,又豈有不滅之理 這首歌曲是「幸若舞」的「敦盛」,之所以這麼有名,主要是因為這是織田信長最喜歡的歌舞。相傳在桶狹間前夕信長跳完了這一段舞後,對今川義元發動奇襲;以及本能寺之變的時候,信長也是舞完了這一段「敦盛」,而後步入火舌之中。 「敦盛」這段故事,典故出於日本第一部合戰傳奇「平家物語」,講的是平家的小將平敦盛,在海邊被源家部將熊谷直實對決斬殺的史實:話說熊谷早就聽說過敦盛的大名,據傳敦盛文武兼資,又是當代吹笛名手之一(當代吹笛名手不是姓藤原就是姓平),是平家年輕一代的佼佼者,但是等到交鋒後才發現敦盛年輕到可以當自己兒子(好像是16歲)!於是熊谷的惻隱之心油然而生,本想饒過這個年輕到不可能和源家上代有仇的小孩,但是眼看其他源家人都追上來了,自己不下手,恐怕還得揹個通敵的黑鍋,正在左右為難之際,平敦盛反而催促這名部將下手,蓋敦盛已經看破了武家的宿命即是如此。等到熊谷砍了敦盛的頭,在遺物中發現笛子,突然想起昨天晚上還聽到敵陣中傳來優美的笛聲,看來恐怕就是敦盛的傑作呢,一念至此,當下頓悟人生無常、枯榮轉瞬之理,於是熊谷就出家當了和尚,給後世流下一段令人嘆息的故事。 不由得聯想到平家物語的序之卷... 祇園精舎の鐘の声、諸行無常の響きあり。 沙羅双樹の花の色、盛者必衰のことわりをあらはす。 おごれる人も久しからず、 ただ春の夜の夢のごとし。 たけき者もつひにはほろびぬ、 ひとへに風の前の塵に同じ。 祇園精舍的鐘聲、響徹著警喻諸行定無常律 沙羅双樹的花色、道盡天下盛極必衰的真理 而驕奢者豈能久長 到頭來有如春夜般夢一場 縱使英雄蓋世終將為之一傾 猶如風前土煙塵

Google 大學?

下面是中國時報 2008.01.15 的一篇報導 //-------------------------------------------- 網路時代,只要在網路搜尋引擎Google鍵入關鍵字就能輕易查到相關資料,英國布萊頓大學媒體研究教授塔拉.布拉芭蓉便形容Google是「心智的白麵包」,但她也指出,網路正製造出一個仰賴不可靠資訊生存的學生世代。  據英國《泰晤士報》14日報導,有18年大學教學經驗的布拉芭蓉本周將在布萊頓大學授課。她認為,資訊取得容易使學生的好奇心鈍化,同時抑制了辯論風氣。  此外,許多剛進入大學的學生根本分辨不出網路上張貼的軼聞與毫無根據的資訊之間有何差異,卡拉芭蓉稱這種教育是「Google大學」教育。   英教授批網路資訊不全正確  卡拉芭蓉指出,艱難的問題能從Google找到簡單答案。但學生無從分辨這些答案是來自嚴謹的期刊論文或者只是粗淺的概念,Google的資訊包羅萬象,但未必是有營養的內容。  布拉巴蓉的疑慮與《業餘愛好者的教派》(The Cult of the Amateur)一書的作者安德魯.基恩的看法不謀而合。基恩痛批「線上業餘主義」,他在書中寫道:「現今媒體正在把這個世界撕碎成十億個個人化的真理,每個都看似合理而且等值。」  布拉巴蓉教授指出,學生雖身處在資訊時代,但他們欠缺正確的資訊,他們上到維基百科網站找資料無可厚非,因為唾手可得。可是由網友編撰內容的維基百科曾被批評充斥不正確資訊,甚至它的創辦人之一拉瑞.桑格在去年離開這個網站之前,曾說維基已經「無可救藥」。   資訊易得 學生不作過濾  由於傳統圖書館式微、藏書減少及圖書管理員人數下降,從Google等媒體平台尋找解答天經地義,然而箇中要訣就是學習如何善用網路工具。  布拉巴蓉認為,教師必須訓練學生成為積極批判的思想家,讓學生具備詮釋及過濾網路資料的能力,而不是照單全收。 //-------------------------------------------- Google 的確很好用,但是所查出來資訊的正確性誰也無法保證。在所謂Web 2.0 的年代,人人都有辦法發表自己的智慧結晶,甚至也可以及眾人之力輕易的編出百科全書,但有誰能為這些在網路上的資訊把關呢?事實上,這篇報導是真的?還是假的呢?

三分鐘看完中國歷史

在網路上看到的文章,挺有意思的~ 盤古說:我開 女媧說:我補 共工說:我撞 神農說:我嘗 精衛說:我填 夸父說:我追 后羿說:我射 嫦娥說:沒射著! --------------------------------------------------------------- 黃帝說:我們做什麼 堯說:我讓 舜說:我也讓 禹說:咱爺們怎麼辦? 啟說:讓他們求! 桀說:好玩 湯說:造反有理了 夏亡了…… --------------------------------------------------------------- 紂說:痛快 武王說:我也反了 商亡了…… --------------------------------------------------------------- 幽王說:點火 褒姒說:刺激 周也亡了…… --------------------------------------------------------------- 干將說:我鑄 專諸說:我舞 荊柯說:我刺 瀛政一躲:沒刺著…… --------------------------------------------------------------- 始皇說:我修 姜女說:我哭 陳勝說:有種 項羽說:我舉 劉邦說:我斬 秦亡了…… --------------------------------------------------------------- 孔子說:我仁 孟子說:我義 老子說:我無為 莊子說:我逍遙 韓非子說:把他們全抓了 --------------------------------------------------------------- 張良說:我出謀劃策 韓信說:我統帥三軍 蕭何說:我運籌帷幄 高祖說:老婆,怎麼辦 呂后說:全喀嚓了 --------------------------------------------------------------- 文景說:我治 武帝說:我興 光武說:我中興 獻帝說:我說了不算 --------------------------------------------------------------- 張騫說:我通 班超說:我也通 蘇武說:通個屁! ----------------------

GCC 詳細編譯步驟

使用 GCC 來編譯程式看起來相當容易,如下面的例子: [neokent@FEDORA Projects]$ gcc hello.c -o hello [neokent@FEDORA Projects]$ ./hello Hello World! 但 GCC 到底做了些什麼事呢?多加一個「-v」的參數以後來試試看(下面是實際跑出來的例子,但是為了美觀起見,稍微修改了一下排版) [neokent@FEDORA Projects]$ gcc -v hello.c -o hello 使用內建 specs。 目的:i386-redhat-linux 配置為:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-cpu=generic --host=i386-redhat-linux 執行緒模型:posix gcc 版本 4.1.2 20070925 (Red Hat 4.1.2-33) /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -auxbase hello -version -o /tmp/ccdKC85q

Paging Structure in Linux

圖片
為了符合各種架構的處理器(包含 64bit 處理器),Linux 所採用的架構是 4-level paging architecture。架構圖如下: 四層架構分別為: Page Global Directory Page Upper Directory Page Middle Directory Page Table 當處理器是 32bit 而且 PAE disabled 的情況下,PUD 和 PMD 是不使用的。 Paging Implementation in Linux Kernel 接下來要看 Linux Kernel 內部關於 Paging 的實作方式。 Kernel Version: 2.6.17 Arch: i386 首先,來看看 page 在Linux Kernel中的定義。 /linux/include/asm-i386/page.h: #ifdef CONFIG_X86_PAE typedef struct { unsigned long pte_low, pte_high; } pte_t; typedef struct { unsigned long long pmd; } pmd_t; typedef struct { unsigned long long pgd; } pgd_t; typedef struct { unsigned long long pgprot; } pgprot_t; #define HPAGE_SHIFT 21 #else typedef struct { unsigned long pte_low; } pte_t; typedef struct { unsigned long pgd; } pgd_t; typedef struct { unsigned long pgprot; } pgprot_t; #define HPAGE_SHIFT 22 在這裡我們可以看到 page entry 和 page directory 的定義。特別要注意的是 pgprot_t,它所代表的含意是「the protection flags associated with a single entry」。至於HPAGE_SHIFT指的是當

IA32 Memory Management

圖片
下面這段資料來自於 「Intel® 64 and IA-32 Architectures Software Developer’s Manual」 The memory management facilities of the IA-32 architecture are divided into two parts: segmentation and paging. Segmentation provides a mechanism of isolating individual code, data, and stack modules so that multiple programs (or tasks) can run on the same processor without interfering with one another. Paging provides a mechanism for implementing a conventional demand-paged, virtual-memory system where sections of a program’s execution environment are mapped into physical memory as needed. Paging can also be used to provide isolation between multiple tasks. When operating in protected mode, some form of segmentation must be used. There is no mode bit to disable segmentation . The use of paging, however, is optional. IA32 Segmentation 和 Paging 關係圖 簡單來說,Segmentation 是處理器上的機制,每一個正在處理器上運作的 task (應該用「任務」呢?還是用「程式」好呢)都會有他自己獨立的 Segment。而所謂的 Logical Address 指的就是處理器上 Segment 的位址。這個機制最大的好處在於保護每個 task 的記憶體區塊不會互相干擾。 在 linux

IA32 Paging Architecture

圖片
Paging Unit:將線性位址(Linear Address,或稱作虛擬位址Virtual Address)轉換成實體位址的功能單元。 在 i386 的系統裡面,因為是 32-bit CPU 的關係,所以最多只能定址到 4GB 的虛擬記憶體。定址方式總共有四種: 4KB/page without PAE enabled 4MB/page without PAE enabled 4KB/page with PAE enabled 2MB/page with PAE enabled 什麼是 CR3 Register points to page table 什麼是 PAE 呢? 在 Intel 的 64 and IA-32 Architectures Software Developer's Manual 裡面給的定義如下: 「Physical Address Extension. Physical addresses greater than 32 bits are supported: extended page table entry formats, an extra level in the page translation tables is defined, 2-Mbyte pages are supported instead of 4 Mbyte pages if PAE bit is 1. The actual number of address bits beyond 32 is not defined, and is implementation specific.」 簡單來說,就是一套讓32bit CPU能夠定址到大於 4GB 的記憶體位址。在Intel的實作裡面,就是把原先 page table 中的 2 個 entries 當成一個 entry 來用,所以從原來的 32bit 延伸到 64bit。不過這裡要注意的是,雖然有 64 bit,不過其實只使用了 36 bit,剩下的 28bit 為 reserved,也就是說記憶體只能支援到 64GB。 Page Directory Entry & Page Table Entry 的欄位詳細資料 下面兩張圖是 IA32 中規定,在 Page Directory Entry 和

刁鑽數學難題?

圖片
上個月在網路上看到一則新聞,「刁鑽數學難題,難倒國中師生」,突然一時興起,想在無聊的DEBUG之餘拿來放鬆心情,不過做完以後心情有點沈重...先來看看新聞報導好了。 ======================================================= 〔記者何玉華/板橋報導〕台灣學生數學能力在國際評比中獲得第一名,但永和國中三年級日前剛結束的第二次段考,一題數學考題難倒九成八學生,家長質疑太難,超過國中能力範圍;縣議會金蘭會議員昨天邀來土城、板橋區八位數學老師試作,時間滴答滴答過六分鐘後,終於有兩位老師解答成功。 永和國中出題老師則透過教育局表示,出題時也思考過學生的答題能力,因此前半段多是難度不高的選擇題、填充題,只有最後的三題難度較高;當初也考慮到時間的排擠性,因此安排在最後回答,避免學生浪費作答時間。 縣議會金蘭會議員金介壽、黃林玲玲、李肇南、鄭世維、黃桂蘭昨天舉行「考學生?烤老師?通通倒」記者會;金介壽說,接獲不少永和國中學生、家長反映,段考有一題數學題目超難, 有學生家長在大學理工科系任教,每題都會,唯獨這一題不會 , 甚至是老師講解也「掛」,一整節解不出來,邊解邊罵。 黃林玲玲說,他把題目拿給就讀清華大學應數研究所的兒子看,兒子雖然成功解答,但表示不知道現在的國三生是不是已經有能力解題;她強調,考試不是要考倒學生, 如果題目有三分之一的學生不會,老師就要思考,要讓孩子了解學習的能力可以解決問題 。 鄭世維、李肇南質疑,是否課堂上教得越難,要讓學生去補習才學得會,他們痛斥這是「教改的失敗」;黃桂蘭也表示,段考是要幫孩子提升數學的能力,不是要考倒學生,要求各校應該要有教學領域的審題制度。 教育局主任秘書洪啟昌表示,各校目前都有審題跟出題的制度,只是實施的方法略有不同;永和國中除出題老師外,還有另一位老師就配分審題,只是沒有進行實質題目討論。 ======================================================= 在發表感想之前,先來看一下題目吧。題目如下: 請算出下列黃色區域的面積。 恩,看起來好像有點難,但這真的無法可解嗎? 對一般理工科的大學生來說,起碼可以用微積分來算吧!當然了,我們不能要求國中生使用微積分這樣不合理的技術,那應該要怎麼作呢? 看看上面的輔助線圖,答案其實就是正中央的綠

很壞很壞的駭客

此事件發生在德國一個名為 stopHipHop 的 IRC channel 上 地點:IRC-Channel #stopHipHop (譯者註: 依名稱來看,這個 IRC 交談室的設立人應該不太喜歡 HipHop 曲風) 角色介紹: Elch~ : 推斷可能是 IRC 交談室 #stopHipHop 的設立者 bitchchecker~ : 號稱"厲害"的"駭客" (推測可能是個 HipHop 迷) Metanot~ : 聊天插花者 #1 HopperHunter|afk~ : 聊天插花者 #2 He~ : 聊天插花者 #3 (以下為 #stopHipHop 的 log 紀錄檔) -------------------------------------------------------- QUOTE * bitchchecker (~java@euirc-a97f9137.dip.t-dialin.net) Quit (Ping timeout#) (Log 紀錄) (不明原因 time-out) * bitchchecker (~java@euirc-61a2169c.dip.t-dialin.net) has joined #stopHipHop (Log 紀錄) (bitchchecker 登入 IRC) bitchchecker~ 你為什麼踢掉我? bitchchecker~ 可以解釋一下嗎? bitchchecker~ 回答我呀! Elch~ 我們沒踢掉你啊! Elch~ 是你自己 ping timeout 的 (紀錄): * bitchchecker (~java@euirc-a97f9137.dip.t-dialin.net) Quit (Ping timeout#) bitchchecker~ 什麼 ping 啊.. 老兄 bitchchecker~ 我電腦的時間是正確的... bitchchecker~ 我還設定了日光節約時間耶! bitchchecker~ 是你踢掉我的啦! bitchchecker~ 承認吧!你這個王八蛋! HopperHunter|afk~ lol 哇哈哈! HopperHunter|afk~ 你這個呆瓜... 哈哈日光節約時間!.... bitchchecker~ 你給我閉嘴!!我