搜索
bottom↓
回复: 27

[已解决]求教:同一个C语言工程同一段代码不同地方运行...

[复制链接]

出20入0汤圆

发表于 2018-12-28 18:35:22 | 显示全部楼层 |阅读模式
本帖最后由 talkingbeast 于 2018-12-29 10:38 编辑

求教各位,是否遇到这样的问题:
  同一段代码,代码如下
  1.         //test 2018-12-28 14:39:48
  2.         SystemInfo.BMS_Info_B.BMS_BCL.BCL_ChargeMode=02;//02
  3.         SystemInfo.BMS_Info_B.BMS_BCL.BCL_CurrnetRequire=0x0F69;//0x0F69
  4.         SystemInfo.BMS_Info_B.BMS_BCL.BCL_VoltageRequire=0x0E5E;//0x0E5E
复制代码


放在不同的文件中,一段是放在 main.c中(测试用),测试可以正确执行;
一段是放在 ev.c中,测试发现执行错误,两段代码调试截图如下
正常编译截图

————————————————————
错误编译截图


经过对比,两段不同位置运行的代码编译后,区别在于结构体地址不同,但是我赋值的结构体明明是相同的啊,都是SystemInfo.BMS_Info_B
SystemInfo.BMS_Info_B.是一个嵌套结构体
  请问有人遇到类似问题吗?我也是第一次遇到这样的问题,百思不得其解,求高手解惑

2018-12-29 更新 问题基本已解决,谢谢帮忙回答的各位高手
结果检查,有一个头文件中我不小心写了#pragma pack(1)但是没有成对使用#pragma pack()取消对齐,导致包含了此头文件的源文件(ev.c)会强制1字节对齐,未包含此头文件的源文件(main.c)采用默认对齐方式,两个源文件中对齐方式不同导致代码编译后地址解析不同;
我在代码中使用了结构体,如果没有设置对齐,可能结构体的某些字段会分配到奇地址,使用结构体转换时会出线hardfault,使用#pragma pack(n)对齐就ok了。
不知道我的理解是否正确,欢迎大家指点。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出30入54汤圆

发表于 2018-12-28 18:44:46 | 显示全部楼层
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传入的指针可能存在地址问题

出0入0汤圆

发表于 2018-12-28 18:53:29 来自手机 | 显示全部楼层
cloudboy 发表于 2018-12-28 18:44
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传 ...

666,厉害

出20入0汤圆

 楼主| 发表于 2018-12-28 18:58:49 | 显示全部楼层
cloudboy 发表于 2018-12-28 18:44
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传 ...

  我传入的是结构体指针,意思是结构体没有对齐吗,需要如何解决

出30入54汤圆

发表于 2018-12-28 19:07:53 | 显示全部楼层
建议检查一下结构体的地址是不是对齐的,然后实际指令来看D这个地址偏移不是16位对齐的,而指令是half

出20入0汤圆

 楼主| 发表于 2018-12-28 19:28:11 | 显示全部楼层
cloudboy 发表于 2018-12-28 19:07
建议检查一下结构体的地址是不是对齐的,然后实际指令来看D这个地址偏移不是16位对齐的,而指令是half ...

结构体要如何对齐,我使用 #pragma pack(1) 对齐,但是好像没有效果

出30入54汤圆

发表于 2018-12-28 20:40:41 | 显示全部楼层
一般是pack 4,你可以追踪断点后面的r0的值,r0应该是指针的值,然后加上偏移, 看看具体放到哪里去了

出100入113汤圆

发表于 2018-12-28 20:40:42 | 显示全部楼层
talkingbeast 发表于 2018-12-28 19:28
结构体要如何对齐,我使用 #pragma pack(1) 对齐,但是好像没有效果

1改成2   2字节对齐

出5入14汤圆

发表于 2018-12-28 21:27:52 来自手机 | 显示全部楼层
疑惑:结构体为什么要对齐?里面分别定义字、字节不行吗?

出0入442汤圆

发表于 2018-12-28 23:09:21 来自手机 | 显示全部楼层
talkingbeast 发表于 2018-12-28 19:28
结构体要如何对齐,我使用 #pragma pack(1) 对齐,但是好像没有效果

pack 1哪是对齐啊,那是为了省ram才用的。正常的结构体所有元素的长度都跟最长的那个一样,多出来的空着不用(不包括字符串,但字符串首地址也对齐到最长的那个长度)。

出0入0汤圆

发表于 2018-12-28 23:18:42 | 显示全部楼层
cloudboy 发表于 2018-12-28 18:44
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传 ...

666,大神能分享一下其他未对齐访问的例子吗

出0入0汤圆

发表于 2018-12-28 23:42:39 | 显示全部楼层
是指针配置的时候需要对齐吧

出0入362汤圆

发表于 2018-12-29 00:33:04 | 显示全部楼层
负西弱 发表于 2018-12-28 23:18
666,大神能分享一下其他未对齐访问的例子吗

比如用串口传来的二进制数据:
void parse(const unsigned char* msg) {
        unsigned char id = *(unsigned char*)msg;
        unsigned short size = *(unsigned short*)(msg + 1);
        ...
}

类似这样的程序,在PC或者8位MCU或者stm32f10x上都没问题,但是在stm32f0xx上就会hard fault,因为不能强制按unsigned short来读取奇数内存地址的变量。
同理,如果是unsigned long的数据,地址必须能被4整除。
8位机自然没这个问题,PC和cortex-m3也都能处理非对齐访问,只是损失一点性能,但是cortex-m0就直接出错。

解决办法:1. 改协议,要求串口二进制数据帧里unsigned short数据必须在偶数地址,unsigned long数据必须在被4整除地址。
2. 改成用memcpy
  1. unsigned short size;
  2. memcpy(&size, msg + 1, sizeof(size));
复制代码

3. 笨办法, unsigned short size = *(msg + 1) + *(msg + 2) * 256; (小端序的情况,大部分场合适用)

出0入0汤圆

发表于 2018-12-29 08:23:24 来自手机 | 显示全部楼层
赞楼上,理解很深

出20入0汤圆

 楼主| 发表于 2018-12-29 08:42:53 | 显示全部楼层
wye11083 发表于 2018-12-28 23:09
pack 1哪是对齐啊,那是为了省ram才用的。正常的结构体所有元素的长度都跟最长的那个一样,多出来的空着 ...

  那为什么会出现我这个帖子描述的这种情况呢,同一段代码运行结构不同,一段正确一段错误。

出0入34汤圆

发表于 2018-12-29 08:44:22 | 显示全部楼层
本帖最后由 epwwm 于 2018-12-29 09:18 编辑

都是大神,膜拜.

只懂,while(1),if ,for 路过

出20入0汤圆

 楼主| 发表于 2018-12-29 08:47:41 | 显示全部楼层
tomzbj 发表于 2018-12-29 00:33
比如用串口传来的二进制数据:

类似这样的程序,在PC或者8位MCU或者stm32f10x上都没问题,但是在stm32f0 ...

  大神,你说的第一种方法,我一般定义一个协议结构体来处理接收,一般都会出现奇地址解析问题,很多时候还需要解析字节里面的位段,所以我一般都是使用 #pragma pack(1) 强制按1字节分配结构体空间来满足协议要求;
请帮忙分析下为啥会出现我说的这种问题,谢谢!

出5入14汤圆

发表于 2018-12-29 08:57:29 | 显示全部楼层
epwwm 发表于 2018-12-29 08:44
都是大神,腊拜.

只懂,while(1),if ,for 路过

Me too ,,,,,, 看了半天都不知道大神们说的是啥,我还以为我会用结构体已经很了不起了!

出0入34汤圆

发表于 2018-12-29 09:19:37 | 显示全部楼层
EMC菜鸟 发表于 2018-12-29 08:57
Me too ,,,,,, 看了半天都不知道大神们说的是啥,我还以为我会用结构体已经很了不起了! ...


我连结构体也糊里糊涂,实质也搞不懂

出0入0汤圆

发表于 2018-12-29 09:44:33 | 显示全部楼层
cloudboy 发表于 2018-12-28 18:44
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传 ...

666,厉害

出0入0汤圆

发表于 2018-12-29 10:04:49 | 显示全部楼层
cloudboy 发表于 2018-12-28 18:44
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传 ...

一击即中,厉害了~膜拜大神~

出0入0汤圆

发表于 2018-12-29 10:20:23 | 显示全部楼层
talkingbeast 发表于 2018-12-29 08:47
大神,你说的第一种方法,我一般定义一个协议结构体来处理接收,一般都会出现奇地址解析问题,很多时候 ...


出问题的代码,用了#pragma pack  (1)修饰?

出20入0汤圆

 楼主| 发表于 2018-12-29 10:36:00 | 显示全部楼层
shiva_shiva 发表于 2018-12-29 10:20
出问题的代码,用了#pragma pack  (1)修饰?

  是的,楼主位贴子我说明了。头文件中不小心把#pragma pack  (1)写上但是没有用#pragma pack  ()取消,导致出问题的c文件包含了这个#pragma pack  (1),两处代码对齐方式不同导致执行错误。

出20入0汤圆

 楼主| 发表于 2018-12-29 10:38:16 | 显示全部楼层
cloudboy 发表于 2018-12-28 18:44
从你的第二张图可以看到,STRH指令引用了一个未对齐的地址,这可能导致未对齐访问问题。可以合理地推导你传 ...

  确实是未对齐地址,只不过造成这种情况的原因不是结构体未对齐,楼主位贴子更新说明了。
  谢谢指教,不知道我的理解是否正确。

出0入4汤圆

发表于 2018-12-29 10:41:14 | 显示全部楼层
从代码看,楼主是做BMS的,还支持快充

出20入0汤圆

 楼主| 发表于 2018-12-29 10:54:22 | 显示全部楼层
xiaoyigechaos 发表于 2018-12-29 10:41
从代码看,楼主是做BMS的,还支持快充

作充电桩,遗留的老代码

出0入0汤圆

发表于 2018-12-29 21:04:30 | 显示全部楼层
tomzbj 发表于 2018-12-29 00:33
比如用串口传来的二进制数据:

类似这样的程序,在PC或者8位MCU或者stm32f10x上都没问题,但是在stm32f0 ...

谢谢分享,我平时用的一般都是方法2或者方法3,就碰巧没遇上问题了

出30入54汤圆

发表于 2018-12-29 21:12:51 | 显示全部楼层
理解正确。一般来说,CM3和CM4的核会自动将一次非对齐(字访问的地址不是4的整数倍或者半字访问的地址不是2的整数倍)的ld或者st访问拆封成两次对齐访问,虽然方便了我们,但是导致用户在编写代码的时候忽略了这个问题。刚工作的时候经常随意转换结构体,然后上csky的核一跑就gg。不过这里吐槽一下cm的核,各种内存错误都会进hardfault,有时候很难一下子看出来是什么问题,csky就会分成好多种不同的异常一目了然
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-25 11:14

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表