加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 请解释此对齐错误

发布时间:2020-12-16 09:41:46 所属栏目:百科 来源:网络整理
导读:#include stdio.hvoid main(void){ char array[4] = {0,1,2,3}; float *fpek; int i; for(i=0;i4;i++) { fprintf(stderr,"i = %d ",i); fpek = (float *)(array[i]); fprintf(stderr,"fpek = %lx ",(unsigned long) fpek); *fpek = (float) i + 10; fprintf(
#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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读