Chinaunix首页 | 论坛 | 博客

分类: LINUX

2013-01-03 15:21:21

相关资料转载自:http://blog.chinaunix.net/uid-23787789-id-2385369.html
    在 PC、ARM 环境下,函数重入的问题一般不是要特别注意的问题。只要你没有使用 static 变量,或者指向 static 变量的指针,一般情况下,函数自然而然地就是可重入的。
    但 C51 不一样,如果你不特别设计你的函数,它就是不可重入的。引起这个差别的原因在于:一般的 C 编译器(或者更确切点地说:基于一般的处理器上的 C 编译器),其函数的局部变量是存放于堆栈中的,而 C51 是存放于一个可覆盖的(数据)段中的。
    至于 C51 这样做的原因,不是像有些人说的那样,为了节约内存。事实上,这样做根本节约不了内存。理由如下:
    1) 如果一个函数 func1() 调用另一个函数 func2(),那么 func1() 和 func2() 的局部变量根本就不能是同一块内存。C51 还是要为他们分配不同的RAM。这跟使用堆栈相比,节约不了内存。
    2) 如果 func1() 和 func2() 不是在一个调用链上,那么 C51 可以通过覆盖分析,让它们的局部变量共享相同的内存地址。但这样也不会比使用堆栈节约内存。因为既然它们是在不同的调用链上,那么当其中一个函数运行时,那么另外一个函数必然不在其生命期内,它所占用的堆栈也已释放,归还给系统。
    真实的原因(C51 使用覆盖段作为局部变量的存放地的原因)是:
    51 的指令系统没有一个有效的相对寻址(变址寻址)的指令,这使得使用堆栈作为变量的代价太过昂贵。
    使用堆栈存放变量的一般做法是:
    进入函数时,保留一段堆栈空间,作为变量的存放空间,用一个可作为基址寻址的寄存器指向这个空间,通过加上一个偏移量,就可以访问不同的变量了。
    例如: MOV EAX, [EBP + 14] ;X86指令
    LDR R0, [R12, #14] ;ARM指令
    都可以很好的解决这个问题。
    但51缺少这样的指令。
    其实,51 中还是有 2 个可变址寻址的指令的,但不适合访问堆栈的局部变量这样的场合。
    MOVC A, @A+DPTR
    MOVC A, @A+PC
    所以,C51有个特别的关键字:reentrant 用来解决函数重入的问题。

                       ——忠于梦想 勇于实践    linux_xpj@opencores.org

阅读(2027) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~