模組劃分
模組劃分的"劃"是規劃的意思,意指怎樣合理的將一個很大的軟體劃分為一系列功能獨立的部分合作完成系統的需求。C語言作為一種結構化的程式設計語言,在模組的劃分上主要依據功能(依功能進行劃分在物件導向設計中成為一個錯誤,牛頓定律遇到了相對論),C語言模組化程式設計需理解如下概念:
(1) 模組即是一個.c檔案和一個.h檔案的結合,標頭檔(.h)中是對於該模組介面的聲明;
(2) 某模組提供給其它模組調用的外部函數及資料需在.h中檔案中冠以extern關鍵字聲明;
(3) 模組內的函數和全域變數需在.c檔案開頭冠以static關鍵字聲明;
(4) 永遠不要在.h檔案中定義變數!定義變數和聲明變數的區別在於定義會產生記憶體配置的操作,是彙編階段的概念;而聲明則只是告訴包含該聲明的模組在串連階段從其它模組尋找外部函數和變數。如:
/*module1.h*/ int a = 5; /* 在模組1的.h檔案中定義int a *//*module1 .c*/ #include "module1.h" /* 在模組1中包含模組1的.h檔案 */ /*module2 .c*/ #include "module1.h" /* 在模組2中包含模組1的.h檔案 */ /*module3 .c*/ #include "module1.h" /* 在模組3中包含模組1的.h檔案 */ |
以上程式的結果是在模組1、2、3中都定義了整型變數a,a在不同的模組中對應不同的地址單元,這個世界上從來不需要這樣的程式。正確的做法是:
/*module1.h*/ extern int a; /* 在模組1的.h檔案中聲明int a *//*module1 .c*/ #include "module1.h" /* 在模組1中包含模組1的.h檔案 */ int a = 5; /* 在模組1的.c檔案中定義int a */ /*module2 .c*/ #include "module1.h" /* 在模組2中包含模組1的.h檔案 */ /*module3 .c*/ #include "module1.h" /* 在模組3中包含模組1的.h檔案 */ |
這樣如果模組1、2、3操作a的話,對應的是同一片記憶體單元。
一個嵌入式系統通常包括兩類別模組:
(1)硬體驅動模組,一種特定硬體對應一個模組;
(2)軟體功能模組,其模組的劃分應滿足低偶合、高內聚的要求。
多任務還是單任務
所謂"單任務系統"是指該系統不能支援多任務並行作業,宏觀串列地執行一個任務。而多任務系統則可以宏觀並行(微觀上可能串列)地"同時"執行多個任務。
多任務的並發執行通常依賴於一個多任務作業系統(OS),多任務OS的核心是系統調度器,它使用任務控制塊(TCB)來管理工作調度功能。TCB包括任務的目前狀態、優先順序、要等待的事件或資源、任務程式碼的起始地址、初始堆棧指標等資訊。調度器在任務被啟用時,要用到這些資訊。此外,TCB還被用來存放任務的"上下文"(context)。任務的上下文就是當一個執行中的任務被停止時,所要儲存的所有資訊。通常,上下文就是電腦當前的狀態,也即各個寄存器的內容。當發生任務切換時,當前啟動並執行任務的上下文被存入TCB,並將要被執行的任務的上下文從它的TCB中取出,放入各個寄存器中。
嵌入式多任務OS的典型例子有Vxworks、ucLinux等。嵌入式OS並非遙不可及的神壇之物,我們可以用不到1000行代碼實現一個針對80186處理器的功能最簡單的OS核心,作者正準備進行此項工作,希望能將心得貢獻給大家。
究竟選擇多任務還是單任務方式,依賴於軟體的體系是否龐大。例如,絕大多數手機程式都是多任務的,但也有一些小靈通的協議棧是單任務的,沒有作業系統,它們的主程式輪流調用各個軟體模組的處理常式,類比多任務環境。