今天在Iphone4调试的时候,遇到一个EXC_ARM_DA_ALIGN。用Iphone 3G(IOS3.1.2)调试之则不出现。因为出问题的代码乃一个库文件里面的,函数大致如下:
void f(const char * pBuffer, uint64_t * pDesLLong)
{
(*(uint64_t *)pDesLLong) = (*(uint64_t *)pBuffer);
...
}
查看crash log文件,发现是由于产生了一个EXC_ARM_DA_ALIGN 的 Exception。google之,找到一位老外兄弟言:IOS3.2以及之后的版本,开发者需要考虑内存对齐的问题。http://byteclub.com/blog/44-development/85-memory-alignment-errors-on-iphone-os-3-2
那么,它是几字节对齐呢?根据上面这位牛哥提供的资源,查到了这样一篇比较系统的文档,知道它是4字节对齐得(word)(https://brewx.qualcomm.com/bws/content/gi/common/appseng/en/knowledgebase/docs/kb95.html)
那么问题就很明显了:如果上面那两个指针pBuffer和pDestLong所指的地址不是4的倍数,就会触发一个对齐的异常EXC_ARM_DA_ALIGN。那么这个问题怎么解决呢?前面的文档中言,使用memcpy来代替type casting来做赋值。于是我将代码改为:
memcpy((char*)pDestLong, (char*)pBuffer, sizeof(uing64_t));
在Debug版本下运行之,果然有效。可是当我编出一个Release版本的时候,问题又出现了。为何?
第一印象一定是memcpy是否被优化掉了。于是google “memcpy optimize”,发现以下这个优化代码:
void * memcpy(void * dst, void const * src, size_t len)
{
long * plDst = (long *) dst;
long const * plSrc = (long const *) src;
if (!(src & 0xFFFFFFFC) && !(dst & 0xFFFFFFFC))
{
while (len >= 4)
{
*plDst++ = *plSrc++;
len -= 4;
}
}
char * pcDst = (char *) plDst;
char const * pcDst = (char const *) plSrc;
while (len--)
{
*pcDst++ = *pcSrc++;
}
return (dst);
}
第一句话这个赋值,如果传入的指针不是一个四字节对齐的指针,即所指地址不是4的倍数,那么就会引发一个EXC_ARM_DA_ALIGN。如果真是这样的话,解决方案就必须自己写一个老版本的memcpy函数了:
void * memcpy(void * dst, void const * src, size_t len)
{
char * pDst = (char *) dst;
char const * pSrc = (char const *) src;
while (len--)
{
*pDst++ = *pSrc++;
}
return (dst);
}
使用之,问题解决。