technorati 標籤:
c, 預編譯,
巨集, 檔案替換,
條件編譯
由「源**」到「可執行檔案」的過程包括四個步驟:預編譯、編譯、彙編、鏈結。所以,首先就應該清楚的首要問題就是:預編譯只是對程式的文字起作用,換句話說就是,預編譯階段僅僅對源**的單詞進行變換,而不是對程式中的變數、函式等。
預編譯指令的基本知識不作詳細介紹,只稍作彙總,重點是後面的我能想到的 使用時的注意事項。
預編譯指令基本分類如下
類別指令
預定義符號
__file__、__line__、__date__、__time__、__stdc__
巨集#define
檔案包含
#include
條件編譯
#if、#elif、#else、#ifdef、#ifndef、#endif
還有一些指令,名稱和功能如下表:
指令功能
#空指令
#undef
移除乙個空定義
#error
停止編譯,並生成錯誤資訊
#line
修改__line__和__file__的值
#progma
允許編譯器提供額外功能
在定義巨集的時候,有兩個運算子:
運算子功能
#將巨集引數轉換為字串
##將多個符號連線成乙個識別符號
1. 一般在巨集定義的結尾不加分號。
我們在使用的時候,要加上分號,像我們平時寫語句一樣。
2. 注意加括號。
在有引數的空定義中,如果含有數值運算,那麼就要在「巨集整體」和「巨集引數」兩端都要加上括號。
如:#define max(a, b) ((a)+(b));
3. 注意空格。
在有引數的巨集定義中,注意「巨集名稱」和「引數列表」之間不能有空格。
如:#define max (a, b) ((a)+(b)); 在"max」和」(a, b)」之間不能有空格。
4. 不要使用有***的引數區呼叫巨集。
常見的有***的引數有:a++,getchar()等。
如:巨集定義為#define max (a, b) ((a)+(b)); 那麼使用max(i++, j++)呼叫該巨集,會造成 i 或 j 中的乙個值增加2,而不是我們期望的 1。
5. 可以使用編譯器選項 新增巨集 和 移除巨集。
我使用的是gcc,新增巨集的指令是」-d」,移除巨集的指令是」-u」。
6. 巨集引數替換的時候,不會替換字串中的字元。
即不會替換雙引號之間的字元,其他的都會被替換,包括單引號之間的。
7. 可以使用#將巨集引數的值轉化為字串。
直接使用#,是將巨集引數的名稱轉化為字串。利用下面的技巧(增加乙個過渡巨集),可以將「巨集引數的值」轉化為字串(當巨集引數有值時,這時的巨集引數常常也是乙個巨集)。
#include #include #define number ten /* 巨集名稱為number,巨集的值為ten */
#define str(x) #x
#define xstr(x) str(x) /* 增加的乙個 過渡巨集 */
int main()
輸出結果為:
str(number) == number
xstr(number) == ten
8. 使用##運算子來實現識別符號連線。
不過,不建議使用操作符##來連線識別符號,因為這個容易是程式可讀性大大降低。
1. 要將標頭檔案的定義在保護條件中。
目的是為了防止重複包含標頭檔案。如果你檢視過gcc或者其他編譯器的源**,你一定對這個非常熟悉。
例如,你要編寫乙個標頭檔案,myheader.h,那麼你的標頭檔案的內容形式應該為:(定義乙個_myheader巨集)
#ifndef _myheader
#define _myheader 1
/* 中間是你的標頭檔案內容 */
#endif /* _myheader */
2. 注意windows系統和unix系統的路徑符號不同。
可以再#include中指定路徑來包含檔案,例如 #include 「../head.h」。但是注意,windows中使用反斜線」/」作為路徑分隔符,而unix系統使用的是斜線」/」。
3. 可以使用 編譯器選項 來設定搜尋路徑。
我使用的gcc,使用的-idir選項,例如: -i"d:/dev-cpp/include"。
1. #ifdef等價於#if defined(),#ifndef等價於#if !defined()。
2. 在#if中可以使用邏輯操作符(&&、||、!)。在#ifdef 中是不可以使用的,這也是#if的優越點。
#include #include #define a 1
#define b 0
int main()
執行結果:
test logic operation in #if
3. sizeof(int)在預編譯階段是不會被求值的。
只要知道「預編譯階段」在真正的「編譯階段」之前,就很容易理解了。預編譯階段只是對組成源**中的字元進行作用,從某種意義上來說,它有時甚至不知道它的操作物件是什麼,它只是按照既定的規則執行替換。
sizeof(int),無論是sizeof的解析,還是型別的解析,都是在「編譯階段」才開始的,編譯階段知道它的操作物件是什麼。
下面的**是錯誤的
#if sizeof(int) == 2
printf("precompile sizeof(int)");
#endif
把乙個預處理指令寫成多行的形式,要使用符號」/」,並且在該符號後面應緊跟換行符。而非預處理指令的**行不需要使用該符號,直接換行即可。 原因:編譯階段會自動忽略空白符,而預編譯階段不會。
C語言的預編譯
預編譯指令基本分類如下 類別指令 預定義符號 file line date time stdc 巨集 define 檔案包含 include 條件編譯 if elif else ifdef ifndef endif 還有一些指令,名稱和功能如下表 指令功能 空指令 undef 移除乙個空定義 err...
C語言的預編譯
預處理功能主要包括巨集定義,檔案包含,條件編譯三部分。分別對應巨集定義命令,檔案包含命令,條件編譯命令三部分實現。預處理過程讀入源 檢查包含預處理指令的語句和巨集定義,並對源 進行響應的轉換。預處理過程還會刪除程式中的注釋和多餘的空白字元。預處理指令是以 號開頭的 行。號必須是該行除了任何空白字元外...
c語言中預編譯
預編譯又被稱為預處理,是做 文字的替換工作。處理 開頭的指令。就是為編譯做預備工作的準備。常見的預編譯指令有三種 1 include指令 該指令指示編輯器將 檔案的全部內容插入此處,如果使用 代表在系統指定目錄下搜尋檔案,使用 代表現在當前目錄下搜尋檔案,然後在系統預設目錄下搜尋。2 define指...