2011年6月21日 星期二

[google]Google Web Font

我在今年的 Google io 2011,看到一件很開心的事。
他們居然要做字型這一塊!

字型這件事,在 2002 年附近我用 gentoo 的時候,遇到很多問題。
當時支援 unicode, UTF-8, big5 的中文字型大多是 windows 的字型。
要使用好看一點的中文只能去找 windows 的 ttf 來用。
這要合法使用,得要你有 windows 作業系統才行。
後來,有王漢宗教授的自由字型,真是很大的福音。
不能說華康做字型就讓他們餓肚子,但是沒有好看的中文字型,
要用 linux 印報告真的是很難看。
其中,令我最不能理解的是字型牽扯到的商業行為,
使用字型的部份我比較沒有意見,
但是誰可以做字型卻有得讓我不能理解。

假設說,我看著AA少女體,做一個BB少女體,說我侵權,侵犯AA公司的權利,
我可以接受。
要是我看著AA柳公權,做一個BB柳公權,也要說我侵權,我就不能接受。
而這一塊,當年是有爭議的。
我當時不能理解的是,柳公權的字,怎麼會被一家公司做成字型檔之後,
後面的人就不能再自行做成字體?又不是檔案直接copy!
當然當時我不是做字型的人,我無法理解,
但是我後來也可以自己解釋為字型這一塊難生存的原因就是如此。

現在 Google web font 的專案,說是所有字型都是自由使用,
也提供機制讓人可以隨喜捐!
對於製作字型的人來說,就好像畫家有一個免費的藝廊可以展示,
甚至獲得金錢上的幫助。
我建議王教授可以將字型給他們 hosting,中文字型現在他們還沒有,
我們自己用的中文字型怎能缺席呢?

[google]Accessibility

Google I_O 2011- Accessibility- Building Products that Everyone Can Use

  1. accessibility 指的是一種能力,讓別人方便使用的能力。
    一般舉例會用讓眼睛不好,也能使用你的產品,
    但更廣義的說,也包含沒滑鼠的情況,也能使用你的產品。
    所以更考量人機介面讓人好操作。
  2. 因為一般人不會覺得有什麼差別,所以 demo 的時候就是設定一個極端的情況。讓 chrome 可以讀出聲音,把字放很大,只用鍵盤控制。
  3. google介紹Chrome integration with screen readers,ChromeVox,ChromeShades
  4. 有關 android 的部份,則是介紹使用一個 reader,只使用 touch pad 來操作上一頁,下一頁,字放大,選擇,讀出聲音。
  5. 關於讓你的應用程式具有 accessibility 他們建議,使用標準 toolkit,讓所有的工作都可用鍵盤完成,注意tab順序及焦點,以及在 screen reader 上試一下效果如何。

2011年6月14日 星期二

[c][程式]處理2進位混合資訊

最近遇到有人把3個資訊編到一個變數裡。
他們是這樣做的:
0001 0000010 00100
上面是一個16個bit,分成3節。
第1節就當做是section,第2節當做變數id,第三節當做步驟順序。
因為這3節是各自獨立,因此是三個獨立軸,這16bit展開成一個空間。

當我們拿到這一個16bit的東西的時候,在程式裡是整數,
也就是看到的時候是 4164,我們要怎麼處理這種東西呢?

當然一個最直覺的做法是,轉成2進位!
是的,腦筋是可以轉成2進位,但是寫c語言,我們不知道怎麼寫2進位的表示法。
if (a == ‘00100’) //這東西我不知道怎麼寫出來。
那寫成16進位呢?2進位轉16進位是一次4bit,又遇到不是4bit的一組,
導致很難處理。

有人大嘆一句為什麼不是10進位?10進位就好做了!
為什麼10進位就好做?
因為上面的數字是10進位,
要找到section,就是數字除10的12次方,
要找到變數id,就是數字除10的5次方。

對,10進位會做,為什麼2進位不會做?
只是被進位系統搞暈了。
4164 除 2的12次方,也會等於section。
4164 除 2的 5次方,也會等於變數id。

用整數的加減乘除就可以把三個值分別找出來。
0001 0000010 00100 = 4164
section = 4164 / 4096 = 1 //只要整數部份,小數直接捨去
變數id = (4164 – 1 * 4096) / 32 = 2 //只要整數部份,小數直接捨去
步驟順序 = (4164 -  1 * 4096 – 2 *32) = 4 //只要整數部份,小數直接捨去

有常寫c語言的人,一定還會弄出一招,就是bitwise的operation,&還有>>。
想法切入點不一樣,結果會是一樣的。

2011年6月8日 星期三

[c][c++]AIX cpp, VC++ cpp, VC2005 cpp

雖然說,只用 ANSI lib 的同樣的程式 應該」都可以直接跑,
事實上,還是辦不到。

舉例:
AIX cpp 可以
#include <userinclude.cpp>
只要把 cpp 放在同一個目錄。
但是
在 VC++ 眼中犯了兩個錯誤,
(1)自己的 header 檔放在同一個目錄的,要用雙引號夾起來。
(2)include 要是 header 檔,不然會出現 link 失敗。
所以要改成
#include "userinclude.hpp"

舉例:
AIX cpp, VC++ cpp可以不宣告
using namespace std;
就使用 cout << "abc" << endl;
但是
VC2005 cpp 就說不行,
using namespace std;
一定要加上去!

舉例:
AIX cpp 的 字元 array 可以設到 9999999 (有7個9)
VC++ cpp,VC2005 cpp 卻會出現 stack overflow。(一進 main 就發生)
要特別把stack 放大,或是把該變數放到global,或是動態配置。
參考:http://legnaleurc.blogspot.com/2007/06/cstack-overflow.html
參考:http://tw.myblog.yahoo.com/josh-chang/article?mid=1340

舉例:
AIX cpp 可以對 NULL pointer 執行 strlen。
但是 VC++ cpp 卻會發生 access violation。
實在有很多要修的地方。
也就是說,原本大家想的程式碼搬過去就會動這檔事,
真的只是自我感覺良好。

[python]every one should touch python one day

很早以前就開始知道python,在跟ruby比較,我猶豫了很久。
在工作上,我發現python只要下載安裝檔,其他的部份安裝比ruby「方便」。
因為多是整個目錄放好就行了。

到了研究所,要寫作業或是論文的程式,我也想了很久。
如果沒有介面的東西,還是用python來做,因為不用擔心型態,
可以一邊探索一邊寫,不用擔心如果一開始的型態或是object沒有設計好,
一改就是一大堆。

但是python不是沒有缺點。他的缺點就是他的優點所帶來的。
這件事情告訴我們一句俗語「有一好沒有兩好」。

google有一群人使用python,也因此,他們所推出的api,或是工具常常會是python。
然而GWT使用java,原因之一是java的人比較好找。我個人認為string typing也是原因之一。

每個人都應該看完google io 2011的 Python@Google,然後考慮一下才對。

以下關鍵字,有空去查一下。有要確定用python再說。祝福你。

diveintopython.org
corepython.com
cp4k

2011年5月2日 星期一

[mac]OSX的排程器

這種文章怎麼會出現?
你問用linux的人,他會回答你可以使用cron,
你問用windows的人,他會回答你使用工作排程器。
你問OSX的人,則眾說紛云,
有的回答說iCal,
有的回答有gui app可以設定,像是http://macscheduler.net/
有的告訴你內建的排程器可以開關機,
有的告訴你各個小程式自己可以定時執行…。
超傷腦筋!!

會這麼亂的緣故我覺得是寫mac程式的人太好心了,把功能都寫好好,
所以一般end user才不管原來OSX那些系統管理員才要去設定的東西。
其實 OSX 也有 cron (linux 很常用),也有 at (這個 windows 也有),
都是指令列的,所以,mac user 誰會去搞指令列的?
請乖乖用http://macscheduler.net/

如果真的受不了,那請參考 launchd 這個
http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/Daemons.html#//apple_ref/doc/uid/TP40001761-SW1

或者 cron
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man8/cron.8.html#//apple_ref/doc/man/8/cron

或者 at
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/at.1.html#//apple_ref/doc/man/1/at

完畢

2011年4月14日 星期四

[C]指標與除錯

最近工作上,遇到了C語言,這個東西是威力強大,
可是,若沒有現成的函式庫,只有標準的函式庫。
那真的很多東西都要先打造完畢,才能開始工作,
不然就是整天在字元裡面打轉,只能見樹不見林。
要解決問題,真是遙遙無期。

尤其是,C語言裡面,變數其實只是位址的代表,
更厲害的是指標的概念讓大家更搞不清楚狀況,
再加上函數的傳值呼叫,指標的指標,取址,
這幾個加起來的效應跟蝴蝶效應一樣。

其實萬法歸宗,在除錯的時候,尤其是處理指標的時候,
要記得變數只是位址,變數值的意思是隨人解釋。
其實 VC++ 的整合開發環境都會有每個變數的名字、位址及值可以查看。
一步一步來是可以體會的。
如果沒有這一類的整合開發環境,只好使用
printf(“%p”,變數)
來看變數的位置還有值。

例如有個需求是「動態字串陣列」,在主程式是這樣寫

int main(int argc, char ** argv){
char **buffer = NULL;
//開始加值
char * t1 = “t1”; //對,字串就是字元陣列的痛苦開始了,所以才要指標的指標。 //第一行
buffer = (char **)realloc(buffer, 1 * sizeof(char *)); //第二行
buffer[0] = t1; //第三行
//加第二個值
char * t2 = “t2”; //第四行
buffer = (char **)realloc(buffer, 2 * sizeof(char *)); //第五行
buffer[1] = t2; //第六行
}

這樣是可以的。可是每次都要copy paste這麼多,還要去改 index,忘了改到就完蛋了。
的確是需要一個函式來幫忙。就來開始改造。

void bufferadd(char ** buffer, char *str, int size)
{
  buffer = (char **)realloc(buffer, size * sizeof(char *)); //第一行
  *(buffer + (size - 1) = str; //第二行
}
int main(int argc, char ** argv){
char **buffer = NULL;
//開始加值
char * t1 = “t1”; //對,字串就是字元陣列的痛苦開始了,所以才要指標的指標。 //第一行
bufferadd(buffer,t1,1); //第二行
//加第二個值
char * t2 = “t2”;  //第四行
bufferadd(buffer,t1,1); //第五行
}

看起來簡單多了對吧,可是這是錯的。因為函式是傳值呼叫,所以問題很大。

新主程式的第二行,buffer的值這時候是 0 。
接下來,進到 bufferadd 之後,buffer 的值是11000d9d0, str 的值是1000015a8
函式第二行,把位址11000d9d0的值填入1000015a8。
第二次進來的時候,buffer 的值是11000d9f0,str 的值是1000015ac
函式第二行,把位址11000d9f0位移一格到11000d9f8的值填入1000015ac。
然後出函式在主程式看,所有的資料是空的。

為什麼?函式裡面自己做開心嗎?函式結束後,主程式的buffer的值還是0。
因為傳值呼叫,函式內無法對主程式的變數處理。

因此,把主程式的buffer的位址傳進去,再改一次。
bufferadd(&buffer,t1,1);
因為如此,bufferadd 的宣告也要變成 void bufferadd(char *** buffer, char *str, int size)
所以整個函數也跟著變

void bufferadd(char *** buffer, char *str, int size)
{
  *buffer = (char **)realloc(buffer, size * sizeof(char *)); //第一行
  *(*buffer + (size - 1)) = str; //第二行
}

新主程式也改成

int main(int argc, char ** argv){
char **buffer = NULL; //第一行
//開始加值
char * t1 = “t1”; //第二行
bufferadd(&buffer,t1,1); //第三行
//加第二個值
char * t2 = “t2”;  //第四行
bufferadd(buffer,t1,1); //第五行
}

依我實際執行的結果,在
主程式執行第一行之前 buffer 的位址是 ffffffffffff980,指到的值是0
所以在第三行執行的時候,要把 ffffffffffff980 傳進函式 bufferadd
在函式 bufferadd 內部檢查一下,
buffer 的位址不是ffffffffffff980,是ffffffffffff940,buffer的值是ffffffffffff980
但是 *buffer 是 0。
問題就在這裡。在函式裡的buffer是一個新的變數,有自己的位址,它的值是主程式的buffer的位址。(都是從這裡搞混的。)
在函式內部的第一行,就是要求幫 *buffer ,重配一組記憶體來用。
配到的是11000d9d0
在函式內部的第二行,把位址 11000d9d0  的值,設成字元指標的位址(1000015a8)。
第二次函式呼叫的時候,*buffer 重配記憶體,還是同一個位址11000d9d0。
(用realloc的話沒事不會移動。)
因要塞入第二組資料,所以把位址移動一格(位址+8)。所以是11000d9d8。
把位址 11000d9d8 的值,設字元指標的位址(1000015ac)

回到主程式,buffer 的位址ffffffffffff980,指到的值現在是11000d9d0。

也就是說在函式做完回到主程式之後,11000d9d0 開始的空間,
就有我們要的東西了。

執行結果整理成下表,有括號的是註解

變數名 位址
主程式的buffer ffffffffffff980 (一開始是0,由函式內*buffer=(char*)realloc(*buffer,1)指定為11000d9d0)
主程式的t1 1000015a8 “T1\0”
主程式的t2 1000015ac “T21234567890\0”
  11000d9d0 1000015a8
(在函式內*(*buffer)=str;指定)
  11000d9d8 1000015ac
(在函式內*(*buffer+1)=str;指定)
函式的buffer ffffffffffff940 ffffffffffff980
函式的str   1000015a8(第一次)
1000015ac(第二次)

 

好累…,記得以前就搞懂一次了,現在又再搞一次,希望不要再碰這個了。
不要怪我用這麼多指標…