C中儲存空間、變數的使用

C中儲存空間、變數的使用

現在工作只能使用公司的電腦,不能帶手機、儲存器,而且不能上傳資料,因此有一段時間沒更新百家了。

過節這幾天又不能出去,因為新病毒的原因,所以抽個時間來聊聊C語言中的儲存空間的話題。

在C中,程式與資料的儲存是放在非易失性儲存器,例如硬碟、FLASH等,而呼叫一般是在記憶體中進行。記憶體一般又分為:堆、棧、全域性變數和常量四大塊(實際上還有程式碼區,我們這不討論),在程式執行中,不斷的對記憶體進行呼叫。為什麼分為這四塊?因為,在作為非易失性儲存的時候,這四塊在這類儲存器中是實際佔用空間的。全域性變數空間,主要包含全域性變數和靜態變數,會實際影響FLASH的佔用空間,而區域性變數和函式引數在棧中呼叫,呼叫後就清空,自然不會佔用FLASH的空間。下面試驗證明一下:

(注:這是在Eclipse上的migwin做的測試,其它編譯器或環境可能會有差異)

C中儲存空間、變數的使用

這裡我寫了一個簡單的主函式,看看生成的可執行檔案有多大?

C中儲存空間、變數的使用

可以看到佔了40786位元組

再定義一個區域性變數

C中儲存空間、變數的使用

這時候還可以看到,可執行檔案沒有變化依舊是40786位元組

C中儲存空間、變數的使用

接下來,定義一個全域性變數

C中儲存空間、變數的使用

此時可執行檔案增加了18位元組,變為40804位元組

C中儲存空間、變數的使用

再定義一個區域性靜態變數,又增加了18位元組,變成了40822位元組

C中儲存空間、變數的使用

從這裡有可能意識到,區域性靜態變數是一種全域性變數的存在,而全域性變數會佔用最終二進位制檔案的空間,使其變大,而區域性變數則不會影響最終二進位制檔案的大小(這裡沒測試函式的引數,大家有興趣可以測一下,和區域性變數一樣,是不佔用二進位制檔案的空間的)。

但區域性變數和函式引數是由棧來呼叫,因此,棧的空間大小會決定二進位制檔案的大小。下面用一個小程式來看看區域性變數和區域性靜態變數的區別:

先看看區域性變數:

C中儲存空間、變數的使用

由於返回的是區域性變數的地址,這個空間是在棧區,意味著程式執行完,這個地址內容就被收回了,第一個p肯定是沒有內容的(有些編譯器出來是亂碼,也就是隨機值)。有意思的是,第二個p重新賦了值,但打印出來依舊是沒有數值的,可能這個編譯器隨時都收回棧空間。

C中儲存空間、變數的使用

現在將a 改為靜態變數

C中儲存空間、變數的使用

可以看到,對p的操作,也就是對a進行了操作,值也沒有被回收

C中儲存空間、變數的使用

這就產生了一個對記憶體進行最佳化的問題,使用全域性變數和靜態變數可以很好地對一些共享資料進行操作,但這些變數在明顯的佔用FLASH的空間,以及記憶體的全域性變數空間,有沒有用的時候來申請,用完了就釋放的空間呢,這就是堆的作用了。

堆是給程式設計師用來手動分配和釋放的空間,這樣一些較大的共享資料就可以透過堆來操作,而堆也是一個固定的大小,用完釋放,這樣就不存在大量的全域性變數佔用儲存空間的問題,但小心的是,一但申請後如果不釋放,會有溢位的風險。現在測試一下

剛剛測試的程式已經達到41034位元組

C中儲存空間、變數的使用

接下來使用堆

C中儲存空間、變數的使用

這一次,test1只用來分配一個堆空間,然後對p來進行操作,可以看到同樣的地址和字串的變化,大小呢?變成了41192個位元組

C中儲存空間、變數的使用

還變大了?這是因為上一個程式沒有使用堆,編譯器可能沒有分配堆空間,但在MCU上操作時堆空間是已經定義好的。所以程式變大了不是重點,重點是,如果將temp再分大了會怎樣?例如這樣

C中儲存空間、變數的使用

再看可執行檔案的大小,依舊是41192個位元組

C中儲存空間、變數的使用

再看看靜態1000個數組呢?

C中儲存空間、變數的使用

已經變成了42069位元組

C中儲存空間、變數的使用

這篇文章主要是介紹一下棧、堆的使用,以及全域性變數,靜態區域性變數對空間的影響。arm和PC機的編譯環境和資源還是很不一樣,包括最佳化選項的選擇,但原理是相通的。因此,資源有限的情況下,對程式碼、變數的手動最佳化還是很有必要的,僅供閱者參考

相關文章