2012-02-13 51 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个字节。

结构分配大小也会根据结构内不同数据类型声明的位置而变化。