当前位置:  开发笔记 > 编程语言 > 正文

这是编译器错误吗?

如何解决《这是编译器错误吗?》经验,为你挑选了1个好方法。

我的几乎微观的基于8051的嵌入式系统有一个调试串口,我写了一个简单的串口输出功能,它运行正常,直到我做了一些小的调整,以减少其内存占用.然后是以下行,哪个WAS工作正常(并且不是更改的一部分)......

dbg_TxBuf[(dbg_TxBufProduceCount++) & (sizeof(dbg_TxBuf) - 1)] = ch;

......停止了正常工作 变量dbg_TxBufdbg_TxBufProduceCount全局变量,仅由输出函数和串行端口ISR使用(根本没有更改):

#define DBG_TX_BUFFER_SIZE 16 // MUST be a power-of-2 (this line is actually in a separate file, not that it matters)
volatile uint8_t xdata dbg_TxBuf[DBG_TX_BUFFER_SIZE]; // must be sized by a power-of-2, and MUST BE LESS THAN 256 since the 'count' vars are uint8
volatile uint8_t xdata dbg_TxBufProduceCount; // akin to a 'head' index but more useful since it allows use of every byte in the buf
volatile uint8_t xdata dbg_TxBufConsumeCount; // akin to a 'tail' index but more useful since it allows use of every byte in the buf

具体发生了什么事是编译器现在优化的代码行的方式是dbg_TxBufProduceCount正在增加(在内存中)之前,该点ch被写入dbg_TxBuf.然后串口ISR"偶尔"(实际上经常)看到dbg_TxBufConsumeCount != dbg_TxBufProduceCountdbg_TxBuf[(dbg_TxBufConsumeCount++) & (sizeof(dbg_TxBuf) - 1)]在输出函数写入ch它之前读取.因此我的串口输出损坏了.

这是该行的8051反汇编:

935>       dbg_TxBuf[(dbg_TxBufProduceCount++) & (sizeof(dbg_TxBuf) - 1)] = ch;
DC84: 9006D6   MOV   DPTR,#dbg_TxBufProduceCount
DC87: E0       MOVX  A,@DPTR    <--- loads the value in dbg_TxBufProduceCount into the A register
DC88: FE       MOV   R6,A       <--- saves a copy of it in R6
DC89: 04       INC   A          <--- increments it
DC8A: F0       MOVX  @DPTR,A    <--- writes the incremented value 
DC8B: EE       MOV   A,R6       <--- gets the original copy of ProduceCount back in A
DC8C: 7C00     MOV   R4,#00     Begin computing address of dbg_TxBuf[~]...
DC8E: 540F     ANL   A,#0F      <--- A = A & (sizeof(dbg_TxBuf) - 1)
DC90: 24D8     ADD   A,#0D8     <--- A is now the low byte of &dbg_TxBuf[~]
DC92: F582     MOV   DPL,A      <--- put that in DPL
DC94: EC       MOV   A,R4       <--- (an inefficient way of loading the...
DC95: 3406     ADDC  A,#06      <---   ...immediate value 0x06 into A)
DC97: F583     MOV   DPH,A      <--- DPTR now points to dbg_TxBuf[~]
DC99: EF       MOV   A,R7       <--- load 'ch' into A
DC9A: F0       MOVX  @DPTR,A    <--- write 'ch' to *DPTR

从"本地"的角度来看,编译器正确地处理后增量运算符,因为它使用dbg_TxBufProduceCount了索引计算中增量之前的值dbg_TxBuf,但从"全局"的角度来看,它似乎不是处理事件的顺序正确,尤其是因为我宣布双方dbg_TxBuf[]dbg_TxBufProduceCount作为volatile.在写入dbg_TxBufProduceCount内存,编译器是否应该将增量值写入ch内存?

顺便说一下,我正在使用Keil 8051 C编译器,v7.10.我不知道v7.10何时发布,但似乎我们对编译器的支持于2005年5月结束.



1> David Schwar..:

在将ch写入内存后,编译器是否应该将dbg_TxBufProduceCount的递增值写入内存?

不,没有理由应该这样做.没有任何事情对单个声明中发生的操作施加任何排序.这是一个写入两个volatile变量的语句 - 它可以按任意顺序写入它们.从概念上讲,它与以下内容没有什么不同:

i = a++ + b++;

即使a并且b是易失性的,编译器也可以自由地生成代码以便以任何顺序写入它们.未指定单个语句的部分的评估顺序以及该指令的副作用可见的顺序.

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有