|
14.3頭文件 在前邊的章節中,多次使用過文件包含命令#include,這條指令的功能是將指定的被包含文件的全部內容插到該命令行的位置處,從而把指定文件和當前的源程序文件連成一個源文件參與編譯,通常的寫法有以下兩種如下: #include <文件名> #include “文件名” 使用尖括號表示預處理程序直接到系統指定的“包含文件目錄”去查找,使用雙引號則表示預處理程序首先在當前文件所在的文件目錄中查找被包含的文件,如果沒有找到才會再到系統的“包含文件目錄”去查找。一般情況下的習慣是系統提供的頭文件用尖括號方式,用戶自己編寫的頭文件用雙引號方式。 在前邊用過很多次#include <reg52.h>,這個文件所在的位置是Keil軟件安裝目錄的\C51\INC這個路徑內。在這個文件夾內,有很多系統自帶的頭文件,當然也包含了<intrins.h>這個頭文件。當一旦寫了#include <reg52.h>這條指令后,那么相當于在當前的.c文件中,寫下了以下的代碼。 #ifndef __REG52_H__ #define __REG52_H__ /* BYTE Registers */ sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0xA0; sfr P3 = 0xB0; ... ... /* BIT Registers */ /* PSW */ sbit CY = PSW^7; sbit AC = PSW^6; sbit F0 = PSW^5; sbit RS1 = PSW^4; sbit RS0 = PSW^3; sbit OV = PSW^2; sbit P = PSW^0; //8052 only /* TCON */ sbit TF1 = TCON^7; sbit TR1 = TCON^6; sbit TF0 = TCON^5; sbit TR0 = TCON^4; sbit IE1 = TCON^3; sbit IT1 = TCON^2; sbit IE0 = TCON^1; sbit IT0 = TCON^0; ... ... #endif 之前在程序中,只要寫了#include <reg52.h>這條語句,就可以隨便使用P0、TCON、TMOD這些寄存器和TR0、TR1、TI、RI等這些寄存器的位,都是因為已經在這個頭文件中定義或聲明過了。 Keil做了很多函數,生成了庫文件,如果要使用這些函數的時候,不需要再去寫這些函數的代碼,而直接調用這些函數即可,只是調用之前首先要進行聲明,而這些聲明也放在頭文件當中。比如所用的_nop_();函數,就是在<intrins.h>這個頭文件中的。 同樣的,用戶很多程序文件中的所要用到的函數,是在其它文件中定義的,在當前文件中要調用它們的時候,也需要提前進行外部聲明。為了使程序的易維護性和可移植性提高,通常用戶會自己編寫所需要的頭文件。用戶編寫的頭文件中不僅僅可以進行函數的外部聲明和變量的外部聲明,一些宏定義也可以放在其中。 舉個例子,比如在寫main.c這個文件時,配套寫一個main.h文件。新建頭文件的方式也很簡單,和.c是類似的,首先點擊新建文件的那個圖標,或者點擊菜單File->New,然后點擊保存文件,保存的時候命名為main.h即可。為了方便編寫和修改維護,在Keil編程環境中新建一個頭文件組,把所有的源文件放在一個組內,把所有的頭文件放在一個組內,如圖14-1所示。 圖14-1 工程文件分組管理 main.h里包含了main.c所要使用的一些宏,還有對main.c內的自定義類型、全局變量、全局函數等需要提供給其他.c文件使用的內容,進行外部聲明。比如把main.h文件寫成下邊這樣。 /* 溫度相關參數,溫度數值左移4位是為與DS18B20數據格式保持一致 */ #define ACT_TEMP_ADDR 0x30 //繼電器動作溫度的E2存儲地址 #define ACT_TEMP_MIN (20<<4) //繼電器動作溫度有效范圍最小值 #define ACT_TEMP_MAX (30<<4) //繼電器動作溫度有效范圍最大值 #define ACT_TEMP_DEFAULT (25<<4) //繼電器動作溫度默認值 #define ALARM_TEMP_ADDR 0x32 //高溫報警溫度的E2存儲地址 #define ALARM_TEMP_MIN (25<<4) //高溫報警溫度有效范圍最小值 #define ALARM_TEMP_MAX (35<<4) //高溫報警溫度有效范圍最大值 #define ALARM_TEMP_DEFAULT (30<<4) //高溫報警溫度默認值 /* 全局數據類型定義 */ enum eStaSystem { //系統運行狀態枚舉 E_NORMAL, E_SET_ACT, E_SET_ALARM }; void TempControl(); void KeyAction(uint8 keycode); void ConfigTimer0(uint16 ms); 請注意,如果對函數進行外部聲明,extern是可以省略的;如果還有外部變量需要進行聲明,extern是不能省略的。為了確保程序的可靠性和可移植性,盡量不使用外部變量,不同文件之間盡量采用函數傳遞信息。 頭文件這樣編寫看似沒問題,實際上則不然。在程序編寫過程中,經常會遇到頭文件包含頭文件的用法,假設a.h包含了main.h文件,b.h文件同樣也包含了main.h文件,如果現在有一個c文件x.c,它既包含了a.h又包含了b.h,這樣就會出現頭文件main.h被x.c重復包含了,從而會發生變量函數等的重復聲明,因此還得用到C語言的另一個知識點——條件編譯。
|