最近看了很多單片機STM32的的相關程序,尤其是設計到ringbuff、buffer_manage、os_memory預計mem_manage等程序中間層的用法,我對這句話有了一些更深的思考,現在記錄下來,希望對處于相同階段的程序一些思想啟迪。
首先“數據結構”也就是對一個事物用結構體類型、枚舉類型、共用體類型、數組等進行封裝描述,其中結構體類型是最常用的,例如STM32單片機中寄存器組就用一個結構體類型進行了封裝。我在這里想說的是定義相關類型,內部成員有好多個。定義好數據結構后,下一步就是要定義一個相關的真實的數據,絕大多數情況就是全局變量,也有使用malloc、free申請釋放的堆內存。最后就是操縱這個數據內部成員變量的相關函數,這就是算法,API函數,也叫接口函數。后面統稱為算法。
再講一下算法,上面我提到算法就是對結構體變量內部成員進行寫讀操作。這里就涉及到如何訪問全局結構體變量內部的成員問題,答案是“使用結構體指針變量作為函數傳參”的方式進行。我們定義接口函數的時候使用結構體指針變量來指向某個結構體變量。因為傳參的過程是壓棧(涉及到算法“=”)的過程,早期編譯器不支持直接調用結構體本身,現在的編譯器開始支持了,不過為了兼容早期程序,還是不建議直接將結構體直接賦值給函數參數,另外如果直接賦值,傳遞的是結構體成員內存格子中存儲的數值,也無法在函數內部對函數外面的結構體內部成員進行修改(又名輸出型參數)。我們在函數內部主要做的工作有:讀取外部結構體的數據,如果需要暫存,那就要定義臨時變量,也就是棧內存進行存儲。我現在的感受就是寫函數內部程序的時候如果需要獲取結構體的成員,并且暫存的話,就要定義某個臨時棧內存進行寫操作,這樣就相當于“數據的產生”(定義了某個變量并且寫入了有效數據),光寫進去還不行,我們還需要在后面的運算中去將臨時棧內存中的變量讀出來參數某些運算。這樣又產生新的變量,于是又定義新變量,又進行寫操作,又進行讀操作... ... ...然后一直進行下去,直到函數運行結束。當然這個過程不可避免的會讀結構體內部成員,以及通過指針變量的方式進行寫有效數值。宏觀上看函數運行的過程就表現為結構體內部成員變量的數值不斷地被讀,然后被寫。最后函數運行可能會有return返回值,這個返回值大部分情況代表函數體內部運行的過程,經常看到提前return返回了,這就是“衛語句的寫法”。從宏觀上看就是一句話:返回值代表函數運行的過程,參數列表存儲著運算的結果。
總結一下:定義相關類型,然后相關類型變量,最后定義API函數不斷訪問(寫/讀,生產/消費)變量本身或者變量內部成員,最后將這些封裝寫成一對頭文件.h和源文件.c。這樣就是程序的寫法。現在想想這樣寫的好處就是:調用API函數對變量進行寫有效數值,然后其他源文件可以直接訪問全局變量的內部成員,也可以訪問對應API函數進行讀操作。兩種方式都可以,在實際應用中都會大量應用。其中直接訪問變量本身或者內部成員更方便。我們根據里面存儲的數據然后加上各種邏輯判斷、利用3大程序結構,就可以知道程序現在代表的狀態,以及接下來要做什么。
整個過程,千萬別在使用全局變量上吝嗇使用,該用的時候還要用,沒有全局變量,哪來的算法。我們大部分人不是高手,所以在程序編寫過程中甚至產生了一些多余的全局變量也是不可避免的,重點是要實現要完成的功能。我再很長時間內都在摸索如何少用全局變量,現在想想真實有點貪心不足蛇吞象了,這個一定要切記。而且,現在51單片機、STM32單片機以及更高級的能跑linux內核的芯片內部有足夠多的內存空間,所以平時寫代碼,真不用節省著來。可能隨著編寫能力的提升,可能會考慮節約使用全局變量以及隔離、分層思想,不能跨層訪問等等,但是現階段我暫時不會再考慮這樣做了。