C语言——预编译
C語言——預編譯
宗旨:技術的學習是有限的,分享的精神是無限的。
? ? ? ? 在C 語言中,并沒有任何內在的機制來完成如下一些功能:在編譯時包含其他源文件、定義宏、根據條件決定編譯時是否包含某些代碼。要完成這些工作,就需要使用預處理程序。盡管在目前絕大多數編譯器都包含了預處理程序,但通常認為它們是獨立于編譯器的。預處理過程讀入源代碼,檢查包含預處理指令的語句和宏定義,并對源代碼進行響應的轉換。預處理過程還會刪除程序中的注釋和多余的空白字符。
?????? 預處理指令是以#號開頭的代碼行。#號必須是該行除了任何空白字符外的第一個字符。#后是指令關鍵字,在關鍵字和#號之間允許存在任意個數的空白字符。整行語句構成了一條預處理指令,該指令將在編譯器進行編譯之前對源代碼做某些轉換。下面是部分預處理指令:
??????????指令??????????????用途
??????????#??????????????????空指令,無任何效果
?????????#include??????包含一個源代碼文件
?????????#define????????定義宏
?????????#undef?????????取消已定義的宏
?????????#if???????????????如果給定條件為真,則編譯下面代碼
?????????#ifdef??????????如果宏已經定義,則編譯下面代碼
?????????#ifndef????????如果宏沒有定義,則編譯下面代碼
?????????#elif?????? ??如果前面的#if給定條件不為真,當前條件為真,則編譯下面代碼
?????????#endif?????????結束一個#if……#else條件編譯塊
?????????#error????????停止編譯并顯示錯誤信息
??一、文件包含
????????#include預處理指令的作用是在指令處展開被包含的文件。包含可以是多重的,也就是說一個被包含的文件中還可以包含其他文件。標準C編譯器至少支持八重嵌套包含。
????????預處理過程不檢查在轉換單元中是否已經包含了某個文件并阻止對它的多次包含。這樣就可以在多次包含同一個頭文件時,通過給定編譯時的條件來達到不同的效果。例如:
????????#defineAAA
????????#include "t.c"
????????#undef AAA
????????#include "t.c"
????????為了避免那些只能包含一次的頭文件被多次包含,可以在頭文件中用編譯時條件來進行控制。例如:???????
????????#ifndef_OS_H_
????????#define _OS_H_
??????????……
????????#endif /* _OS_H_ */
????????在程序中包含頭文件有兩種格式:
????????#include
????????#include "os.h"
?????????第一種方法是用尖括號把頭文件括起來。這種格式告訴預處理程序在編譯器自帶的或外部庫的頭文件中搜索被包含的頭文件。第二種方法是用雙引號把頭文件括起來。這種格式告訴預處理程序在當前被編譯的應用程序的源代碼文件中搜索被包含的頭文件,如果找不到,再搜索編譯器自帶的頭文件。
二、宏
????????宏定義了一個代表特定內容的標識符。預處理過程會把源代碼中出現的宏標識符替換成宏定義時的值。宏最常見的用法是定義代表某個值的全局符號。宏的第二種用法是定義帶參數的宏,這樣的宏可以象函數一樣被調用,但它是在調用語句處展開宏,并用調用時的實際參數來代替定義中的形式參數。
?1.#define指令
????????#define預處理指令是用來定義宏的。該指令最簡單的格式是:首先神明一個標識符,然后給出這個標識符代表的代碼。在后面的源代碼中,就用這些代碼來替代該標識符。
宏表示的值可以是一個常量表達式,其中允許包括前面已經定義的宏標識符。例如:
???????#define ONE 1
???????#define TWO 2
???????#define THREE (ONE+TWO)
????????注意上面的宏定義使用了括號。盡管它們并不是必須的。但出于謹慎考慮,還是應該加上括號的。
?
2.#運算符
????????出現在宏定義中的#運算符把跟在其后的參數轉換成一個字符串。有時把這種用法的#稱為字符串化運算符。例如:
? ? ? ? 宏定義中的#運算符告訴預處理程序,把源代碼中任何傳遞給該宏的參數轉換成一個字符串。所以輸出應該是adhfkj15。
3.##運算符
????????##運算符用于把參數連接到一起。預處理程序把出現在##兩側的參數合并成一個符號。看下面的例子:
?
三、條件編譯指令
????條件編譯指令將決定那些代碼被編譯,而哪些是不被編譯的。可以根據表達式的值或者某個特定的宏是否被定義來確定編譯條件。
1.#if指令
????????#if指令檢測跟在制造另關鍵字后的常量表達式。如果表達式為真,則編譯后面的代碼,知道出現#else、#elif或#endif為止;否則就不編譯。
????????如果要屏蔽一段代碼,建議使用 [ #if 0?... ?#endif ]
2.#endif指令
????????#endif用于終止#if預處理指令。
? ? ? ? 由于程序定義DEBUG宏代表0,所以#if條件為假,不編譯后面的代碼直到#endif,所以程序直接輸出Running。
????????如果去掉#define語句,效果是一樣的。
?
3.#ifdef和#ifndef
#define DEBUGint main(void) { #ifdef DEBUGprintf("yes\n"); #endif #ifndef DEBUGprintf("no\n"); #endifreturn 0; }
? ? ? ? #if defined等價于#ifdef; #if !defined等價于#ifndef
4.#else指令
????????#else指令用于某個#if指令之后,當前面的#if指令的條件不為真時,就編譯#else后面的代碼。#endif指令將中指上面的條件塊。
5.#elif指令
????????#elif預處理指令綜合了#else和#if指令的作用。
? ? ? ? 程序很好理解,最后輸出結果是2。
?6.其他一些標準指令
????????#error指令將使編譯器顯示一條錯誤信息,然后停止編譯。
????????#line指令可以改變編譯器用來指出警告和錯誤信息的文件號和行號。
????????#pragma指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某些煩人的警告信息。
總結
- 上一篇: 状态机——protothreads
- 下一篇: FFT FNT 简要整理