作業系統 & 程式語言 dada on April 18, 2008

一個長整數各自表述 (in 64-bit system)

Size of long integer may vary in 64-bit systems (一個長整數各自表述)

不知道是不是我太落伍了...

我一直以為 C/C++ 下面 short, long, long long 三種資料型態都固定是 2, 4, 8 個 bytes 大小。只有 int 這個資料型態會因為 16-bit/32-bit 系統的不同而變成 2 或 4 bytes 的大小,所以理所當然 int 在 64-bit 的電腦也應該會變成 8 bytes (64-bit) 的大小囉 ?!

在整理前一篇文章《Bypass the 2GB file size limit on 32-bit Linux》的時候,讓我驚覺在 64-bit 的系統下,long 的長度也是各自表述的!

首先,int 的大小即使到了 64-bit 的機器上,大部分的系統仍然使用 4 bytes 的大小而已,這主要是為了避免程式從 32-bit 系統轉換到 64-bit 系統需要修改太多地方

再來,請參考 Wikipedia: 64-bit data models 的說明

絕大多數的 UNIX 系統在 64-bit 下面採用 LP64 這種 data model,這時候 long 就不再是固定為 4 bytes 大小,而是變成 8 bytes 的大小了!

然而,Win64 卻不是使用 LP64,而是採用 LLP64 這個 data model,這時候 long 的大小仍然還是 4 bytes

Many 64-bit compilers today use the LP64 model (including Solaris, AIX, HP, Linux, Mac OS X, and IBM z/OS native compilers). Microsoft's VC++ compiler uses the LLP64 model.

兩種 data model 的最大差異點就是 long 這個資料型態的大小,LP64 是 64-bit,而 LLP64 則是 32-bit

LLP64 data model 基本上可以說跟 32-bit 的系統一樣,唯一差別只有位址(pointer)改成了 64-bit 而已。資料物件(class, structure) 等如果沒有包含 pointer 的成員的話,整個物件的大小是與 32-bit 系統一樣的!

而 LP64 則是除了位址(pointer)改成 64-bit 之外,long 的大小也變成了 64-bit 大小。所以在 UNIX 下面,要把 32-bit 程式 porting 到 64-bit 可能要比 Windows 多花費多一點功夫。

所以呢,我們觀察到兩個問題影響著程式的相容性

  1. 在 UNIX 下面,long 的大小在 32-bit 與 64-bit 的系統下是不一樣的
  2. 同樣是 64-bit 系統,UNIX 與 Windows 對於 long 的大小看法是不一致的

為了使程式在 32-bit 與 64-bit 之間以及 UNIX 與 Windows 之間的相容性提昇,改用固定長度的資料型態是寫程式的一個好習慣

在 UNIX 下面,我們可以改用 stdint.h 這個 header file 中對於資料型態的定義:

int8_t     8-bit signed interger
int16_t    16-bit signed interger
int32_t    32-bit signed interger
int64_t    64-bit signed interger
uint8_t    8-bit unsigned interger
uint16_t   16-bit unsigned interger
uint32_t   32-bit unsigned interger
uint64_t   64-bit unsigned interger

在 Windows 下面,則改用下面這些整數固定大小的資料型態

INT8       8-bit signed integer
INT16      16-bit signed integer
INT32      32-bit signed integer
INT64      64-bit signed integer
UINT8      8-bit unsigned integer
UINT16     16-bit unsigned integer
UINT32     32-bit unsigned integer
UINT64     64-bit unsigned integer

絕對不要再使用 int 和 long 了!

尤其是寫網路程式時,很可能 client 是 Windows 而 server 是 UNIX,然後又有 32-bit 及 64-bit 系統混在裡面,一不小心就發生不相容的問題了...

當然,在 64-bit 的系統下寫程式,要考慮的絕對不只上面這些基本的資料型態。除了 pointer 的大小變成 64-bit 外,許多系統內建函式會用到的 size_t 及 off_t 的大小也變成 64-bit 了.... 寫程式時若有用到這些資料型態,需特別注意,尤其是 casting 時,千萬不要用 32-bit 的整數去裝這些資料,免得造成不可預期的結果!

最後提供一個小程式讓你得知你的系統主要資料型態的大小

#include <stdio.h>
#include <sys/types.h>
int main()
{
        printf("sizeof(short)     = %d\n", sizeof(short));
        printf("sizeof(int)       = %d\n", sizeof(int));
        printf("sizeof(long)      = %d\n", sizeof(long));
        printf("sizeof(long long) = %d\n\n", sizeof(long long));
 
        printf("sizeof(size_t)    = %d\n", sizeof(size_t));
        printf("sizeof(off_t)     = %d\n", sizeof(off_t));
        printf("sizeof(void *)    = %d\n", sizeof(void *));
}

參考資料:

  1. Wikipedia: 64-bit data models
  2. 64-Bit Programming Models: Why LP64?
  3. Introduction to Win32/Win64
  4. Porting 32-bit Applications to the Itanium® Architecture
  5. Preparing Code for the IA-64 Architecture (PDF)

作業系統 dada on April 18, 2008

Bypass the 2GB file size limit on 32-bit Linux

Bypass the 2GB file size limit on 32-bit Linux (在 Linux 上面突破 2GB 的檔案大小限制)

在 32 位元的 Linux 上面寫超過 2GB 的檔案會發生錯誤,甚至導致程式終止執行

這是因為 Linux 的系統內部處理檔案時用的指標定義為 long,而 long 在 32 位元的系統上的大小為 32 位元,因此最大只能支援 2^31-1 = 2,147,483,647 bytes 等於是 2GB 扣掉 1 byte 的檔案大小

64 位元的系統 (例如 AMD64IA64) 則因為 long 定義成 64 位元,所以不會有問題..

#  if __WORDSIZE == 64
typedef long int int64_t;
# endif

不過在 FreeBSD 上面,即使是 32 位元的系統,也不會有 2GB 檔案大小的限制,這是因為 FreeBSD 內部處理檔案時,本來就是使用 64 位元的數字當作指標,所以不會有問題

因此在 32 位元的 Linux 上面,程式需要作一些額外處理才能正確寫超過 2GB 的檔案

我們先寫一個小程式來測試一下 (large.c)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
void sig_xfsz(int sig)
{
        printf("ERROR: SIGXFSZ (%d) signal received!\n", sig);
}
int main()
{
        int     i, fd;
        char    dummy[4096];
 
        signal( SIGXFSZ, sig_xfsz );
 
        unlink("large.log");
        fd = open("large.log", O_CREAT|O_WRONLY, 0644 );
 
        bzero( dummy, 4096 );
        /* 2GB = 4KB x 524288 */
        for( i = 0 ; i < 524287 ; i++ )
                write( fd, dummy, 4096 );
        write( fd, dummy, 4095 );
        printf("large.log: 2147483647 bytes\n");
 
        if( write( fd, dummy, 1 ) < 0 )
                printf("ERROR: %s [errno:%d]\n",strerror(errno),errno);
        else
                printf("large.log: 2147483648 bytes\n");
 
        close(fd);
        exit(0);
}

在 32 位元的 Linux 下面,以上程式編譯後若沒有特殊處理,執行結果如下:

# gcc -o large32 large.c
# ./large32
large.log: 2147483647 bytes
ERROR: SIGXFSZ (25) signal received!
ERROR: File too large [errno:27]

在寫第 2147483648 byte 的時候,程式會收到 signal SIGXFSZ,同時 write() 會回傳 -1 錯誤,errno 則為 27 (File too large)。更甚者,如果程式沒有像上面一樣去處理 SIGXFSZ 的話,內定的 signal handler 甚至會造成程式停止執行並產生 core dump

接下來,我們在編譯同一個程式的時候加入 -D_FILE_OFFSET_BITS=64 再試看看:

# gcc -D_FILE_OFFSET_BITS=64 -o large64 large.c
# ./large64
large.log: 2147483647 bytes
large.log: 2147483648 bytes

果然順利突破 2GB 的限制了!

而同樣的程式在 32 位元的 FreeBSD 下面,不論有沒有加這個定義,跑起來都是正確的

不過處理這些大檔案的時候,除了編譯程式時的參數不同外,有些函數的使用上也要作一些調整,例如 fseek() 與 ftell() 這兩個原本使用到 long integer 當作 offset 的函數:

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);

只要系統是 32 位元,即使是在 FreeBSD 下面,都需要改為使用 off_t 的版本:

int fseeko(FILE *stream, off_t offset, int whence);
off_t ftello(FILE *stream);

在 Linux 下面,如果 _FILE_OFFSET_BITS 定義為 64,則 off_t 這個型態會自動轉成 64 位元的大小(在 FreeBSD 上面,off_t 本來就是 64 位元的大小)

每種系統支援大於 2GB 的檔案讀寫所需要的編譯選項都會有一些差異,即使是同樣是 Linux 也會因為 32 位元或 64 位元而有不同。有一個簡單的方法可以判斷,就是利用 glibc 提供的 getconf 來取得編譯(compile)以及連結(linking)時所需的參數:

# getconf LFS_CFLAGS
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
# getconf LFS_LDFLAGS 
 
#

上面是在 32 位元的 Redhat Linux 上面跑出來的結果,代表的是在這個系統上,若要讓程式支援 2GB 的檔案讀寫,編譯(compile)時需要加上 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 這兩個參數,連結(linking)時則不用加任何參數

參考資料:

網路科技 dada on March 02, 2008

China blocked FeedBurner (problem for FeedSmith)

這次到大陸出差,讓我發現到一個嚴重的問題,就是 Great Firewall (GFW) 把著名的 feed service provider FeedBurner 給擋掉了,這已經是去年八月發生的事了。所以如果您自己以 WordPress 架設的 blog 使用了 FeedBurner FeedSmith 這個 WordPress plugin,就會有一些奇怪的問題發生...

首先是 blog 的 RSS/Atom 等都無法直接被訂閱了,因為 FeedSmith 自動把 RSS/Atom 導向到 FeedBurner 那邊了,所以大陸那邊的人就無法直接訂閱。

例如: 我的 blog 的 feed 是: http://blog.urdada.net/feed/ 就會被 FeedSmith 使用 HTTP Status Code 307 (Temporary Redirect) 重導到 http://feeds.feedburner.com/cdsheen,所以大陸人就看不到啦...

當然,從大陸透過 BloglinesGoogle Reader 可能還是可以間接訂閱就是了...

另外一個問題是,所有 RSS/Atom 內文章的原始連結都會被 FeedSmith 代換成 FeedBurner 的網址來追蹤點擊率,但是這些連結在大陸都沒有任何作用,無法導回原始網站了... 因此即使大陸人可以使用 Bloglines 或 Google Reader 來間接訂閱,但是當要回原網站查看原文時,也會因為 FeedBurner 被擋而無法正確連結!

暫時還想不到比較好的解決方法,有人建議額外使用一個沒被 GFW 擋掉的 feed service provider 來專門給大陸客使用,例如: FeedSky,這是大陸的公司,我想應該不會被擋。不過為了不讓阿共仔的陰謀輕易得逞,我暫時還是維持只使用 FeedBurner,但是另外提供一個 feed 讓苦難的大陸同胞訂閱(雖然這樣就無法追蹤那邊的訂閱狀況了..)

# cp wp-rss.php rss-china.php

如果您人在大陸,想要訂閱我的 blog,請改用下面這個未經 FeedSmith 處理過的 feed 吧:

http://blog.urdada.net/rss-china.php

真是無奈... 大陸對於言論審查的尺度一直跟不上經濟自由化的腳步,總有一天會出問題的

趣味軼事 dada on February 14, 2008

富邦momo購物網的 Touch Cruise 驚爆價!(標錯價?)

話說一個禮拜前貼的一篇文章才提到說我的手機 Siemens 3618 用了五年多了,一直都還是頭好壯壯的,沒想到今天慘事就發生了...



液晶畫面突然變得亂七八糟,雖然看起來還可以接聽來電,但根本看不出來是誰找我,也無法查詢電話簿,看來真的是該換一隻手機了...

不過這一篇的重點不在這邊...

我從 momo 富邦購物網訂購(疑似標錯價錢)的 HTC Touch Cruise PDA 手機今天又有最新消息了,下午有一位 momo 的客服人員打電話過來,說我訂購的手機缺貨,可能要一陣子才能到貨,問我要不要取消訂單。我當然是嚴詞拒絕囉,要求 momo 必須依照網站上的說明於五個工作天內到貨。而且既然客服人員這樣說明,就表示沒有標錯價錢的問題囉 !?

不過這隻手機雖然熱門,但也不可能達到這麼缺貨的地步,網路上甚至有人說被 momo 客服告知要兩個月才會到貨!其實就算標錯價錢,還是有辦法協商的,購物網站仍不見得要完全履行(可參考之前的聯邦銀行案例)如果富邦想用這招來騙買家取消訂單,未免也太低級了一點... 而且這樣可能適得其反,富邦是不是就等於承認沒有標錯價錢了呢?如果有人不接受取消訂單,那 momo 是不是兩個月內都不用想賣這支手機了呢? 沒貨源還放上網站去賣,momo 以後不想混了嗎?

從 momo 網站的訂單查詢已經可以看到目前我這筆訂單處於「物流作業」狀態:



另外,我使用信用卡分期繳費,也已經在信用卡網站上看到第一期的扣款了



關於 momo 富邦購物網這次出的包,可參考 Mobile01 上的 [相關討論],上面還有人說去年十二月底已經遇過相同的事了,那時主角是 HTC 的手機 TyTN II,富邦反悔推說沒貨,強制取消訂單,只送了一個保溫杯,沒想到現在又來一次,這個網站問題還真大...

[2008/02/21 update] 後來 momo 客服說 23 號才會出貨,目前東西還沒收到,慢慢等囉
[2008/02/23 update] 還是沒有收到貨,客服說 HTC 把貨扣住了,真爛的理由..
[2008/02/25 update] 出發到大陸上海出差,但東西還沒收到
[2008/03/01 update] 晚上回到台灣,大樓警衛說剛好今天到貨了,有圖有真相:

[總結]
2008/02/07 大年初一訂貨,二十三天後(2008/03/01) 收到貨品 (照規定應於五個工作日內到貨),與市價約有五千多元價差,從頭到尾富邦 momo 都沒說這是標錯價錢,看來真的是驚爆價吧 :roll:

趣味軼事 dada on February 07, 2008

鼠年給自己的第一個新年禮物 HTC Touch Cruise

鼠年第一篇,祝大家新年快樂,鼠年發大財!

昨天除夕夜,用免費簡訊送了幾十通拜年簡訊出去,元宵節前去註冊都還有送100通免費簡訊,想用的人去玩看看吧。註冊時要輸入電話號碼以及真實姓名,據說填錯姓名不會獲得免費點數,雖然我沒試過填假名字,但是有點好奇這家公司怎麼去跟電信公司驗證註冊者的真實姓名,不曉得有沒有違反「電腦處理個人資料保護法

我的手機 Siemens 3618 (沙漠風暴) 小橘已經用了五年多了,這支號稱防塵防震的運動型手機還真的蠻耐用的,摔了無數次,還曾經掉到馬桶裡面,到現在除了電池弱一點,其他功能都沒有任何問題,我想再用個一兩年應該不是問題。



不過,看到同事用 PDA 手機用的很高興,也興起我想買一支有 GPS 功能 PDA 手機來玩看看的念頭。今年一月底宏達電出了一支 Touch Cruise,3.5G+Wifi+Bluetooth+GPS+AF,看來外型及功能都符合我的需求,我想應該就是這支了,打算過年後就去買。這支手機在電腦家的訂價為 $24,990,據說一般通信行最低約可以拿到約 $22,500 的價格(不綁約)。

話說今天大年初一早上,無意中在 momo 富邦購物網 發現 HTC Touch Cruise「驚爆價」只賣 $16,688 元,不確定是促銷還是標錯價錢:



不過上面這項在我看到的時候已經買不到了,但有另一個可分12期的賣 $17,588 元,雖然較貴一點但是還是算便宜:



剛開始買的時候,填入信用卡卡號後,還是一樣跟我說商品數量不足,買不到。不過不死心的我過一個小時又試了一次,沒想到竟然成功了...



哈哈,就當作鼠年給自己的第一個新年禮物囉 :razz: 希望富邦不要反悔不出貨就好了


話說將近四年前我也遇過類似的案件,聯邦銀行的購物網站 UBMall 賣一台當時市價約19萬的Panasonic 37吋電漿電視,網路上標價僅為19,499元,我就刷卡買了1台,後來聯邦銀行發現錯誤(少標了一個零),跑來和解希望取消訂單,我接受了,不過也收到了幾樣贈品以及6,000元的和解金。當時有十幾個人堅持不願接受和解,分別告上法院要求履行契約,後來結果法院好像均判決聯邦銀行不用履行契約,詳細資訊可參考這邊

不過每個案件的情況不同,聯邦銀行這個案件當時判決理由之一是「原告既有意購買此類電視,依社會通念及客觀情況判斷,理應曾於市場訪價並知悉該類商品之市場一般價格,故被告聯邦銀行絕無可能以低於二萬元價格於網路上販售系爭電漿電視,此應為原告所明知或可得而知,揆諸前揭說明,原告應無可資保護之信賴利益」。但這次價差只有幾千元,看起來很像是促銷,尤其第一個網頁商品說明還寫著「驚爆價」,與聯邦銀行案件的情況不同,就看富邦怎麼處理囉。

網路科技 dada on January 27, 2008

Using Flickr API with phpFlickr

本來我的私人照片都是放到自己架的網站上面的,一直在考慮要不要改放到 Flickr 上面...
最重要的一個考量因素就是與我自己的網站程式容不容易整合

雖然利用 Yahoo 送的免費三個月 Flickr Pro 帳號已經把幾年來、數十本相簿統統丟上去備份了,但一直沒有時間去實驗一下 Flickr API 到底合不合我用

拖了一陣子,結果免費三個月的 Flickr Pro 帳號在今天終於到期了,而且 Flickr Gift 買一年送三個月(備註)的活動也即將在一月底結束了,因此今天還是花了點時間評估了一下 Flickr API,結果還蠻滿意的,這幾天應該就會刷卡買了吧

我用的是 phpFlickr 這套程式庫,使用起來還蠻容易的,所有 Flickr 提供的 API 都有支援,而我要的其實只是列出所有相簿(sets)列表而已。唯一有點可惜的是,Flickr API 還沒有支援珍藏集 (collections),目前僅能到相簿(sets)這個層次而已,但這不是 phpFlickr 的問題

使用 phpFlickr 前,要先去生一個 Flickr API Key 出來,然後就可以用這個 Key 來連接 Flickr API 了

要用 phpFlickr 程式去使用 Flickr API 需要認證,有兩種模式:

1. 每次都去認證使用者的帳號,phpFlickr 會把你導到 Flickr 的認證頁面再導回來

先把 API Key 的 callback 指到 phpFlickr/auth.php,然後程式呼叫 auth() 後再作想作的事

<?
 
include('phpFlickr/phpFlickr.php');
 
$f = new phpFlickr("[API Key]","[Auth Secret]");    //  填入 API Key 及 Secret
$f->auth();
 
// 作自己的事
 
print_r( $f->photosets_getList() );
 
?>

呼叫 auth() 會把使用者瀏覽器導到 Flickr 的認證網頁,而程式本身會結束執行:

Flickr API authentication

認證網頁可以讓使用者授權讓你的服務去存取使用者的 Flickr 帳號,不一定是上面產生 API key 的那個帳號。當認證完畢後,Flickr 會再把使用者瀏覽器導回之前設定的 callback (phpFlickr/auth.php),然後再導回你原本呼叫 auth() 的那隻程式

再導回這個程式時,會有相關認證資訊 (authentication token) 放在 session data 中,這時呼叫 auth() 就不再會把使用者導到其他網頁了,而是會回傳認證的權限狀況,接下來程式就可以作自己的事了

使用者隨時可以經由 這個網頁 來取消對你的程式的授權:

Flickr extended authentication

2. 每次都是用固定的帳號去認證,不會導到 Flickr 認證頁面

要使用這種作法,請參考 http://www.phpflickr.com/tools/auth/ 去產生一個永久的 token,接下來程式就可以直接使用了:

<?
 
include('phpFlickr/phpFlickr.php');
 
$f = new phpFlickr("[API Key]","[Auth Secret]");    //  填入 API Key 及 Secret
$f->setToken("[Token]");                 // 填入上面產生的 token
 
// 作自己的事
 
print_r( $f->photosets_getList() );
 
?>

-----
複雜的認證過後,你就可以開始玩 Flickr API 了... phpFlickr 支援所有的 Flickr API,詳細列表請直接參照 API 說明文件

例如要得到所有相簿列表必須要呼叫 flickr.photosets.getList 這個 API,在 phpFlickr 裡面就直接呼叫 $f->photosets_getList() 這個函數即可。也就是把 API 名字中的 "flickr." 拿掉,並把 . 換成 _ 就是 phpFlickr 支援的函數名稱了!

更詳細的說明請直接參閱 phpFlickr 的網站: http://phpflickr.com/

--
[備註]
Flickr 實際上並沒有買一年送三個月的活動,但是現在可以買一年 Flickr Pro 帳號送別人,自己也會得到免費三個月的 Flickr Pro 帳號,而這個活動並沒有限制你不能送給自己,所以等於是買一年送三個月。

想參加這個活動的人千萬不要直接去買一年喔,一定要參加 Flickr Gift 活動 "送禮物給自己" 才有多送三個月。

這個活動於太平洋時間 2008 年 1 月 31 日晚上 11時59分 (GMT-8) 結束,也就是台北時間 2008 年 2 月 1 日下午 3時59分 (GMT+8),想買 Flickr Pro 的人請把握時間囉...

硬體 dada on January 19, 2008

SDHC support on Thinkpad X60

Thinkpad X60 原本並沒有 支援 SDHC 卡,把 SDHC 卡插入 X60 左方的 SD 插槽會讀不到

本來以為 X60 對於 SDHC 的支援是無望了,沒想到現在竟然可以了,而且還只要更新作業系統即可... 詳情請參考微軟發佈的 Hotfix 923293
(標題: 在 Windows XP Hotfix 923293 為高容量的 SD 記憶卡加入支援)

不過這個 Hotfix 微軟還沒有釋放出來讓大家下載安裝,未來新的 Service Pack 3 才會放進去,有需要的人必須自己去線上申請,選擇好你的作業系統版本及語言即可

申請之後,微軟就會把 Hotfix 的下載連結寄給你(還有個密碼來解壓縮),正體中文 WinXP 的 Hotfix 檔名為: WindowsXP-KB923293-v4-x86-CHT.exe,怕麻煩的話網路上搜尋一下應該找得到.. 或者寄信給我吧...

安裝此 Hotfix、重新開機後,果然可以讀到 SDHC 卡了! 同事的華碩 ASUS W5 (WinXP) 原本也是不能讀 SDHC 卡,服用這帖 Hotfix 後也 OK 了

Yeah! 這樣方便多了

2008/04/30 update: Windows XP SP3 已經包含這個修正了,不需要再特別安裝 hotfix 了...

資訊安全 dada on January 07, 2008

SSH Keyboard-Interactive Authentication

有些 SSH clients (例如: SecureCRT)允許使用者「儲存」密碼,這對系統安全是個大忌,一旦 client 遭受入侵,server 也會暴露在危險之中。

建議直接在伺服器端取消 SSH 的 password authentication 功能,改用 keyboard interactive 的方式認證,通常這樣的話,client 就無法儲存密碼了:

1. OpenSSH - /etc/ssh/sshd_config

PasswordAuthentication no
ChallengeResponseAuthentication yes

2. SSH2 (Tectia) - /etc/ssh2/sshd2_config

AllowedAuthentications          publickey,keyboard-interactive
AuthKbdInt.Optional             pam,password
AuthKbdInt.Required             password

修改好上述 sshd 的設定檔後,送個 HUP 給 sshd 即可(注意不要不小心把目前用的 session 也砍了,不然改錯的話只好到 console 前面去救了)

# ps ax | grep sbin/sshd | grep Ss
 9767 ?        Ss     0:00 /usr/sbin/sshd
# kill -HUP 9767

然後就可以請大家改用 keyboard-interactive authentication 了:

SSH keyboard-interactive authentication

Next Page »


follow cdsheen at http://twitter.com