星期三, 五月 27, 2009
星期日, 五月 24, 2009
用 Objective-C 從二進位檔案(binary file)中讀入數值的 byte order 問題
要從二進位檔案中讀入數值,其中一個會遇到的問題就是 Little-endian 和 Big-endian,這和 CPU 的種類有關。Intel 系列的 x86 CPU 使用的是 Little-endian,而 PowerPC、ARM 等的 CPU 則是採用 Big-endian。endian 不同的問題,在以前 PPC 的時代算是相當重要,後來改用 Intel CPU 之後重要性就下降了許多,不過現在因為 iPhone 採用的 ARM 又是 Big-endian,所以這問題的重要性又大幅提升了,尤其許多新手設計師,之前可能根本沒碰過非 Intel 的平台,根本沒考慮過這問題,於是寫出來的程式就會讀到一堆詭異的數字。
首先我們要先界定 endian 的問題會影響到哪些資料型別。所謂 endian 不同,是因為高低位元在記憶體中表示的方式不同而造成的,Little-endian 將高位元放在記憶體位址較大的地方,Big-endian 則反之。舉例來說,0x00112233 這個 16 進位的數字,在 Little-endian 的機器上,在記憶體中呈現的是 33 22 11 00,而在 Big-endian 的機器上則呈現 00 11 22 33。因此,假如把在 Little-endian 機器上寫入的二進位檔拿給 Big-endian 的機器讀取,讀出來的數字就會出錯。
從這邊我們可以發現,要發生 endian 的問題,首先資料型別必須用超過 2 個 byte 來儲存才有可能,因此只用一個 byte 儲存的型別,例如 char,就沒有 endian 的問題。
至於 int、long 之類的整數型別,可以用 CFSwap[type][Big/Littile/Host]To[Big/Littile/Host] 系列函式來轉換。其中的 type 可能是 Int16、Int32 等等。使用方法如下:
不過浮點數就沒這麼輕鬆了。我們在前面的例子中還是用 int 來存放 littleEndian,因為就算 byte order 不對了,但它仍然是個 valid 的 integer,不過浮點數的每個 bit 有它不同的意義,因此一旦 byte order 解譯錯誤,它就可能變成 invalid float,導致程式直接當掉。
為了解決這個問題,Objective-C 中用了一個與 byte order 無關的資料結構來儲存這個資料,定義如下:
首先我們要先界定 endian 的問題會影響到哪些資料型別。所謂 endian 不同,是因為高低位元在記憶體中表示的方式不同而造成的,Little-endian 將高位元放在記憶體位址較大的地方,Big-endian 則反之。舉例來說,0x00112233 這個 16 進位的數字,在 Little-endian 的機器上,在記憶體中呈現的是 33 22 11 00,而在 Big-endian 的機器上則呈現 00 11 22 33。因此,假如把在 Little-endian 機器上寫入的二進位檔拿給 Big-endian 的機器讀取,讀出來的數字就會出錯。
從這邊我們可以發現,要發生 endian 的問題,首先資料型別必須用超過 2 個 byte 來儲存才有可能,因此只用一個 byte 儲存的型別,例如 char,就沒有 endian 的問題。
至於 int、long 之類的整數型別,可以用 CFSwap[type][Big/Littile/Host]To[Big/Littile/Host] 系列函式來轉換。其中的 type 可能是 Int16、Int32 等等。使用方法如下:
int littleEndian = 1234;那麼 hostEndian 的變數值就是採用目前機器上的 endian 順序的 int。
int hostEndian = CFSwapInt16LittleToHost(littleEndian);
不過浮點數就沒這麼輕鬆了。我們在前面的例子中還是用 int 來存放 littleEndian,因為就算 byte order 不對了,但它仍然是個 valid 的 integer,不過浮點數的每個 bit 有它不同的意義,因此一旦 byte order 解譯錯誤,它就可能變成 invalid float,導致程式直接當掉。
為了解決這個問題,Objective-C 中用了一個與 byte order 無關的資料結構來儲存這個資料,定義如下:
struct CFSwappedFloat32 {可以看到,這個結構中就只有一個 data,uint32_t,Objective-C 就是用它來儲存這個 float 的資料(當然,此時系統並不會把它當成一個 float)。接下來的處理方式就是,將這個 uint32_t 裡面的 byte 頭尾互換位置,然後將這 32 個 bit(4 個 byte)轉化成 float。而這就是 CFConvertFloat32SwappedToHost 這個函式在作的事。整個的用法可以用以下的例子表示:
uint32_t v;
};
typedef struct CFSwappedFloat32 CFSwappedFloat32;
CFSwappedFloat32 littleFloat;當然,其中的 fread 可以用 memcpy、NSData 的 byte method 等等取代,只要把握住一個原則:「 CFSwappedFloat32 的內部是用 uint32_t 來儲存這個待轉換的 float」即可。
long buffer;
float hostFloat;
fread(&buffer, sizeof(long), 1, fp);
littleFloat.v = buffer;
hostFloat = CFConvertFloat32SwappedToHost(littleFloat);
標籤: Develope, iPhone Dev, Obj-C, Tip
NSNumber 與 NSInteger
在 Mac OSX 10.5 中新增加了 NSInteger 這個東西,但是這下就會跟 NSNumber 搞混,到底要用哪個?
基本上,NSInteger(以及類似的 NSUInteger)是為了解決在 32-bit/64-bit CPU 架構下,int 長度不同的問題,它的定義如下:
NSNumber 則是個不折不扣的 Objective-C 類別,因此這兩者的使用時機就很明顯了,當你要把 integer 放到 Obj-C 的集合,例如 NSArray/NSSet 時,請用 NSNumber,不然其他的時候用 NSInteger 就好了。
基本上,NSInteger(以及類似的 NSUInteger)是為了解決在 32-bit/64-bit CPU 架構下,int 長度不同的問題,它的定義如下:
#if __LP64__ || NS_BUILD_32_LIKE_64也就是說,NSInteger 只是用 typedef 包裝過的 int/long,它是個基本資料型別(data type)。
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
NSNumber 則是個不折不扣的 Objective-C 類別,因此這兩者的使用時機就很明顯了,當你要把 integer 放到 Obj-C 的集合,例如 NSArray/NSSet 時,請用 NSNumber,不然其他的時候用 NSInteger 就好了。
星期六, 五月 02, 2009
iPod Shuffle - Small talk
Apple 推出 iPod Shuffle 三代已經一段時間了,功能外觀不再贅述,雖然它的語音功能好像真的蠻好玩的,只是老是要聽人聲慢慢念,還是覺得有點麻煩。我比較感興趣的反倒是它的標語 "Small talk"。

看到 Small talk,實在沒辦法讓我不連想到那個程式語言 - Smalltalk。
Smalltalk 是世界上第二個物件導向程式語言,在 1970 年代就開發出來,後來也影響了眾多的語言,著名的包括 Java、Ruby 等,但是對 Mac 開發者來說,最重要的應該就是 Objective-C 了,而 Obj-C 也是唯一保留了 Smalltalk 那特殊的 [object method] 語法的語言。因此雖然我沒寫過 Smalltalk,但是聽到這個標語還是不禁會心一笑,這是我開始用 Apple 產品以來,第一次感受到 Apple 與工程師這麼接近的一次(或許這也只是 Apple 一次美麗的錯誤?)
不過台灣的網頁在第一次出現的時候,把標語定為 "輕小說",結果在 OIKOS 上被圍剿,說 iPod 跟小說根本沒關係,牛頭不對馬嘴。過了幾天就看到台灣把標語換成與香港一樣的 "輕身細語",老實說,這樣有比較好嗎?我反倒覺得輕小說三個字更有輕飄飄的感覺,而把 "輕" "小" "說" 三個字拆開來看,則更符合這次的功能特色,就翻譯上也比較貼近英文的標語 Small talk。"輕身細語" 光聽根本感受不到它的體積小,因為太容易與原來的成語 "輕聲細語" 直接聯想在一起。
只是,即使是 "輕小說",還是沒辦法傳達那個隱藏的聯想,Objective-C 的老前輩,Smalltalk。

看到 Small talk,實在沒辦法讓我不連想到那個程式語言 - Smalltalk。
Smalltalk 是世界上第二個物件導向程式語言,在 1970 年代就開發出來,後來也影響了眾多的語言,著名的包括 Java、Ruby 等,但是對 Mac 開發者來說,最重要的應該就是 Objective-C 了,而 Obj-C 也是唯一保留了 Smalltalk 那特殊的 [object method] 語法的語言。因此雖然我沒寫過 Smalltalk,但是聽到這個標語還是不禁會心一笑,這是我開始用 Apple 產品以來,第一次感受到 Apple 與工程師這麼接近的一次(或許這也只是 Apple 一次美麗的錯誤?)
不過台灣的網頁在第一次出現的時候,把標語定為 "輕小說",結果在 OIKOS 上被圍剿,說 iPod 跟小說根本沒關係,牛頭不對馬嘴。過了幾天就看到台灣把標語換成與香港一樣的 "輕身細語",老實說,這樣有比較好嗎?我反倒覺得輕小說三個字更有輕飄飄的感覺,而把 "輕" "小" "說" 三個字拆開來看,則更符合這次的功能特色,就翻譯上也比較貼近英文的標語 Small talk。"輕身細語" 光聽根本感受不到它的體積小,因為太容易與原來的成語 "輕聲細語" 直接聯想在一起。
只是,即使是 "輕小說",還是沒辦法傳達那個隱藏的聯想,Objective-C 的老前輩,Smalltalk。

