c – 请解释此对齐错误
#include <stdio.h> void main(void) { char array[4] = {0,1,2,3}; float *fpek; int i; for(i=0;i<4;i++) { fprintf(stderr,"i = %d ",i); fpek = (float *)(&array[i]); fprintf(stderr,"fpek = %lx ",(unsigned long) fpek); *fpek = (float) i + 10; fprintf(stderr,"*fpek = %.2fn",*fpek); } } $cc alignment.c $a.out i = 0 fpek = effff0fc *fpek = 10.00 i = 1 fpek = effff0fd Bus error 上面的代码可以在C编程实践资料中找到.我理解这些陈述本身,但我并没有真正看到作者试图说明的内容.为什么会出现总线错误? 解决方法
对齐与否,这是完全错误的:
fpek = (float *)(&array[i]); // invalid for i>0,questionable for i==0 fprintf(stderr,(unsigned long) fpek); *fpek = (float) i + 10; 由于数组是最好的四个字符宽,即使你的系统浮点数是4个字节,当你使用i> 0时,你会立即寻址(可能是未对齐的)数据i字节超出数组的范围.一旦你取消引用那个指针,你就会因为未对准而导致总线错误,或者你的架构没有对齐浮点数(大多数情况下)没有对齐限制你将开始用赋值转换堆栈变量接下来. 为了突出显示作者可能试图解决的错误(该对齐可能很重要)而不引入除此之外的未定义行为,请考虑这样的事情: #include <stdlib.h> #include <stdio.h> int main() { /* note: defined to hold enough bytes for *two* floats. */ float *fpek = NULL; char array[2*sizeof(*fpek)]; int i; /* fill with incrementing values */ for (i=0; i<sizeof(array)/sizeof(array[0]);++i) array[i] = (i+1); // now walk the array,one char at a time,// casting the address of the current element // to a float pointer and try to read/write it. fprintf(stderr,"array = %p,size=%lun",array,sizeof(array)); for(i=0;i<sizeof(*fpek);++i) { fprintf(stderr,"i = %d,",i); fpek = (void*)(array+i); fprintf(stderr,"fpek = %p,fpek); *fpek = i+10; fprintf(stderr,*fpek); } return 0; } 无论您的系统上的浮点数有多宽/多,这都可以工作,而不会引入特定于遍历char数组末尾的未定义行为.它很可能仍然是总线错误,但至少可以解决超出数组下标的UB问题. 在我的Mac Air(英特尔64位CPU)上运行此操作不会产生总线错误: array = 0x7fff5fbff868,size=8 i = 0,fpek = 0x7fff5fbff868,*fpek = 10.00 i = 1,fpek = 0x7fff5fbff869,*fpek = 11.00 i = 2,fpek = 0x7fff5fbff86a,*fpek = 12.00 i = 3,fpek = 0x7fff5fbff86b,*fpek = 13.00 正如您所看到的,我的平台对于浮动对齐并不是特别挑剔.您的结果可以(并且根据您之前的输出判断,可能会有所不同). 注意:fpek =(void *)(array i)的(void *)强制转换;可能看起来很奇怪,但这是C,所以我可以逃脱它.我这样做的原因是允许您演示其他浮点类型,看看它们是否有对齐限制.如上所述,您可以将函数顶部的fpek声明更改为double: double *fpek = NULL; 然后重新运行该程序.在我的系统上,这会产生: array = 0x7fff5fbff860,size=16 i = 0,fpek = 0x7fff5fbff860,fpek = 0x7fff5fbff861,fpek = 0x7fff5fbff862,fpek = 0x7fff5fbff863,*fpek = 13.00 i = 4,fpek = 0x7fff5fbff864,*fpek = 14.00 i = 5,fpek = 0x7fff5fbff865,*fpek = 15.00 i = 6,fpek = 0x7fff5fbff866,*fpek = 16.00 i = 7,fpek = 0x7fff5fbff867,*fpek = 17.00 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |