如何解决进行对齐违规转换后,指针算术是否仍然定义正确?
我知道,具有对齐冲突的指针强制转换的结果一旦被取消引用就会调用未定义的行为。
但是仅用于地址计算(不进行解引用)的指针转换呢?
void *addr_calc(single_byte_aligned_struct_t *ptr,uint32_t dword_offset)
{
uint32_t *dw_ptr = (uint32_t *)ptr;
return dw_ptr + dword_offset;
}
我们假设ptr
的值为 X 。是否保证addr_calc()
将返回X + sizeof(uint32_t) * dword_offset
?
我的假设是这样,但是最近我在C11标准的 J.2未定义行为
部分中看到了以下内容-两种指针类型之间的转换产生的结果未正确对齐(6.3.2.3)。
如果我正确理解的话,强制转换本身会调用未定义的行为,而不仅是取消引用,这意味着即使指针算术在这种情况下也可能行为异常。我说的对吗?
解决方法
如果ptr
与uint32_t
的对齐方式不正确,则实际上可能导致未定义的行为。某些系统可能允许这样做,但其他系统可能会触发故障。
安全的转换将是转换为char *
,然后对该指针进行算术运算。
return (char *)ptr + dword_offset * sizeof(uint32_t);
,
是的,您理解正确。例如,在某些使用单词寻址但仍具有小于单词的char
类型的计算机上,int *
指针的大小可能更小 没有说明将未对齐的char *
强制转换为int *
会做什么-但是陷阱将是最佳情况方案。
如果需要按字节指针算术,请使用指向字符类型的指针。 所有其他对象指针类型永远只能用于引用指向类型的真实对象或数组
,在处理以下情况时,可能会出现一个明显的例子:施放未对准的指针可能会导致故障:
void test(void *dest,void *src)
{
uint32_t *d = dest;
uint32_t *s = src;
memcpy(d,s,4);
}
在不支持未对齐单词访问的平台上使用clang。如果源和目标不重叠,则memcpy(d,4);
的行为被指定为等同于:
((unsigned char*)d)[0] = ((unsigned char*)s)[0];
((unsigned char*)d)[1] = ((unsigned char*)s)[1];
((unsigned char*)d)[2] = ((unsigned char*)s)[2];
((unsigned char*)d)[3] = ((unsigned char*)s)[3];
但是,Clang将利用这样一个事实,即可以假定uint32_t*
永远不会保存未对齐的地址,从而生成使用单个32位加载和存储的代码,因此仅在指针对齐。尽管clang生成的代码用于执行对uint32_t*
的赋值并不关心指针是否对齐,并且尽管在将指针传递给void*
时将其强制转换为memcpy
,在该事件序列中将指针转换为uint32_t*
会导致clang生成确实在乎对齐的代码。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。