字節對齊導致的iOS EXC_ARM_DA_ALIGN崩潰


 

本文原鏈接: http://www.cnblogs.com/zouzf/p/4455167.html 

 

先看一下這個鏈接:http://www.cnblogs.com/ren54/archive/2013/01/11/2856207.html

我遇到情況和這位朋友很類似:用二進制方式從文件讀取內容到內存,假設內容只有7個字節,前面三個字節是三個字符,后四個字節的內容是一個int數據,在把后四個字節轉成int數據時如(pFileContent是char*指針,已指向第四個字節):int intValue = *(pFileContent); 就會崩潰報EXC_ARM_DA_ALIGN錯誤。

 

查了一下資料:http://www.justinyan.me/post/1609 、http://www.shaoqun.com/a/54537.aspx 、http://blog.csdn.net/slay_cn/article/details/6221637 ,是因為字節對齊問題引起的,大概描述如下(摘自前面三篇資料):

內存地址空間以byte划分,所以理論上訪問內存地址可以從任意byte開始,但是事實上我們不是直接訪問硬件地址,而是通過操作系統的虛擬內存地址來訪問,虛擬內存地址是以字為單位的。一個32位機器的字長就是32位,所以32位機器一次訪問內存大小就是4個byte。再者為了性能考慮,數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。

這個問題常見於對字節流進行處理解析,比如從網絡收到一個數據包,讀入本地緩存后進行處理,頭兩個字節是一個short標志,接下來四個字節是一個int參數,所以將指向這個位置的指針直接cast成int*來讀取數據——於是問題就出現了,當讀int*時,ARM要求字節對齊,而此時不對齊。則有可能出現EXC_ARM_DA_ALIGN異常而崩潰。

 

大概就是說,在進行強制數據類型轉換的時候,(release版本)會要求內存字節對齊。編譯release版本,編譯器會對代碼進行優化,在處理數據時要求數據結構在自然邊界上對齊以提高CPU效率。

解決方法了http://www.shaoqun.com/a/54537.aspx

方案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 { char[5] name; int age; };就出問題了,windows下寫進文件需要16個字節,而ARM設備下讀取文件反序列化需要12個字節~~

 

上面說到:windows下默認是8字節對齊的,mac、iOS、Android(如果有誤請指正)默認是4字節對齊的 ,這個說法是不嚴謹的,應該更多的是跟編譯器有關吧,而編譯器會根據系統和CPU特性來決定的吧,這塊了解得不多,有了解的朋友可以留下鏈接和看法,謝了。

 

另外還有個疑惑,那個EXC_ARM_DA_ALIGN 崩潰會出現在Xcode5.1.1 出的release版本,而Xcode5.0.1 出的release版本卻沒事,一個小版本的有必要差異那么大么。。。。

 

本文原鏈接: http://www.cnblogs.com/zouzf/p/4455167.html 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM