一、背景:
自從接觸單片機編程以來,由於工作上的需要,不可避免的時常會接手別人的代碼,但常常由於上一位同事的編碼隨意性有點大,導致可讀性非常的差,有時候不得不完全捨棄原有代碼,推倒重來,無形中增加了工作量,浪費了寶貴的開發時間。因而也越來越覺著規范的代碼才是提高工作效率的重要保證,不僅僅是為了別人,也為自己的日後維護帶來十足便利。
因此本文即挑某一個方面:下位機多個".c, .h"文件的相互包含及排版做一個記錄,提示自己,也為新加入的朋友們做個參考。
二、正文:
以我現在正在開發的電源管理項目為例,項目需求既是通過I2C與某電腦主板通信並按要求對主板的供電進行管理。上一位同事也許由於時間倉促,只使用了一個"main.c"文件來實現了部分功能,造成的後果既是刪改功能很難定位到相應位置並難以厘清相關聯函數間的關系。
此項目共有幾大模塊——主循環模塊,與主板通信的IIC/UART模塊,讀取撥碼開關/button按鍵模塊,存儲flash模塊,電池管理模塊。以及電源管理模塊。每個模塊既是一個".c,.h"文件,現在著重記錄多個".c.h"相互關聯、相互包含的解決辦法。
為了便於管理,該項目文件夾內,我分了以下幾個文件夾:"PROJ"存放工程文件,"APP"存放"main.c"、"aplication.c"文件,"BASEDRIVE"存放的"Uart.c"文件,"EXTIDRIVE"存放的是"Flash.c","DOC"存放的是"Readme"文件,對應".h"文件存放在對應文件夾。
包含頭文件時可寫絕對路徑:譬如"#include XXX/EXTIDRIVE/'Flash.h'",但過於麻煩,也可將頭文件所在的目錄設置進編譯軟件,
a)IAR的設置方法:
在工程文件名右鍵,選擇"Option"-->"C/C++complier"-->"Proprocessor"-->"Additonal Include directories"。
b)KEIL的設置方法:
“Project”-->”Option for Target XXX”-->”C/C++”-->”Include Paths”。
這樣直接寫相對路徑:"#include 'Flash.h'",頭文件也可被編譯器找到。
前期鋪墊這麼多,現在開始進入正題:“多個.c文件相互包含.h文件該做如何處理”?
在每個”.c”文件內聲明變量與函數,某些變量/函數如果會被其它”.c”文件調用,則在對應的”.h”文件extern 該變量/函數,若有文件要使用這些變量/函數,只需包含其頭文件即可。宏定義可直接在頭文件內定義。
以該電源管理項目為例:在”main.c”文件中,我會聲明一些基本上會被許多模塊使用或者更改的變量,譬如主板的狀態標志位,是開機,關機還是休眠,此狀態由撥碼開關/button,IIC/UART等模塊共同更改,所以需要在”main.h”中extern該變量/函數,然後讓所有文件包含該頭文件;”main.h”的宏定義一般也是基本上所有模塊均會使用的宏定義。又譬如”Uart.c”這個文件內,有一個標志位”uartdone_flag”,一個函數”myprintf(*string);前者不會有其它文件調用,我只在”Uart.c”文件聲明即可,但函數”myprintf(*string)”一定會被其它文件調用,所以這個函數不僅僅在”Uart.c”聲明,還需要在”Uart.h”中external出來,若有文件需要調用該函數,只需包含”Uart.h”即可。
再來說說為何不直接在頭文件內聲明,而是需要extern關鍵詞,若是直接在頭文件內聲明,兩個”.c”文件同時包含該頭文件,在編譯時會出現重復定義的錯誤,加了”#ifndef”之類的條件編譯也沒有效果,所以為了避免該錯誤的發生,我使用了extern的關鍵詞。至於為什麼,還得待有時間去深究編譯器原理。
以下為實際效果對比圖:
記錄地點:深圳WZ
記錄時間:2016年5月6日