2012-02-13 10 views
5

Trong một ứng dụng iOS, tôi có một cấu trúc trông như thế nàyEXC_BAD_ACCESS liên quan đến sắp xếp cấu trúc?

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

Trong mã của tôi, tôi bố trí một mảng của những việc này với calloc:

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

Bây giờ, điều này hoạt động hoàn hảo trong mô phỏng , nhưng trên thiết bị, nếu tôi cố gắng truy cập buff[width * height - 1] (tức là phần tử cuối cùng trong buff), tôi nhận được EXC_BAD_ACCESS.

này không có ý nghĩa đối với tôi, vì vậy sau một vài giờ gỡ lỗi, tôi tự hỏi nếu nó là một số loại vấn đề liên kết, vì vậy trên một whim tôi đã cố gắng:

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

làm cho kích thước của Pixel một sức mạnh của hai.

Điều này sửa lỗi EXC_BAD_ACCESS, nhưng điều đó thật kỳ lạ. Có ai có bất kỳ cái nhìn sâu sắc vào những gì đang xảy ra ở đây? Tôi chỉ cần che giấu các vấn đề cơ bản bằng cách đệm cấu trúc hoặc có thể liên kết thực sự gây ra một truy cập xấu (tôi nghĩ sự liên kết chỉ có ảnh hưởng đến hiệu suất, không đúng).

+0

Xin chào Bill hai điều. Vì SO không cho phép tôi chỉnh sửa một ký tự, bạn có một lỗi đánh máy trong calloc. Bạn đang thiếu một dấu ngoặc đơn ở cuối. Đối với vấn đề chính của bạn, loại sự việc này thường xảy ra nếu bạn Hoặc thực hiện buff ở một nơi khác, hoặc trong một lần bạn truy cập nó, bạn tình cờ vô tình tắt chỉ mục. Bạn có làm gì khác để * buff * trước khi cố gắng truy cập phần tử cuối cùng không? – Lefteris

+0

kiểm tra giá trị chiều rộng và chiều cao của bạn một lần nữa ... !!! –

+0

Đây là mã đã hoạt động trong nhiều tháng - khác biệt duy nhất là tôi đã thay đổi loại thành viên cấu trúc từ CGFloat thành các byte đã ký. Vì vậy, chiều rộng và chiều cao không phải là vấn đề - đó là một cái gì đó để làm với bố trí của cấu trúc. – Bill

Trả lời

3

EXC_BAD_ACCESS is related to alignment. Không giống như x86, ARM yêu cầu quyền truy cập bộ nhớ được liên kết với ranh giới nhất định.

Để kiểm soát căn chỉnh, hãy sử dụng #pragma push, #pragma pack(n)#pragma pop xung quanh.

Xem http://tedlogan.com/techblog2.html

+2

Anh ta không hỏi cách kiểm soát sự liên kết. Ông hỏi nếu có ai biết tại sao không có đệm nó gây ra EXC_BAD_ACCESS ở nơi đầu tiên – Lefteris

+0

Mis-alignment là nguyên nhân của EXC_BAD_ACCESS, trên ARM. Không chấp nhận các hành vi trên x86. – ZhangChn

+0

nó là lạ, kể từ khi ông đang truy cập byte, mà không nên bị ngoại lệ liên kết. Có lẽ cấu trúc được chuyển đến một phần của ứng dụng không được biên dịch lại sau khi thay đổi cấu trúc? –

2

Đây là vấn đề về căn chỉnh. Kích thước liên kết cấu trúc tối thiểu là 4 byte và nó sẽ thay đổi theo khai báo kiểu dữ liệu trong cấu trúc (ví dụ: double). Nếu bạn in kích thước của khối đơn, nó sẽ in 3 thay vì 4. Nhưng nếu bạn in kích thước của cấu trúc của bạn, nó sẽ in 4 vì kích thước căn chỉnh tối thiểu.

Giả sử bạn cũng có phần tử 'int' trong cấu trúc, thì cả kích thước của khối đơn và cấu trúc sẽ là 8. Điều này là do trình biên dịch buộc phân bổ byte đệm giữa các ký tự và int. Ví dụ

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])); 

Tuyên bố printf đầu tiên sẽ in 4 và thứ hai sẽ in 3. Bởi vì cấu trúc mặc định kích thước phù hợp là 4 byte và phân bổ thực tế là 3 byte. Bây giờ chỉ cần thêm một loại int vào cùng một cấu trúc.

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])); 

đây cả hai câu lệnh printf sẽ in 8. Bởi vì trình biên dịch buộc phải phân bổ một byte ở giữa char và int để chỉ giữ sự liên kết trong đến bội số của bốn. Sau đó, cấu trúc sẽ trông giống như được đưa ra bên dưới,

typedef struct { 

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

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

int i; 
}MyType; 

Vì vậy, bạn phải thêm một byte đệm vào cấu trúc của mình để giữ căn chỉnh vì phân bổ thực tế là 3 byte.

Kích thước phân bổ cấu trúc cũng sẽ thay đổi theo vị trí của các khai báo datatype khác nhau bên trong cấu trúc.