找回密码
 立即注册
查看: 436|回复: 29

C251又出bug了,有关数组下标减法计算 | 这段程序对于C251来说是错误的程序 ?

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:165
  • 最近打卡:2026-03-07 00:57:19

25

主题

231

回帖

2033

积分

金牌会员

积分
2033
发表于 2026-1-30 13:51:40 | 显示全部楼层 |阅读模式
举例说明,向位于xdata的数组写入数据

  1. void write(uint16_t *dst, uint16_t dat)
  2. {
  3.     int i;        
  4.         
  5.     for (i = 15; i >= 0; i--)
  6.     {
  7.         dst[15 - i] = dat;
  8.     }
  9. }
复制代码


假设当前i=14,显然 dst[15 - i] 应该是访问 dst[1]。
dst如果是xdata空间起始的数组,即地址为0x10000,那么dst[1]的地址应该是0x10002。
然而,C251编译出的代码并非如此。看汇编代码

XRL      WR6,WR6
SUB      WR6,WR28
SLL      WR6
ADD      WR6,WR10
MOV      WR4,WR8
MOV      @DR4+0x001E,WR30

设i=14
先计算 0 - i 的值即 -i ,得到-14(即 0xFFF2);
因为是int16类型,所以左移一位相当于乘以2,得到 -28(即 0xFFE4);
"-i"加上dst地址低16位,即0xFFE4 + 0x0000 = 0xFFE4;存入DR4结果为0x01FFE4。
最后用(@DR4+0x001E)作为内存的地址访问。
写入地址即0x01FFE4 + 0x001E;直接按算术加法来的话结果是0x020002,已经不是xdata空间了。
而我们需要写入的地址是0x010002。

在实际芯片上运行,该写入的地址没有写入,反而乱修改其它变量。
此bug极为隐晦,看C代码看不出一点问题。
程序调试好几天,各种奇怪的故障,动不动崩溃,找不出原因。
明明这个模块改动一个小地方,却对其它模块的变量造成严重破坏,皆是因此而来。

结论:C251下数组下标慎用减法计算。




1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:71
  • 最近打卡:2026-03-07 09:59:50
已绑定手机

4

主题

198

回帖

748

积分

高级会员

积分
748
发表于 2026-1-30 14:32:53 | 显示全部楼层
没看太明白,意思是先加15后减14和先减14后加15的结果不一样?真奇怪。
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:165
  • 最近打卡:2026-03-07 00:57:19

25

主题

231

回帖

2033

积分

金牌会员

积分
2033
发表于 2026-1-30 15:08:09 来自手机 | 显示全部楼层
主要是内存分区的原因,高位地址,也表示内存类型,有时候计算考虑高位地址,有时候又忽略高位地址,造成混乱。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:467
  • 最近打卡:2026-03-07 15:12:16
已绑定手机

102

主题

4137

回帖

9103

积分

荣誉版主

无情的代码机器

积分
9103
发表于 2026-1-30 15:31:29 | 显示全部楼层
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:659
  • 最近打卡:2026-03-07 11:42:18

9

主题

607

回帖

4251

积分

论坛元老

积分
4251
发表于 2026-1-30 15:46:13 | 显示全部楼层
访问存储器的地址都是无符号整数.所以用作处理存储地址的变量,最好转换成无符号整数类型
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:243
  • 最近打卡:2026-03-06 08:17:29
已绑定手机

22

主题

622

回帖

2294

积分

金牌会员

积分
2294
发表于 2026-1-30 16:41:41 | 显示全部楼层
没看懂
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:243
  • 最近打卡:2026-03-06 08:17:29
已绑定手机

22

主题

622

回帖

2294

积分

金牌会员

积分
2294
发表于 2026-1-30 16:44:08 | 显示全部楼层
这是完整的汇编,应该没有问题的
; line 695: void write(u16 *dst, u16 dat)
        MOV      WR30,WR6
;---- Variable 'dat' assigned to Register 'WR30' ----
        MOV      DR8,DR0
;---- Variable 'dst' assigned to Register 'DR8' ----
; line 696: {
; line 697:     int i;        
; line 698:         
; line 699:     for (i = 15; i >= 0; i--)
        MOV      WR28,#0FH
;---- Variable 'i' assigned to Register 'WR28' ----
?C0182:
; line 700:     {
; line 701:         dst[15 - i] = dat;
        XRL      WR6,WR6
        SUB      WR6,WR28
        SLL      WR6
        ADD      WR6,WR10
        MOV      WR4,WR8
        MOV      @DR4+0x1E,WR30
; line 702:     }
        DEC      WR28,#01H
        CMP      WR28,#00H
        JSGE     ?C0182
; line 703: }
        ERET   

点评

方法正确,看完整程序,不断章取义  详情 回复 发表于 2026-1-30 19:05
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:165
  • 最近打卡:2026-03-07 00:57:19

25

主题

231

回帖

2033

积分

金牌会员

积分
2033
发表于 2026-1-30 17:39:44 | 显示全部楼层
Ayb_*** 发表于 2026-1-30 16:44
这是完整的汇编,应该没有问题的
; line 695: void write(u16 *dst, u16 dat)
        MOV      WR30,WR6

实测一下就知道了,可以用keil软仿真。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:761
  • 最近打卡:2026-03-07 09:49:48
已绑定手机

16

主题

1402

回帖

4893

积分

论坛元老

积分
4893
发表于 2026-1-30 17:54:42 | 显示全部楼层
严格来说,这个“问题”不算BUG,从整体设计上是没问题的。
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:165
  • 最近打卡:2026-03-07 00:57:19

25

主题

231

回帖

2033

积分

金牌会员

积分
2033
发表于 2026-1-30 17:58:12 | 显示全部楼层

传入参数dst = xdata首地址0x10000
; line 695: void write(u16 *dst, u16 dat)
        MOV      WR30,WR6
;---- Variable 'dat' assigned to Register 'WR30' ----
        MOV      DR8,DR0
;---- Variable 'dst' assigned to Register 'DR8' ----变量dst分配给DR8
; line 696: {
; line 697:     int i;        
; line 698:         
; line 699:     for (i = 15; i >= 0; i--)
        MOV      WR28,#0FH                    ;i = 15
;---- Variable 'i' assigned to Register 'WR28' ----变量i分配给WR28
?C0182:
; line 700:     {
; line 701:         dst[15 - i] = dat;
        XRL      WR6,WR6       ;WR6清零
        SUB      WR6,WR28     ;WR6 = 0 - i = -15 = 0xFFF1
        SLL      WR6               ;WR6 = -15 * 2 = -30 = 0xFFE2
        ADD      WR6,WR10     ;WR6 = 0xFFE2 + dst低16位 = 0xFFE2
        MOV      WR4,WR8       ;WR4 = dst高16位即0x0001,此时DR4 = 0x0001FFE2
        MOV      @DR4+0x1E,WR30     ;数据写入地址[DR4+0x1E] = [0x0001FFE2 + 0x1E] = [0x00020000],本应写入dst[0]即地址[0x00010000]才对。
; line 702:     }
        DEC      WR28,#01H
        CMP      WR28,#00H
        JSGE     ?C0182
; line 703: }
        ERET

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-7 20:02 , Processed in 0.119722 second(s), 98 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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