我遇到情況和這位朋友很類似:用二進位制方式從檔案讀取內容到記憶體,假設內容只有7個位元組,前面三個位元組是三個字元,後四個位元組的內容是乙個int資料,在把後四個位元組轉成int資料時如(pfilecontent是char*指標,已指向第四個位元組):intintvalue =
*(pfilecontent
); 就會崩潰報exc_arm_da_align錯誤。
查了一下資料: 、 、 ,是因為位元組對齊問題引起的,大概描述如下(摘自前面三篇資料):
記憶體位址空間以byte劃分,所以理論上訪問記憶體位址可以從任意byte開始,但是事實上我們不是直接訪問硬體位址,而是通過作業系統的虛擬記憶體位址來訪問,虛擬記憶體位址是以字為單位的。乙個32位機器的字長就是32位,所以32位機器一次訪問記憶體大小就是4個byte。再者為了效能考慮,資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。這個問題常見於對位元組流進行處理解析,比如從網路收到乙個資料報,讀入本地快取後進行處理,頭兩個位元組是乙個short標誌,接下來四個位元組是乙個int引數,所以將指向這個位置的指標直接cast成int*來讀取資料——於是問題就出現了,當讀int*時,arm要求位元組對齊,而此時不對齊。則有可能出現exc_arm_da_align異常而崩潰。
大概就是說,在進行強制資料型別轉換的時候,(release版本)會要求記憶體位元組對齊。編譯release版本,編譯器會對**進行優化,在處理資料時要求資料結構在自然邊界上對齊以提高cpu效率。
解決方法了:
方案1、在指標定義時加上編譯器指令packed,則編譯器在遇到此關鍵字時就不再要求位元組對齊,而是自行進行正確的處理。
方案2、使用memcpy逐字節拷貝來繞過直接的int*指標讀取。給memcpy傳入引數時,先將引數轉成void*型別,因為release的memcpy被優化掉了,在優化的版本中,將指標轉成long型,4個4個位元組的進行複製,於是又出現了位元組對齊的問題。
我採用了方案2,給memcpy傳引數時轉成 void* 。
後記當讀取檔案獲取資料時經常會採用反序列化的方式來提高效率,如上篇文章提到的骨骼動畫的優化,這個時候要特別注意位元組對齊的問題,特別是現在做手遊基本都會涉及到多平台,在定義一些struct時最好顯示呼叫
#pragma pack(n)來指定位元組對齊。windows下編譯器預設是8位元組對齊的,mac、ios、android(如果有誤請指正)預設是4位元組對齊的,而經常發生的時,在windows下對檔案資源進行序列化,然後在ios和android上執行的時候讀取檔案進行反序列化,如果有個結構體如 struct mytest ;就出問題了,windows下寫進檔案需要16個位元組,而arm裝置下讀取檔案反序列化需要12個位元組~~
上面說到:windows下預設是8位元組對齊的,mac、ios、android(如果有誤請指正)預設是4位元組對齊的 ,這個說法是不嚴謹的,應該更多的是跟編譯器有關吧,而編譯器會根據系統和cpu特性來決定的吧,這塊了解得不多,有了解的朋友可以留下鏈結和看法,謝了。
另外還有個疑惑,那個exc_arm_da_align 崩潰會出現在xcode5.1.1 出的release版本,而xcode5.0.1 出的release版本卻沒事,乙個小版本的有必要差異那麼大麼。。。。
由於記憶體位元組對齊導致的硬體錯誤
最近在除錯stm32程式的時候,經常進到hardfault handler這個中斷裡。產生這個中斷的原因一般和記憶體有關係,像是陣列越界 堆疊溢位之類的。檢查了好幾天終於發現了問題的所在,產生問題的原因是程式在執行函式指標所指向的時候,由於指標指向的位址不對而引發hardfault handler中...
位元組順序 位元組對齊
一.位元組順序的產生 在計算機中,資料是以位元組為單位存放的,而c語言中只有char才是乙個位元組,其他如int,float都是大於乙個位元組,所以就存在將資料按怎樣的順序存放的問題。一般有大端序和小端序兩種方式,特殊的還有混合序,也就是兩種存放方式同時存在於乙個計算機系統中。上面講的都是主機位元組...
位元組順序 位元組對齊
一.位元組順序的產生 在計算機中,資料是以位元組為單位存放的,而c語言中只有char才是乙個位元組,其他如int,float都是大於乙個位元組,所以就存在將資料按怎樣的順序存放的問題。一般有大端序和小端序兩種方式,特殊的還有混合序,也就是兩種存放方式同時存在於乙個計算機系統中。上面講的都是主機位元組...