當前位置:才華齋>計算機>C語言>

有趣的C語言預處理

C語言 閱讀(5.55K)

#define和#include是最常用的預處理,微控制器程式不用其他預處理也完全可行。所以初學者並不深究預處理的應用。下面是有趣C語言預處理,歡迎閱讀了解。

有趣的C語言預處理

  分類解釋

在編譯器編譯之前,會首先搜尋預處理指令,按照指令完成編譯,預處理又分為:檔案包含、條件編譯、佈局控制(雜注)和巨集替換。

  檔案包含:

#include""和#include<>,前者是和該c檔案相同目錄下的.h,如 #include "os_cfg.h" ,或指明路徑的.h,如 #include "softwareucos-iisourceucos_ii.h" ;

後者是編譯器系統路徑中的.h,一般C語言標準庫函式在編譯器裡整合,如 #include 。

只要包含了.h,而.h裡有函式宣告(或變數、結構體例項),那麼不論這個函式(變數、結構體例項)在那個.c檔案裡定義的,都可以在主C檔案中使用。

對於函式,可以按功能分類成各種模組,集合在一起寫成一個.c檔案,然後作同名的.h給出函式宣告,如果模組太多,也可以再用一個.h來包含各模組的.h,uCOS-II中的includes.h就是這樣。

對於變數,C模組中的全域性變數只對該模組有效,如果想要被其他C檔案訪問,就得在.h裡宣告,如果主C包含了這個.h,那麼此變數就成了真正全域性的了。

對於結構體例項,其結構的定義可以放在.h裡,(如果不需要到處定義很多例項放在c裡也可以),例項定義在c裡,而宣告放在.h裡,這樣就到處可用此例項了。

#include 的物件直接被 插入到了該位置,所以可能出現#include重複甚至巢狀,用#ifndef...#define...程式碼...#endif的方法可以保證重複包含的.h那個只在第一次出現時編譯.

  條件編譯:

上面的#ifndef就是條件編譯的一種。條件編譯主要用於跳過某些程式碼不編譯,這樣可以用來寫一個C檔案,但是適應不同硬體版本,或者可採用不同演算法。我就經常用多種演算法寫同一個功能,#define method 1,#if methof==1...#endif, #if method ==2...#endif

Protothread的神奇功能就是用巨集和條件編譯來實現的。舉個例子:

#define LC_INIT(s) s = 0;

#define LC_RESUME(s) switch(s) { case 0:

#define LC_SET(s) s = __LINE__; case __LINE__:

#define LC_END(s) }

#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)

每個執行緒執行一次 PT_BEGIN(pt),這樣就建立了一個switch,一開始 pt->lc=0, PT_BEGIN(pt)之後繼續執行語句(本protothread的語句,一般是while(1)),執行到PT_WAIT_UNTIL(pt, condition)之類會呼叫LC_SET((pt)->lc);然後return,於是pt->lc記錄了行號,建立了case:,下次進到執行緒之直接走 LC_RESUME(s)裡的switch到上次的位置

  佈局控制/雜注:

主要是#pragma,從實用的`角度講,就是編譯器為了簡化使用者操作,給使用者提供了一些命令,不同編譯器是不一樣的,比如,IAR EW430就可以直接定義中斷函式而不用管中斷向量表在哪兒。(比如ARM7就要編譯前手動改程式段的中斷向量表,DSPF2812就要用程式指令改資料段的中斷向量表,而51則由keil自動放置中斷跳轉指令。)

#pragma vector=PORT1_VECTOR

__interrupt void Port_1(void)

{

//code

}

編譯器會自動給中斷函式指定中斷向量。

  巨集替換:

巨集函式其實可以巧妙的代替函式,尤其是很短又沒有區域性變數的一些語句,還可以代換很多複雜的格式,如

#define F "%6.2f"

#define F3 F " " F " " F""

用函式printf(F3,a,b,c),可以同時指定a,b,c 的格式

  其他:

預定義識別符號

為了處理一些有用的資訊,預處理定義了一些預處理識別符號,雖然各種編譯器的預處理識別符號不盡相同,但是他們都會處理下面的4種:

__FILE__ 正在編譯的檔案的名字

__LINE__ 正在編譯的檔案的行號

__DATE__ 編譯時刻的日期字串,例如: "25 Dec 2000"

__TIME__ 編譯時刻的時間字串,例如: "12:30:55"