2012-02-13 17 views
5

En una aplicación iOS, tengo una estructura que tiene este aspectoEXC_BAD_ACCESS relacionado con la alineación de estructuras?

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

En mi código, asignar una matriz de estos con calloc:

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

Ahora bien, esto funciona a la perfección en el simulador , pero en el dispositivo, si intento acceder al buff[width * height - 1] (es decir, el último elemento en buff), obtengo un EXC_BAD_ACCESS.

Esto no tiene sentido para mí, así que después de unas horas de depuración, me preguntó si había algún tipo de problema de alineación, por lo que en un capricho Traté:

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

haciendo que el tamaño de Pixel una potencia de dos.

Esto corrige el EXC_BAD_ACCESS, pero es terriblemente extraño. ¿Alguien tiene alguna idea de lo que está pasando aquí? ¿Estoy enmascarando el problema subyacente rellenando la estructura o alineamiento de la lata que realmente causa un mal acceso (pensé que la alineación solo tenía un efecto en el rendimiento, no en la corrección).

+0

Hola Bill dos cosas. Como SO no me permite editar un personaje, tienes un error tipográfico en calloc. Le falta un paréntesis al final. En cuanto a su problema principal, este tipo de cosas generalmente ocurre si reasigna el buff en otro lugar, o en una de las veces que accede, accidentalmente se sale del índice. ¿Haces algo más para * buff * antes de intentar acceder al último elemento? – Lefteris

+0

verifique nuevamente sus valores de ancho y alto ... !!! –

+0

Este es el código que funcionó durante meses; la única diferencia es que cambié el tipo de los miembros de la estructura de CGFloat a bytes firmados. Entonces, el ancho y la altura no son el problema, es algo que tiene que ver con el diseño de la estructura. – Bill

Respuesta

3

EXC_BAD_ACCESS is related to alignment. A diferencia de x86, ARM requiere acceso a memoria alineado con cierto límite.

Para controlar la alineación, use #pragma push, #pragma pack(n) y #pragma pop alrededor.

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

+2

No preguntó cómo controlar la alineación. Preguntó si alguien sabe por qué sin el relleno causa EXC_BAD_ACCESS en primer lugar – Lefteris

+0

La mala alineación es la causa de EXC_BAD_ACCESS, en ARM. No tome por sentado los comportamientos en x86. – ZhangChn

+0

es extraño, ya que está accediendo a bytes, que no deberían sufrir excepciones de alineación. ¿Tal vez la estructura pasa a una parte de la aplicación que no fue recompilada después del cambio de estructura? –

2

Es el problema de la alineación. El tamaño mínimo de alineación de la estructura es de 4 bytes y variará de acuerdo con la declaración de tipo de datos en la estructura (por ejemplo, doble). Aquí, si imprime el tamaño de un bloque, imprimirá 3 en lugar de 4. Pero si imprime el tamaño de su estructura, imprimirá 4 debido al tamaño mínimo de alineación.

Suponga que si también tiene un elemento 'int' en la estructura, tanto el tamaño del bloque único como la estructura serán 8. Esto se debe a que el compilador forzó el byte de relleno entre los chars y el int. Por ejemplo

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

La primera instrucción printf imprimirá 4 y la segunda imprimirá 3. Debido a que el tamaño de la estructura de alineación por defecto es de 4 bytes y la asignación actual es de 3 bytes. Ahora solo agregue un tipo int en la misma estructura.

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

Aquí ambas sentencias printf imprimirá 8. Debido a que el compilador ve obligado a asignar un byte entre carbón y la int sólo para mantener la alineación en múltiplos de cuatro. A continuación, la estructura se verá como se indican a continuación,

typedef struct { 

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

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

int i; 
}MyType; 

lo que hay que añadir un byte de relleno en su estructura para mantener la alineación debido a la asignación real es de 3 bytes.

El tamaño de asignación de estructura también variará según la posición de las diferentes declaraciones de tipos de datos dentro de la estructura.

Cuestiones relacionadas