完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
我在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); } |
|
相关推荐
14个回答
|
|
解决了,是字节对齐问题,要凑够32位,分享一下别人的介绍http://blog.csdn.net/u013445530/article/details/44005057
|
|
|
|
1.指针++后的具体“跨度”取决于该指针的数据类型,这就要求你的强制类型转换要“得体”。
即使人眼看的不明显也得让编译器明白才行,你的tmp是u16的,但是强制转换的结构体并没有体现出来和它对应的值。 2.指针++后无论“跨度”怎么样确实会指向一个内存,但这个内存不一定是安全或可以用的。STM32永远不会把4GB的存储器地址全部用完且都可访问即使你只是读。 3.内核寄存器寻址和存储器寻址不是一个概念,对于STM32,对内核寄存器寻址只能使用R0~R15等方式(意思就是说你如果不用汇编则无法直接访问到),对存储器寻址可以直接引用其地址值(无论是外设寄存器或者是RAM存储器等)。 你说的“指针跳到STM32的寄存器当中”我对你的理解是对存储器的寻址,当你试图访问系统不允许的位置时自然会引起HardFault。由于你存在不“得体”的强制类型转换,使得内存位置访问变得不可靠,具体你可以调试到此处时打开汇编,看下具体的位置是否被允许访问。但指针错误引用不是导致HardFault的唯一原因,比如大小越位也会导致此类错误。 4.你说的其它MCU可行,那完全是巧合导致的。这中巧合可能由于编译器、芯片类型、存储器映射、代码大小等等各类因素制约,但它基于错误的指针运算,永远都不是安全的即使你看起来“行得通”。 |
|
|
|
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; } } 你们试试这段代码看看能不能跑通 |
|
|
|
STORAGE saveblock,Storage;
他们都是STORAGE类型的,即使可以通过强制类型转换你也得转换的“得体”才行。 对于: Tmp = (u16*)&saveblock; 这种,显然有问题!即使你现在没有出现问题。 语法上看,你把Tmp+=1,相当于u16的指针往下跳u16,跟STORAGE内部完全匹配不上。 |
|
|
|
7762642422d 发表于 2019-1-9 13:59 我不赞同你的说法,它更内部匹配没有关系, 我只是把这个变量的地址取出来,不管你匹不匹配,指针++后,都应该能够正常指向下一个内存, 我仅仅是读取了下一个内存单元的值,就跳入硬件错误,就算指针跳到STM32的寄存器当中,不管怎么样也该可以读取 |
|
|
|
经过测试 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; } |
|
|
|
|
|
|
|
觉得这样访问地址确实有问题、
|
|
|
|
学习了,要注意对齐
|
|
|
|
7762642422d 发表于 2019-1-9 13:35 虽然看不懂,但是觉得你说得有道理,看来我需要补一补转换得体这一块 |
|
|
|
MARK
|
|
|
|
看到楼主 和 moyanming2013的回复蛮有感触上来发个言.
昨晚出现的这个问题,类似楼主,不过我注意到可能通过指针读写结构体会出现一些问题,为了协议组包方便,我们结构体定义的时候全部都使用 #pragma pack (1) 声明结构体 #pragma pack() 禁止keil编译器的字节对齐. 但是还是出现了问题,一个指针很明显是指向的结构体那块存储空间了,但是一旦向指针指向的空间写入数据就会进入硬件故障中断. 我的认识,如果禁止字节对齐,那么存储空间都是以个字节为单位,我用指针指向结构体的内存空间,然后写入数据,多么天经地义,这不就是指针的魅力所在.....可是不知道为什么报错了,有点颠覆认知.如果像楼上那位老师说的可能换芯片同样的写法就会不能使用,那对我来说可能是个灾难了... |
|
|
|
野指针,或越界了
|
|
|
|
很简单的问题
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
969 浏览 0 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
954 浏览 2 评论
2066 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1162 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1587 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 13:04 , Processed in 0.772939 second(s), Total 66, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号