在51单片机上使用递归的注意事项
目錄
- 問題
- 應對措施
- 原理
普中51-單核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
問題
???????在Keil C51中直接使用遞歸會報如下警告:
???????recursive call to non-reentrant function
???????為了提高運行效率,C51采用靜態(tài)分配局部變量的方式,所以一般情況下不可遞歸。
被中斷和非中斷函數(shù)調(diào)用的函數(shù),如果在非中斷狀態(tài)運行,發(fā)生中斷后,局部變量被破壞,中斷結束后再執(zhí)行就完全錯誤了,這個跟不能遞歸的原理是一樣的。
如對數(shù)組arr[10] = { 7,1,3,9,2,6,1,7,3,5 }進行快速排序
得到的數(shù)據(jù)可能會出錯
應對措施
加上reentrant關鍵字后,輸出結果正確。
typedef int QuickSortType; void QuickSort(QuickSortType v[], int left, int right) reentrant {int i, pos;QuickSortType temp;if (left >= right)return;//取第一個元素為錨定點pos = left;//遍歷數(shù)組,將小于錨定點的數(shù)swap到數(shù)組前部for (i = left + 1; i <= right; ++i) {if (v[i] < v[left]){ ++pos;temp = v[i];v[i] = v[pos];v[pos] = temp;}}//將錨定點的數(shù)與swap至其正確位置pos;temp = v[left];v[left] = v[pos];v[pos] = temp;//遞歸該過程QuickSort(v, left, pos - 1);QuickSort(v, pos + 1, right); }
但reentrant后也不能隨意使用遞歸:
由于51稀缺的資源,當數(shù)組長度達到46后也出現(xiàn)了錯誤,因此在51上盡量不要使用遞歸
原理
本節(jié)摘自Keil C51對C語言的關鍵詞擴展之十五: reentrant —— 昵稱90天可改
這篇博文寫的很詳細模擬堆棧,可重入函數(shù)調(diào)用,參數(shù)傳遞 —— hplog
???????reentrant聲明的函數(shù)為可重入函數(shù)。可重入的函數(shù)能夠被多個進程同時調(diào)用??芍厝牒瘮?shù)在執(zhí)行時,另外的進程可以中斷當前執(zhí)行的函數(shù),并且調(diào)用同一個函數(shù)。正常情況下,C51程序中的函數(shù)不能被遞歸地調(diào)用,這是由于函數(shù)的參數(shù)和局部變量都被保存在固定的地址,在遞歸調(diào)用時操作了相同存儲位置,導致數(shù)據(jù)被覆蓋。
???????使用reentrant聲明函數(shù)為可遞歸調(diào)用的可重入函數(shù):
int calc (char i, int b) reentrant {int x;x = table [i];return (x * b); }???????可重入函數(shù),能夠被遞歸調(diào)用,也能被兩個以上的進程同時調(diào)用??芍厝牒瘮?shù)通常在實時應用或者中斷與非中斷程序共享相同函數(shù)這兩種情況下被使用。
每個可重入函數(shù)都有一個位于內(nèi)部ram或外部ram的模擬堆棧:
SMALL內(nèi)存模型下,可重入函數(shù)模擬堆棧位于idata區(qū);
COMPACT內(nèi)存模型下,可重入函數(shù)模擬堆棧位于pdata區(qū);
LARGE內(nèi)存模型下,可重入函數(shù)模擬堆棧位于xdata區(qū);
使用reentrant聲明可重入函數(shù)須遵循的規(guī)則:
可重入函數(shù)不支持位尋址變量,比如bit類型的參數(shù);
可重入函數(shù)不能被alien函數(shù)調(diào)用;
可重入函數(shù)不能被聲明為alien屬性(alien用于使能PL/M-51參數(shù)傳遞約定);
可重入函數(shù)可以同時擁有其他屬性,比如using、interrupt、small、compact、large;
返回地址被保存在硬件堆棧中;
使用不同存儲模型的可重入函數(shù)能夠混合,但是各自函數(shù)聲明時必須指定存儲模型;
三種內(nèi)存模型的可重入函數(shù)都有自己的對戰(zhàn)區(qū)和棧指針。比如在相同模塊中,定義了small和large類型的可重入函數(shù),則small和large類型的堆棧及其堆棧指針都被創(chuàng)建;
???????可重入堆棧模擬體系,效率比較低下,但是由于8051自身缺乏適當尋址方法的硬件特性,所以推出這種堆棧模擬體系來滿足我們的可重入需求,在應用中 ,我們應該盡量不用或少用可重入函數(shù)。
???????可重入函數(shù)使用的模擬堆棧擁有獨立于8051硬件堆棧的棧指針。堆棧和堆棧指針在STARTUP.A51文件中被定義和初始化。
???????8051硬件堆棧向上增長,堆棧指針先加再壓棧,可重入模擬堆棧正好相反,其指針先減再壓棧。
???????STARTUP.A51啟動代碼聲明并初始化了模擬堆棧及其堆棧指針,如果使用可???????重入函數(shù)就必須修改啟動代碼指出哪個模擬堆棧須要初始化??梢栽趩哟a中修改模擬堆棧的起始地址。
???????可重入函數(shù)的參數(shù)傳遞,通過模擬堆棧的壓棧、出棧完成。
???????可重入函數(shù)的局部變量,也保存在模擬堆棧中,通過模擬堆棧指針訪問。
總結
以上是生活随笔為你收集整理的在51单片机上使用递归的注意事项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI(Adobe illustrator
- 下一篇: 从函数中返回多个值的方法