举例说明,向位于xdata的数组写入数据
- void write(uint16_t *dst, uint16_t dat)
- {
- int i;
-
- for (i = 15; i >= 0; i--)
- {
- dst[15 - i] = dat;
- }
- }
复制代码
假设当前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下数组下标慎用减法计算。
|