C語言預處理指令整理

什麼是預處理指令?

預處理就是在進行編譯的第一遍詞法掃描和語法分析之前所作的工作。說白了,就是對源文件進行編譯前,先對預處理部分進行處理,然後對處理後的代碼進行編譯。這樣做的好處是,經過處理後的代碼,將會變的很精短。C源碼在進行編譯前會先經過預處理,預處理指令均以#開頭,結尾沒有分號(;)不是C語句。預處理器採用“語言符號”的分析方式,將空格作爲區分標誌之間的符號,一行作爲一條指令,“\”可以將預處理指令延伸到下一行。

常見預處理指令

#define,#error,#include,#if,#else,#elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma等。

一、宏定義

1.不帶參數的宏定義

  (1)不帶參數的宏定義就是用一個標識符(宏名)來代表一個字符串。它的一般形式爲 #define Macro Str 在預處理的時候程序中的宏名Macro被替換爲字符串Str,這個過程稱爲宏展開。
  (2)#define指令出現在程序中函數的外面,宏名的有效範圍爲該指令行起到本源文件結束或#undef。
  (3)宏展開只是簡單的字符串替換,簡單宏常用於定義常量,宏沒有類型,也沒有優先級的概念,使用定義常量主要用於指定數組長度 #define ayyLength 256 ,建議儘量使用const或enum代替宏定義常量 const intarrLen 256; 。建議不使用宏定義類型 #define Status int 而是用typedef關鍵字 typedef Status int; 。
  (4)宏不是C語句不能加分號,否則會將分號一起代入。考慮到優先級問題,其中表達式也可能需要括號。
  (5)宏代替的字符串可以是常量也可以表達式,格式描述符,語句(甚至是它們的一部分)等任何C程序中出現的字符串。 當然,宏代替的字符串中也可以包含已定義的宏名。#undef macro #undef指令可以終止宏名的定義。

2.帶參數的宏定義

  (1)#define Macro(argus) str
  對帶參數的宏展開 是將帶實參的宏 按照#define指令行中按從左到右的順序進行置換。宏名和帶參數的括號之間不能加空格,否則將成爲無參數宏,空格後的每一個字符都將作爲替代字符串的一部分。
  (2)帶參數的宏不是函數,它只是進行簡單字符代換 。定義宏時參數和字符串可以是任意的,但在定義時要注意標識符不能出現重名【#define Macro(Macro) str】(利用代碼塊作用域)。在實際調用時參數可能是單個數據對象也可能是表達式,由於宏只進行簡單文本代換考慮到優先級和結合性的問題,建議在定義宏時將參數用圓括號括起以作爲一個獨立單位。
  (3)含參宏類似於inline函數,其調用也是採用傳址的方式(真正的在調用點嵌入函數代碼)。宏無類型,其參數也沒有類型,只是一個符號代表,含參宏可以作爲模板函數(C++引入,不同類型的參數可以使用同一段函數體)。
  (4)宏與函數相比沒有參數傳遞和返回值的限制使用更加自由靈活,而函數相對獨立便於完成較複雜的任務。函數調用需較多時間處理內存等,而宏不需要。

3.宏定義中的運算符

  (1)對程序作預處理前,編譯器會進行翻譯處理。編譯器首先把源碼中的字符映射到源字符集。然後編譯器查找反斜線後緊跟換行符(這裏指按下回車鍵在源碼中產生的換行符而非轉義字符’\n’)的實例並刪除這些實例。所以反斜線加回車鍵可以將宏定義擴展到多行。
  (2)#運算符與參數結合可以那參數名轉換爲相應字符串。例如:x是宏的形參,實參爲1時#x將被替換爲”1”(字符串),x將被替換爲1(數值常量)。
  (3)##運算符可以把兩個語言符號組合成一個語言符號。例如:n是宏的形參,實參爲1時,x##n將變爲標識符x1,如果無##編譯器將把xn當做一個語言符號,在宏參數中中無法找到於是不進行替換。

二、文件包含處理

#include<filename> 或  #include"filename" 

● 尖括號中的文件名優先在編譯器安裝目錄中查找(通常是標準庫),雙引號中的文件優先在工作目錄中查找(自定義庫)。
● 文件包含處理是指將另一個源文件的全部內容包含進來,即將另外的文件內容包含到本文件之中,插入到當前位置,代替預處理指令然後進行編譯得到一個目標文件。
● 頭文件中只有函數聲明和宏定義,真正的實現在庫中。在鏈接(linking)時,庫才被鏈接進來。
● 這種常用在文件頭部的被包含文件被稱爲頭文件(header),常以.h作爲後綴。當然不用.h作爲後綴用.c作爲後綴也是可以的,但是用.h更能表示此文件的性質。
● 同樣,#include指令不一定要出現在文件首部。應當注意,被包含文件修改後,凡包含此文件的所有文件都要全部重新編譯。文件包含處理是將要包含的文件的內容代替預處理指令,成爲源文件的一部分。

三、條件編譯

  條件編譯使得程序中的一部分內容只在滿足一定條件時才進行編譯或不進行編譯。

1.ifdef指令

    #ifdef Label
        Block1
    #else
        Block2
    #endif

  若指定的標識符已經被#define指令定義過,則對程序段1進行編譯否則對程序段2進行編譯。可以用於程序調試等。
  也可以用

 #ifdef

      Block

#endif

2.ifndef指令

#ifndef Label

     Block1

#else

    Block2

#endif

  與1正好相反,若標識符未被定義則編譯程序段1,否則編譯程序段2。
  爲了避免頭文件重複包含,通常使用條件編譯:

#ifndef STDIO_H

#define STDIO_H

     ...

#endif

3.if指令

#if expr

     Block1

#else

    Block2

#endif

  表達式爲真時編譯程序段1,否則編譯程序段2。
  不用條件編譯指令而用if語句同樣也可以實現,但是那樣做目標程序長(所有語句都參加編譯),運行時間長(在if語句處需進行邏輯判斷)。

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