2012-02-13 62 views
5

在iOS應用程序,我有一個結構,看起來像這樣與結構對齊相關的EXC_BAD_ACCESS?

typedef struct _Pixel { 
    signed char r; 
    signed char g; 
    signed char b; 
} Pixel; 

在我的代碼,我分配的這些陣列用calloc:

Pixel* buff = calloc(width * height, sizeof(Pixel)); 

現在,這個完美的作品在模擬器,但在設備上,如果我嘗試訪問buff[width * height - 1](即buff中的最後一個元素),我會得到一個EXC_BAD_ACCESS

這沒有任何意義,我,所以調試的幾個小時後,我懷疑這是某種對齊問題,所以一時興起我想:

typedef struct _Pixel { 
    signed char r; 
    signed char g; 
    signed char b; 
    signed char padding; 
} Pixel; 

製作的大小像素是兩個冪。

這修復了EXC_BAD_ACCESS,但它非常奇怪。有沒有人對這裏發生的事情有任何瞭解?我只是通過填充結構或可以對齊真正導致訪問不良(我認爲對齊只對性能有影響,而不是正確性)來掩蓋底層問題。

+0

嘿比爾兩件事。由於SO不允許我編輯一個字符,所以在calloc中出現錯字。最後你錯過了一個括號。 至於你的主要問題,這種事情通常會發生,如果你 要麼buff在其他地方,或在你訪問它的時間之一,你偶然脫離索引。 在嘗試訪問最後一個元素之前,您是否對* buff *進行了其他操作? – Lefteris 2012-02-13 03:46:53

+0

再次檢查您的寬度和高度的值... !!! – 2012-02-13 04:04:39

+0

這是已經工作了幾個月的代碼 - 唯一的區別是我將CGFloat的結構成員的類型更改爲帶符號的字節。所以寬度和高度不是問題 - 這與結構的佈局有關。 – Bill 2012-02-13 04:08:17

回答

3

EXC_BAD_ACCESS is related to alignment.與x86不同,ARM要求內存訪問對齊某個邊界。

要控制比對,請使用#pragma push,#pragma pack(n)#pragma pop左右。

http://tedlogan.com/techblog2.html

+2

他沒有問如何控制對齊。他詢問是否有人知道爲什麼沒有填充,首先會導致EXC_BAD_ACCESS – Lefteris 2012-02-13 04:05:11

+0

錯誤對齊是ARM上EXC_BAD_ACCESS的原因。不要將x86上的行爲視爲理所當然。 – ZhangChn 2012-02-13 04:15:11

+0

這很奇怪,因爲他正在訪問字節,不應該遭受對齊異常。也許結構被傳遞給應用程序的一部分,該應用程序在結構更改後未重新編譯? – 2012-02-14 15:53:49

2

這是對齊的問題。最小結構對齊大小爲4個字節,並且會根據結構中的數據類型聲明(例如,double)而有所不同。如果您打印單個塊的大小,它將打印3而不是4.但是,如果打印大小你的結構,它會打印4,因爲最小的對齊尺寸。

假設你在結構中還有一個'int'元素,那麼單個塊和結構的大小都將是8.這是因爲編譯器強制在字符和int之間分配填充字節。例如

typedef struct { 

signed char r; 
signed char g; 
signed char b; 
}MyType; 

MyType *type = (MyType *)calloc(20, sizeof(MyType)); 
printf("size: %ld", sizeof(MyType)); 
printf("size: %ld", sizeof(type[0])); 

第一printf語句將打印4和第二將打印3.由於缺省結構對準大小爲4個字節和實際分配是3個字節。現在只需將一個int類型添加到相同的結構中。

typedef struct { 

signed char r; 
signed char g; 
signed char b; 

int i;   // New int element added here 
}MyType; 

MyType *type = (MyType *)calloc(20, sizeof(MyType)); 
printf("size: %ld", sizeof(MyType)); 
printf("size: %ld", sizeof(type[0])); 

這裏既有printf語句會打印8.因爲編譯器被迫在焦炭和INT之間分配一個字節只保留排列在以四的倍數。然後結構將類似於下面給出,

typedef struct { 

signed char r; 
signed char g; 
signed char b; 

char padding; // Padding byte allocated to keep alignment. 

int i; 
}MyType; 

所以,你必須在你的結構中添加填充字節,以保持,因爲實際分配的定位是3個字節。

結構分配大小也會根據結構內不同數據類型聲明的位置而變化。