Wednesday, March 21, 2007

misalgnment

記錄一下最近遇到的問題。 在 WinCE 寫一段讀取 BMP 的程式時,發現在讀取 BMP 檔頭時出現下面的 Exception :

0x80000002: Datatype misalignment.

同樣的程式在 x86 上不會有這個的問題(但會對效率有影響)。這個 Exception 在這篇有更多的說明,所謂的記憶體對齊的問題,似乎除了 x86 以外的 CPU 都有這樣的限制,就是在存取記憶體時會依要存取的大小而必需要對齊適當的起點,例如要存取 DWORD 的變數,一定要依 4 倍數的記憶體起點對齊,而 WORD 要對齊 2 的變數,而如果是 BYTE 的話就不會有這樣的問題。正常情況下 Compiler 不會弄出違反這個規則的 code ,但如果是自己對 pointer 強制轉型就要小心這樣的問題,像下面的程式就會出問題:

int a ;
char *p = (char*)&a ;
int *pp = (int*)(p+1) ;
int b = *pp ;

回到 BMP 檔頭的問題,BMP 檔案是像下面的格式: bmp header 基本上讀取的程式是類似這樣:

PBITMAPFILEHEADER pbmfh = (PBITMAPFILEHEADER)(bmpfile.GetFileContent());
PBITMAPINFO pih = (PBITMAPINFO)(pbmfh+1);
int b = (pih->bmiHeader).biSize ;

結果問題就出在 BITMAPFILEHEADER 的大小是 14 ,非 4 的倍數,就會造成讀取其下 BITMAPINFO 時造成不對齊的情況。這個問題治本的解法是在定 struct 就要小心,不要弄出這種容易造成問題的結構。而治標的方法有使用 __unaligned 來避免這個問題,不過我覺得直接把他 co 一份出來用比較方便。

BITMAPINFO bmi ;
memcpy(&bmi, (BITMAPINFO*)(pbmfh + 1), sizeof(bmi));

至於 co 的時候為什麼不會造成 misalignment 呢?因為 memcpy 時是 byte-wise copy,而 byte 不會有 misalignment 的問題了。

0 comments:

Post a Comment