2012年3月30日 星期五

阿妹2012台北演唱會

如果沒有這次參加阿妹的演唱會,
我實在很難想像一個歌手的影響力是這麼巨大!
全場隨著阿妹一起抒情、搖滾、懷舊、唱唱跳跳。
我很高興,能夠參與這天的演唱會,
已經不只是演唱會,
而是欣賞就這一刻的阿妹的演出,
有一種恰到好處的舒適。

演唱會中阿妹說,她也曾經不知道自己未來的方向,曾經挫折的泣訴自己不會唱歌。
但是當我聽到她親口說出
"我真的很喜歡唱歌"
"我不知道我不唱歌的話,我還能幹什麼"
"我的決定是對的"
我真是他馬的感動。
聽她唱海闊天空那段,配上她背後的回憶紀錄片,好像看到正在發出靄靄光芒的阿妹。
而中間那段40分鐘unplugged連續演唱是我覺得氛圍最好的部份,
都是緩緩的慢歌,
但放輕鬆,思緒會一直被她的歌聲給帶動。
最後一段則是快歌,整場很High,
就算我這種很難High的人,還是有跟著音樂一起搖擺一下身體,
也不會太彆扭拉。

當然演唱會還是有美中不足的部份,
例如說我斜後方的仁兄,唱的比阿妹大聲就算了,難聽我也還可以勉強忍耐,
但是連阿妹在即興的轉音,你老兄都硬要跟上是哪一招,血輪眼嗎,真的很刺耳。
另外不知道哪邊傳來的腳臭味,
阿妹說可以大聲跟著唱,
但有說可以脫鞋嗎?x的。

很感性,但也很High!阿妹的演唱會很讚!

2012年2月19日 星期日

Linsanity

前幾天和老婆去爬了內湖金面山 還蠻有趣的呢
不是那種很無聊地爬樓梯迴圈行程
有點難度(對於平常只去爬陽明山二子坪或是四獸山的我而言)
一開始的階梯坡度還蠻陡的
接下來有些路必須在大石頭堆中攀爬
要手腳並用
拉著繩索踩著大石頭的凹槽向上
爬到山頂後視野雖不算頂好
但有些大石頭就在懸崖旁
蠻適合爬上去坐著或躺著發呆
搞不好會有鳥飛到你附近也說不定
很不賴喔 我喜歡這座山 挺特別
中午出發 慢慢走 走超慢 大概三四個小時可以回到山腳下(當然是不迷路的情況下)
有某些路段只有岩石可以攀附
下雨天會蠻難走的就是

Linsanity也在這禮拜開始正式發燒
到今天已經燒了第9場了
MOD用了一年
我終於覺得錢沒有白花了(還好今年還有奧運)
過漁夫那球太棒了
還有在三分線做個假動作後橫移再冷靜的出手命中
Live直播看到時 都跳起來了

雅妮也很厲害
當天看Live直播
看到18洞那球很漂亮的攻果嶺
就落在洞口旁邊
太爽拉
雖然我老婆一直說你變胖了

而且我發現我是看運動節目的天才
以前一直覺得看不懂高爾夫
覺得很無聊
但那天居然也看了最後5洞

繼續發光發熱下去吧兩位Rising star
有不少人的生活都會因為你們而改變
(至少我現在覺得裝MOD還算值得)

不過也有幾件令人down的事情
像是敘利亞的血腥鎮壓
那天看到PTT鄉民的分享 感覺好沉重阿
還有惠妮Houston和鳳飛飛的falling
R.I.P.

2011年1月24日 星期一

Reverse a single linked list - 反轉一個串列

#include <stdio.h>
/*************************************************************
 * Struct definition
 *************************************************************/

typedef struct{
 void *next;
 int v;
}item_t;
/*************************************************************
 * Global variable
 *************************************************************/
item_t *Head;
/*************************************************************
 * Function decalaration
 *************************************************************/
int   list_add(int);
void   list_init(int);
item_t* list_reverse(item_t *);
int   list_print();
item_t *list_tail();
void list_remove();
/*************************************************************
 * Entry point
 *************************************************************/
int main(){
 list_init(9);
 list_add(1);
 list_add(7);
 list_add(5);
 list_print();  //9,1,7,5
 Head = list_reverse(Head);
 list_print();  //5,7,1,9
 list_add(6);
 list_add(9);
 list_print();  //5,7,1,9,6,9
 Head = list_reverse(Head);
 list_print();  //9,6,9,1,7,5
 list_remove();
 return 0;
}

/*************************************************************
 * list_init()
 *************************************************************/
void list_init(int value){
 Head = malloc(sizeof(item_t));
 Head->v = value;
 Head->next = NULL;
}
/*************************************************************
 * list_add()
 *************************************************************/
int list_add(int value){
 item_t *p,*tail;
 p = malloc(sizeof(item_t));
 if(p){
  p->v = value;
  p->next = NULL;
  tail=list_tail();
  tail->next=p;
  return 0;
 }else{
  return -1;
 }
}
/*************************************************************
 * list_tail()
 *************************************************************/
item_t *list_tail(){
 item_t *c;
 c = Head;
 while( c->next != NULL ){
   c = c->next;
 }
 //printf("last item is %d\n",c->v);
 return c;
}
/*************************************************************
 * list_reverse()
 *************************************************************/
item_t* list_reverse(item_t *head){
 item_t *p,*c,*n;

 p = NULL;
 c = head;
 n = c->next;
 while( c != NULL ){
  n = c->next;
  c->next = p;
  p = c;
  c = n;
 }
 return p;
}
/*************************************************************
 * list_print()
 *************************************************************/
int list_print(){
 int count=0;//calculate total items in list
 item_t *p = Head;
 if( p == NULL){
   printf("ERR:Head is NULL\n");
   return -1;
 }
 while(p!=NULL){
  count++;
  printf("%d\n",p->v);
  p = p->next;
 }
 printf("total items=%d\n",count);
return 0;
}
/*************************************************************
 * list_remove()
 *************************************************************/
void list_remove(){
 item_t *c,*t;
 c = Head;
 while( c->next != NULL ){
  t = c;
  c = c->next;
  free(t);
 }
}

2010年10月13日 星期三

Linux下time_t,struct tm,還有時間相關的一堆函式

搞不清楚Linux下面的time_t,struct tm,還有時間相關的一堆函式。

其實不是Linux的錯,是大家平常不那麼在乎時間的定義,或者說平常不在乎也沒關係。
時間要分成兩種,本地時間跟世界時間。
本地時間指的是當地的時間,像是台北時間,香港時間,美國時間,
世界各地方的本地時間是不同的。
如果你有看王建民的實況轉播的話,
你就會發現台灣現在半夜三點,可是美國那邊卻是出大太陽在下午三點。
或者是台灣現在已經早上8點了,美國那邊還是晚上8點。

本地時間參考的標準其實跟各地日出的時間有很大的關係。
各地的日出時間因為地球自轉的關係,有先後順序的差別,
拿台灣,英國,跟美國東岸來說,
台灣會先日出,過了8小時才輪到英國日出,再過4小時才輪到美國東岸日出。
因此我們說台灣時間比英國時間快了8小時,比美國時間快了4小時。
所以當人家說"你哪來的美國時間"阿,就是指你動作太慢了。
這也是為什麼每年跨年的時候,
台灣會先跨,然後到了隔天中午12點時,
新聞才會開始報導紐約時代廣場的跨年。
這裡可以參考一下鳥哥的文章http://linux.vbird.org/linux_server/0440ntp.php

而UTC(universal time, coordinated),"世界標準時間",指的就是世界時間,
或是也可以想成絕對時間。
各國的本地時間都可以轉換成世界時間,也就是UTC,
這樣世界各地的人就有一個統一的標準時間可以參考了。
這就像英語是全世界共通的語言,但各地仍可以用當地傳統的語言來溝通,
目的是相同的。
UTC其實就是英國法國的本地時間(因為世界世間是他們想出來的)
所以英國的世界時間用UTC來表示,本地時間也等於UTC。
而台灣的本地時間比英國的本地時間快了8小時,
所以台灣的世界時間用UTC+8表示,
(或是說台灣的日出時間比英國的日出時間快了8小時)
而紐約的世界時間則用UTC-4來表示。
(美國的日出時間比英國的日出時間慢了4小時)

回到Linux programming裡面。在Linux下面要看時間,可不是容易的事情。
在Linux下面要經過三個步驟
    1.程式設計師從電腦那邊取counter
    2.把counter轉換為本地或世界時間
    3.將時間顯示為一般使用者看的懂的時間
才能顯示出人類看的懂的時間。
counter是給電腦看的。程式設計師寫了一些函式把counter轉成程式設計師看的懂的,最後程式設計師再轉換成給一般人看的

[步驟一]
首先要知道在電腦內時間是利用counter來計算。
1970/1/1 00:00:00 counter為0。counter每秒鐘加1。
到2010年10月14日 2點59分41秒
(此處都是以UTC為準,此時台灣本地時間應該是2010年10月14日 10點59分41秒)
為止此counter的值為1287025181。
利用time()函式,我們可以取counter的值。
counter的表示就是用time_t來表示。

[步驟二]
取得counter的值後,接下來要作一個轉換。
轉換為程式設計師看的懂的格式(程式設計師也是人),
程式設計師用struct tm來表示時間。
struct tm {
    int tm_sec;         /* seconds */
    int tm_min;         /* minutes */
    int tm_hour;        /* hours */
    int tm_mday;        /* day of the month */
    int tm_mon;         /* month */
    int tm_year;        /* year */
    int tm_wday;        /* day of the week */
    int tm_yday;        /* day in the year */
    int tm_isdst;       /* daylight saving time */
};
有年月日時分秒,清楚多了。
Linux裡面提供了兩個函式可以把counter轉換為struct tm。
使用的函式是gmtime(),或是localtime()。
用gmtime()會把counter轉換為struct tm,轉換出來是UTC時間。
用localtime()跟用gmtime()很像,會把counter轉換為struct tm。
不同的是轉換出來的UTC時間,會再根據本機電腦時區的設定,再轉換為本地時間。

[步驟三]
轉換完之後接著才是顯示給一般的使用者來看。
也就是要把struct tm轉換給一般的使用者看。
顯示的時候用的函式是asctime(),參數是struct tm
這一連串的用法比較...怪,一個簡單的範例如下:
time_t times;
time(&times);
printf("time() is %ld\n",times);                                                          // time() is 1287025181
printf("asctime(GMT or UTC) is %s",asctime(gmtime(&times)));      // asctime(GMT or UTC) is Thu Oct 14 02:59:41 2010
printf("asctime(local) is %s",asctime(localtime(&times)));               // asctime(local) is Thu Oct 14 10:59:41 2010
這邊有一個函式可以簡化asctime(localtime),那就是ctime()。
範例如下 :
printf("asctime(local) is %s",asctime(localtime(&times)));               // ...Thu Oct 14 10:59:41 2010
printf("ctime equals to asctime(local), it is %s",ctime(&times));      // ...Thu Oct 14 10:59:41 2010
有沒有,雖然一個呼叫asctime(),一個呼叫ctime(),但是輸出卻是一模一樣。

如果程式設計師不喜歡asctime()顯示的方式時,可以改用strftime()這個函式。
範例如下:
char tbuf[64];
strftime(tbuf,sizeof(tbuf),"%Z:%Y/%m/%d %H:%M:%S",gmtime(&times));
printf("%s\n",tbuf);                                                                                             // GMT:2010/10/14 02:59:41
strftime(tbuf,sizeof(tbuf),"%Z:%Y/%m/%d %H:%M:%S",localtime(&times));
printf("%s\n",tbuf);                                                                                             // CST:2010/10/14 10:59:41

因此讓使用者看到目前時間的整體流程圖大約如下所示:
Machine - time() -> time_t -> gmtime() or localtime() -> struct tm -> asctime() or strftime() -> User

[reference]
http://zh.wikipedia.org/zh-tw/UTC%2B8
http://en.wikipedia.org/wiki/Coordinated_Universal_Time
http://linux.vbird.org/linux_server/0440ntp.php
http://linux.die.net/


 

2010年9月5日 星期日

Makefile-把多個程式連結在一起的寫法

執行make的時候總會去找一個叫做Makefile的東西。
========
Makefile範例
====
CC = gcc
CFLAGS =
INCLUDE_PATH = .
SRCS = red.c blue.c
OBJS = $(SRCS:.c=.o)
PROGRAM = exe
all:
<TAB>make $(PROGRAM)
$(PROGRAM):$(OBJS)
<TAB>$(CC) $(OBJS) -o $@
%.o: %.c
<TAB>$(CC) $(CFLAGS) -I$(INCLUDE_PATH) -c $< -o $@
clean:
<TAB>rm -rf *.o
<TAB>rm -rf $(PROGRAM)
========
在執行make時會有這樣子的輸出:
make exe

make[1]: Entering directory `/usr/src/local/test/fp'
gcc -I. -c red.c -o red.o
gcc -I. -c blue.c -o blue.o
gcc red.o blue.o -o exe
make[1]: Leaving directory `/usr/src/local/test/fp'
 
在執行make clean時會有這樣子的輸出:
rm -rf *.o
rm -rf exe

函式指標(function pointer)-用途

我喜歡用"寫程式的先後順序"來理解 函式指標。

假設兩位程式設計師Red,Blue同時合作撰寫一個"顯示時間"的專案。
Red負責取得系統時間,Blue負責顯示(電子鐘,復古鐘,給寵物看的鐘,...whatever)。
這時候程式的寫法大約是這樣
========
Project : SHOW CLOCK IN VARIOUS TYPE
====
//blue.c written by blue
void blue_show_clock_digitial(time_t t){
  printf("Now:%02d:%02d:%02d\n",t.hour,t.min,t.second);
}
void blue_show_clock_1(time_t t){/*Not implemented yet*/}
void blue_show_clock_2(time_t t){/*Not implemented yet*/}

void blue_show_clock_3(time_t t){/*Not implemented yet*/}
//...//
====
//main.c written by red
time_t red_get_clock(){
  /*
   *Do something to get time
   */
  return time;

int main(){
  /* ... */
  time = red_get_clock();
  blue_show_clock_digital(time);// This function is implemented by programmer 'blue'
  /* ... */
}
========
這時候注意程式碼撰寫順序的問題。
理論上來說red所撰寫的程式未來幾乎是不太需要再做更改了,而blue所撰寫的程式卻有可能因為使用者的需求而有所變動。
當blue變動的時候,red就需要把blue_show_clock_digital(time)這一行改掉,改成blue所撰寫的函式(blue_show_clock_1()...等等)。

如果我是red,改個一兩次還沒關係,天天都來改的話,我一定會抓狂。(使用者一定會叫blue改,blue就叫我來改...)
每次blue改程式,我就要跟著改,但是事實上我red寫的程式核心幾乎沒有動耶。

這時候就是函式指標派上用途的時機了。看以下範例的改寫
========
Project : SHOW CLOCK IN VARIOUS TYPE by FUNCTION POINTER
====
//blue.c written by blue
void blue_show_clock_digitial(time_t t){
printf("Now:%02d:%02d:%02d\n",t.hour,t.min,t.second);
}
void blue_show_clock_1(time_t t){/*Not implemented yet*/}
void blue_show_clock_2(time_t t){/*Not implemented yet*/}
void blue_show_clock_3(time_t t){/*Not implemented yet*/}
//...//
red_display = blue_show_clock_digitial;
====
//main.c written by red
void (*red_display)(time_t);//red_display is a function pointer
time_t red_get_clock(){
/*
*Do something to get clock
*/
return time;
}
int main(){
/* ... */
time = red_get_clock();
red_display(time);// red_display is a function pointer
/* ... */
}
========
 red先宣告一個函式指標red_display(),然後請blue把這個函式指標red_display()納進blue.c裡面。
每次blue收到使用者需求需要新增一個新的函式時,就把這個新的函式assign給red宣告的函式指標red_display。
 
函式指標需要三個部份,說穿了他只是一個長的比較怪的參數型態:
void (*red_display) (time_t);
回傳值     函式指標名稱          函式參數型態
 
函數指標的assign是這樣:
red_display = blue_show_clock_digitial;
簡單來說就是把return type跟參數type跟括號通通拿掉,然後再用`=`連在一起就好囉。
比較標準的寫法是這樣  :
red_display = &blue_show_clock_digitial;
兩者皆可。


如此一來當使用者修改需求時,只需要blue更改blue.c裡面就可以囉。
對red來說,我以後都不需要再改跟我無關的程式。
對blue來說,比較不需要麻煩別人。
對其他人而言,程式的可讀性(red.c裡面的red_display()是固定的)和彈性(blue修改時不需要跟red同步)變的好多了。
 
這樣子的特性讓函式指標常常會用在做所謂callback function : 先實作的函式(red_display)"call back"後實作的函式(blue_show_clock_xxx)。
由於函數指標可以像是變數一樣,可以在執行時期才做assign的動作,所以就稱為late-binding,late到執行時期,才binding指定的函式。
在大型專案中就會常常發現,像是Linux核心內,隨便撿都有。