你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

指针访问结构体出现硬件错误

[复制链接]
飞儿 提问时间:2016-12-2 13:44 /
我在MDK518环境下, 使用STM32F072芯片,在做结构体时,定义了两个变量saveblock,Storage。用指针访问saveblock成功,访问Storage时就跳转到硬件错误,  两个变量是同一个结构,进行的同样的操作,为什么先定义的那个就没事,后定义的那个旧不能正常访问。

typedef union
{
        u8 Mem[6];
        struct
        {
                u8 ID            : 8;
                u8 Year                : 8;
                u8 Month        : 4;
                u8 Day                : 6;
                u8 Hour                : 6;
                u8 Minute        : 8;
                u8 Second        : 8;                       
        }Date;
}Date_Union;

typedef struct {
               
        u8 Machine_State[2];
        Date_Union Date_Result;               
       
}STORAGE;

STORAGE saveblock,Storage;


int main()
{       
        u16 *Tmp;       
        u16 TestValue;
                       
        saveblock.Date_Result.Date.ID=0x15;
        Storage.Date_Result.Date.ID=0x16;
       
        Tmp = (u16*)&saveblock;
        Tmp+=2;
        TestValue = *Tmp;
       
        Tmp = (u16*)&Storage;
        Tmp+=1;
        TestValue = *Tmp;        //调试的时候  在这里跳转到硬件错误  不能正常读取
       
        while(1);
}

收藏 1 评论12 发布时间:2016-12-2 13:44

举报

12个回答
飞儿 最优答案 回答时间:2016-12-2 14:51:28
解决了,是字节对齐问题,要凑够32位,分享一下别人的介绍http://blog.csdn.net/u013445530/article/details/44005057

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2 结贴奖励

查看全部评分

moyanming2013 回答时间:2016-12-2 15:03:14
本帖最后由 moyanming2013 于 2016-12-2 15:07 编辑
风铃草2 发表于 2016-12-2 14:19
我不赞同你的说法,它更内部匹配没有关系,  我只是把这个变量的地址取出来,不管你匹不匹配,指针++后, ...

1.指针++后的具体“跨度”取决于该指针的数据类型,这就要求你的强制类型转换要“得体”。
即使人眼看的不明显也得让编译器明白才行,你的tmp是u16的,但是强制转换的结构体并没有体现出来和它对应的值。
2.指针++后无论“跨度”怎么样确实会指向一个内存,但这个内存不一定是安全或可以用的。STM32永远不会把4GB的存储器地址全部用完且都可访问即使你只是读。
3.内核寄存器寻址和存储器寻址不是一个概念,对于STM32,对内核寄存器寻址只能使用R0~R15等方式(意思就是说你如果不用汇编则无法直接访问到),对存储器寻址可以直接引用其地址值(无论是外设寄存器或者是RAM存储器等)。
你说的“指针跳到STM32的寄存器当中”我对你的理解是对存储器的寻址,当你试图访问系统不允许的位置时自然会引起HardFault。由于你存在不“得体”的强制类型转换,使得内存位置访问变得不可靠,具体你可以调试到此处时打开汇编,看下具体的位置是否被允许访问。但指针错误引用不是导致HardFault的唯一原因,比如大小越位也会导致此类错误。
4.你说的其它MCU可行,那完全是巧合导致的。这中巧合可能由于编译器、芯片类型、存储器映射、代码大小等等各类因素制约,但它基于错误的指针运算,永远都不是安全的即使你看起来“行得通”。

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2

查看全部评分

飞儿 回答时间:2016-12-2 13:46:27
typedef union
{
        u8 Mem[6];
        struct
        {
                u8 ID            : 8;
                u8 Year                : 8;
                u8 Month        : 4;
                u8 Day                : 6;
                u8 Hour                : 6;
                u8 Minute        : 8;
                u8 Second        : 8;                       
        }Date;
}Date_Union;

typedef struct {
               
        u8 Machine_State[2];
        Date_Union Date_Result;               
       
}STORAGE;

STORAGE saveblock,Storage;

u8 Errno;
void Test(void)
{
        u16 *Tmp;       
        u16 TestValue;
                       
        saveblock.Date_Result.Date.ID=0x15;
        Storage.Date_Result.Date.ID=0x16;
       
        Tmp = (u16*)&saveblock;
        Tmp+=1;
        TestValue = *Tmp;
        if(TestValue!=0x0015)
        {
                Errno=1;
        }
       
        Tmp = (u16*)&Storage;
        Tmp+=1;
        TestValue = *Tmp;       
        if(TestValue!=0x0016)
        {
                Errno=1;
        }       
}

你们试试这段代码看看能不能跑通
moyanming2013 回答时间:2016-12-2 13:51:57
STORAGE saveblock,Storage;
他们都是STORAGE类型的,即使可以通过强制类型转换你也得转换的“得体”才行。
对于:
Tmp = (u16*)&saveblock;
这种,显然有问题!即使你现在没有出现问题。
语法上看,你把Tmp+=1,相当于u16的指针往下跳u16,跟STORAGE内部完全匹配不上。
飞儿 回答时间:2016-12-2 14:19:46
moyanming2013 发表于 2016-12-2 13:51
STORAGE saveblock,Storage;
他们都是STORAGE类型的,即使可以通过强制类型转换你也得转换的“得体”才行。 ...

我不赞同你的说法,它更内部匹配没有关系,  我只是把这个变量的地址取出来,不管你匹不匹配,指针++后,都应该能够正常指向下一个内存, 我仅仅是读取了下一个内存单元的值,就跳入硬件错误,就算指针跳到STM32的寄存器当中,不管怎么样也该可以读取
飞儿 回答时间:2016-12-2 14:21:40
经过测试 STM32F103没有问题  ,STM32F072将指针变为8位的也行的通,  就是16位的失败
        u8 *Tmp;       
        u16 TestValue;
                       
        saveblock.Date_Result.Date.ID=0x15;
        Storage.Date_Result.Date.ID=0x16;
       
        Tmp = (u8*)&saveblock;
        Tmp+=2;
        TestValue = *Tmp;
        if(TestValue!=0x15)
        {
                Errno=1;
        }
       
        Tmp = (u8*)&Storage;
        Tmp+=2;
        TestValue = *Tmp;       
        if(TestValue!=0x16)
        {
                Errno=1;
        }       

creep 回答时间:2016-12-2 14:46:40
本帖最后由 creep 于 2016-12-2 14:50 编辑

测试了F76x运行下代码没有问题。楼主看下fault的时候Tmp的地址是不是有问题。
小小超 回答时间:2016-12-2 15:32:07
觉得这样访问地址确实有问题、
peter001 回答时间:2016-12-2 18:53:00
学习了,要注意对齐
飞儿 回答时间:2016-12-5 09:55:32
moyanming2013 发表于 2016-12-2 15:03
1.指针++后的具体“跨度”取决于该指针的数据类型,这就要求你的强制类型转换要“得体”。
即使人眼看的不 ...

虽然看不懂,但是觉得你说得有道理,看来我需要补一补转换得体这一块
斜阳 回答时间:2016-12-5 10:12:26
MARK                              
天上飞的大树 回答时间:2018-6-3 10:57:37
看到楼主 和 moyanming2013的回复蛮有感触上来发个言.
昨晚出现的这个问题,类似楼主,不过我注意到可能通过指针读写结构体会出现一些问题,为了协议组包方便,我们结构体定义的时候全部都使用
#pragma pack (1)
声明结构体
#pragma pack()
禁止keil编译器的字节对齐.
但是还是出现了问题,一个指针很明显是指向的结构体那块存储空间了,但是一旦向指针指向的空间写入数据就会进入硬件故障中断.
我的认识,如果禁止字节对齐,那么存储空间都是以个字节为单位,我用指针指向结构体的内存空间,然后写入数据,多么天经地义,这不就是指针的魅力所在.....可是不知道为什么报错了,有点颠覆认知.如果像楼上那位老师说的可能换芯片同样的写法就会不能使用,那对我来说可能是个灾难了...

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版