C語言的預編譯

 

1. 基本內容

預編譯指令基本分類如下

類別

指令

預定義符號 __FILE__、__LINE__、__DATE__、__TIME__、__STDC__
#define
文件包含 #include
條件編譯 #if、#elif、#else、#ifdef、#ifndef、#endif

還有一些指令,名稱和功能如下表:

指令 功能
# 空指令
#undef 移除一個空定義
#error 停止編譯,並生成錯誤信息
#line 修改__LINE__和__FILE__的值
#progma 允許編譯器提供額外功能

在定義宏的時候,有兩個運算符

運算符 功能
# 將宏參數轉換爲字符串
## 將多個符號連接成一個標識符

2. 宏定義

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 <stdio.h> #include <stdlib.h> #define NUMBER ten /* 宏名稱爲NUMBER,宏的值爲ten */ #define Str(x) #x #define XStr(x) Str(x) /* 增加的一個 過渡宏 */ int main(){ printf("Str(NUMBER) == %s /n", Str(NUMBER)); printf("XStr(NUMBER) == %s /n", XStr(NUMBER)); system("pause"); return EXIT_SUCCESS; }

輸出結果爲:

Str(NUMBER) == NUMBER XStr(NUMBER) == ten

8. 使用##運算符來實現標識符連接

        不過,不建議使用操作符##來連接標識符,因爲這個容易是程序可讀性大大降低。

3. 文件包含

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"。

4. 條件編譯

1. #ifdef等價於#if defined(),#ifndef等價於#if !defined()。

2. 在#if中可以使用邏輯操作符(&&、||、!)。在#ifdef 中是不可以使用的,這也是#if的優越點。

#include <stdio.h> #include <stdlib.h> #define A 1 #define B 0 int main(){ #if defined( A ) && defined( B ) printf("test logic operation in #if /n"); /* 如果上面的邏輯判斷成立,那麼將打印出一句話;如果不成立,那麼就不會打印這句話 */ #endif system("pause"); return EXIT_SUCCESS; }

運行結果:

test logic operation in #if

3. sizeof(int)在預編譯階段是不會被求值的。

        只要知道“預編譯階段”在真正的“編譯階段”之前,就很容易理解了。預編譯階段只是對組成源代碼中的字符進行作用,從某種意義上來說,它有時甚至不知道它的操作對象是什麼,它只是按照既定的規則執行替換。

        sizeof(int),無論是sizeof的解析,還是類型的解析,都是在“編譯階段”纔開始的,編譯階段知道它的操作對象是什麼。

下面的代碼是錯誤

#if sizeof(int) == 2 printf("precompile sizeof(int)"); #endif

5. 額外注意

        把一個預處理指令成多行的形式,要使用符號”/”,並且在該符號後面應緊跟換行符。而非預處理指令代碼行不需要使用該符號,直接換行即可。 原因:編譯階段會自動忽略空白符,而預編譯階段不會。

 

本文鏈接:http://blog.csdn.net/daheiantian/archive/2011/02/09/6243993.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章