【发布时间】:2017-01-03 09:52:48
【问题描述】:
我有一个具有以下实现的函数:
void func (uint8 index, uint8 status)
{
if (status == 1)
{
myArrayOfStructures[index].status = 1;
}
else if (status == 0)
{
myArrayOfStructures[index].status = 0;
}
else
{
/* Nothing */
}
}
注意:myArrayOfStructures 是文件上的全局变量。
我认为这个函数是可重入的,只要它的参数的传递是通过堆栈完成的,因为以下分析:
函数的 2 个参数在函数调用时被压入堆栈。 如果函数本身被另一个 OS 任务中断,则第二次将参数压入堆栈。 因此,该函数的 2 个实例是“独立的”,因为每个实例在堆栈中都有自己的一组参数。
直到,我使用某个编译器选项优化了这个文件的速度。
经过优化,我发现那些参数的传递是通过寄存器完成的(我知道编译器有权做这种事情(寄存器分配))。但是这个优化使得这个函数是不可重入的。
所以,我的问题是
- 上面的函数真的是可重入的吗?
- 如果是(可重入),编译器如何进行这样的优化以恢复其重入状态?
请参考我的答案。
非常感谢。
【问题讨论】:
-
通过寄存器或堆栈传递根本不相关 - 每个操作系统任务都有自己的一组寄存器(每个内核都有自己的寄存器,操作系统会根据需要小心保存和恢复它们切换到另一个任务/处理同一内核上的中断时)。
-
旁注,但功能可以简化为简单的
myArrayOfStructures[index].status = !!status;。遵守C非零约定意味着正确。你甚至可以通过使用来自stdbool.h的bool来进行更多的自我记录 -
@StoryTeller:不完全; status=2 表示“不要触摸;保持原样。”
-
@SF。 - 是的,在 OP 的原始帖子中。我的建议是增强。不要成为 254 个值的 NO OP,而是使函数符合 C 语言习惯。
-
@joop 这个元素的写操作是原子的。我检查了编译器生成的对应汇编代码(.lst文件)。
标签: c compiler-optimization reentrancy register-allocation