C51单片机中reentrant关键字的使用,关于MULTIPLE CALL TO FUNCTION警告的问题
📅 2026/7/16 21:15:15
👁️ 阅读次数
📝 编程学习
关于可重入关键字reentrant的使用:
现象:
在一个项目中警告信息如下,提示该函数多次调用,因为该函数在串口中断和主循环中都有被调用。
影响:
如果在使用该函数期间被中断打断,而中断也调用了该函数,那么该函数的局部变量会被覆盖。当中断结束返回,则此时的变量已经被中断修改了,此时的数据不对,会出现意想不到的结果。
这就是:不可重入(non-reentrant)
原因:
Keil C51 为了省 RAM、提速,普通函数的参数和局部变量往往不放在硬件栈上,而是放在固定的静态内存里(类似全局变量)。
51单片机资源有限,为了提高运行效率,C51采用静态分配局部变量的方式,所以不可递归。而标准C语言的堆栈是动态分配的。
解决方案:
给需要重复调用的函数加上reentrant关键字,使用方式如下图(编译器会改成:参数/局部变量放到专用的可重入栈上,每次调用都有自己的一份,不再共用固定地址。)
这样中断里可以安全再调这个函数。
另外递归调用也可以(8051 上很少这么干,且很吃 RAM)
最后再编译发现警告消失。
注意:使用reentrant,要另外需要在启动文件中根据内存模型打开对应栈
3.IBPSTACK / XBPSTACK / PBPSTACK分别是什么?
它们对应三种内存模型下的可重入栈指针初始化:
| 开关 | 名字含义 | 可重入栈放哪 | 典型场景 |
|---|---|---|---|
IBPSTACK | IdataBasePointer Stack | 内部 RAM(idata) | Small 模型 +reentrant |
PBPSTACK | PdataBasePointer Stack | pdata(一页 256 字节外存) | Compact 模型 +reentrant |
XBPSTACK | XdataBasePointer Stack | xdata(外部 RAM) | Large 模型 +reentrant |
建议:什么时候才需要reentrant?
典型需求:
- 中断服务程序里要调用某个也会在主循环调用的函数,且该函数有局部变量/参数
- 需要递归
- 某些第三方库明确要求
reentrant,并说明要开哪一种栈
更常见、更稳妥的做法:
- 同个函数再复制一份(功能完全一样,但函数名不一样)
- 中断里只置标志、收数据
- 复杂处理放到主循环
- 这样就不需要
reentrant
参考文章:
1、C51的再入函数 reentrant RECURSIVE CALL TO SEGMENT
2、51单片机与递归的问题
编程学习
技术分享
实战经验