我想將一些值保存到EEPROM,還想通過避免一些變量聲明來釋放SRAM,但是EEPROM存儲器是按字節的。
如果我想存儲一個int值,我有重複使用一些表達式。我以為我會為它們做一些功能。但是我擔心,如果創建一個函數,它仍然會佔用SRAM內存,最好是聲明一個int變量而不是使用EEPROM。
函數和局部變量如何存儲在SRAM中?它是僅存儲閃存中功能指針的地址還是所有變量和命令都存儲在堆棧中?
我想將一些值保存到EEPROM,還想通過避免一些變量聲明來釋放SRAM,但是EEPROM存儲器是按字節的。
如果我想存儲一個int值,我有重複使用一些表達式。我以為我會為它們做一些功能。但是我擔心,如果創建一個函數,它仍然會佔用SRAM內存,最好是聲明一個int變量而不是使用EEPROM。
函數和局部變量如何存儲在SRAM中?它是僅存儲閃存中功能指針的地址還是所有變量和命令都存儲在堆棧中?
局部變量和函數參數存儲在堆棧中。但是,這不是不使用它們的原因。計算機是按這種方式工作的。
僅在功能啟用時才使用堆棧內存。函數返回後,將立即釋放內存。堆棧存儲器是一件好事。
您不想使用具有很多遞歸級別的遞歸函數,也不想在堆棧上分配很多大型結構。但是,正常使用是可以的。
6502堆棧只有256個字節,但是Apple II可以正常工作。
AVR(傳統上在Arduino板上使用的微控制器系列)是哈佛架構,這意味著可執行代碼和變量位於兩個單獨的存儲器中,在本例中為閃存和SRAM。可執行代碼永遠不會離開閃存。
調用函數時,返回地址通常被壓入堆棧-例外是函數調用發生在調用函數的末尾。在這種情況下,將改為使用調用調用函數的函數的返回地址-它已在堆棧中。
是否將其他任何數據放在堆棧中取決於調用函數和寄存器中的寄存器壓力。稱為函數。寄存器是CPU的工作區域,AVR具有32個1字節寄存器。可以通過CPU指令直接訪問寄存器,而SRAM中的數據首先必須存儲在寄存器中。僅當參數或局部變量太大或太多而無法容納在寄存器中時,它們才會被放入堆棧中。但是,結構始終存儲在堆棧中。
您可以在以下位置閱讀有關AVR平台上GCC編譯器如何使用堆棧的詳細信息: https://gcc.gnu.org / wiki / avr-gcc#Frame_Layout
閱讀“框架佈局”和“呼叫約定”部分。
僅函數的數據存儲在堆棧中;它的代碼保留在閃存中。您不能真正通過使用EEPROM來減少SRAM的使用,因為如您所見,EEPROM不能以相同的方式尋址。讀取和存儲EEPROM的代碼還需要使用一些SRAM-可能與您要保存的SRAM一樣多! EEPROM的寫入速度也很慢,並且具有有限的生命週期(每個字節的寫入次數),這兩者都使得存儲通常放在堆棧中的臨時數據種類不切實際。它更適合保存不經常更改的數據,例如用於批量生產設備的獨特設備配置,或捕獲不頻繁的錯誤以供以後分析。
已編輯:該函數直到該函數已被調用,所以是的,那就是當該函數的任何數據放入該函數時。函數返回後發生的事情是不再保留其堆棧幀(其SRAM的保留區域)。最終它將被另一個函數調用重新使用。 這是內存中C堆棧的圖。當堆棧框架不再有用時,只需釋放它,並使其內存可重複使用即可。
在函數調用進入函數後,立即執行的第一個代碼將堆棧指針遞減等於該函數內部臨時變量所需空間的數量。妙處在於,所有函數因此成為可重入和遞歸的,因為它們的變量是建立在調用程序的堆棧上的,這意味著如果中斷中止一個程序的執行並將其轉移給另一個程序,它也可以調用同一程序功能,而不會彼此干擾。
我一直在努力嘗試編寫一些示例代碼,以演示此處的出色答案所講的內容,但到目前為止沒有成功。原因是編譯器積極地優化了東西。到目前為止,即使在函數中使用局部變量,我的測試也根本沒有使用堆棧。原因是:
編譯器可能會內聯函數調用,因此返回地址可能根本不會被壓入堆棧。示例:
void foo(字節a){digitalWrite(13,a); } void loop(){foo(5); }
編譯器將其轉換為:
無效循環(){digitalWrite(13,5); }
不調用函數,不使用堆棧。
編譯器可能在其中傳遞參數註冊,因此省去了將它們壓入堆棧的麻煩。示例:
digitalWrite(13,1);
編譯為:
158:8d e0 ldi r24, 0x0D; 1315a:61 e0 ldi r22,0x01; 115c:0e 94 05 01呼叫0x20a; 0x20a <digitalWrite>
參數被放入寄存器中,因此不使用堆棧(除了用於調用digitalWrite的返回地址)。
編譯器會優化掉不需要的變量。示例:
void foo(字節a){無符號長條[100]; bar [1] = a; digitalWrite(9,條[1]); } void loop(){foo(3); } //循環結束
現在,得到了,可以為“ bar”分配400個字節,不是嗎?不:
00000100 <_Z3fooh>:100:68 2f mov r22,r24 102:89 e0 ldi r24,0x09; 9104:0e 94 cd 00呼叫0x19a; 0x19a <digitalWrite> 108:08 95 ret
0000010a <loop>:10a:83 e0 ldi r24,0x03; 3 10c:0e 94 80 00呼叫0x100; 0x100 <_Z3fooh> 110:08 95 ret
編譯器優化了整個數組!它可以表明我們實際上只是在執行 digitalWrite(9,3)
,這就是它生成的內容。
故事:不要試圖超越編譯器。