天天看點

C語言宏進階用法 [總結]

1、前言

    今天看代碼時候,遇到一些宏,之前沒有見過,感覺挺新鮮。如是上網google一下,順便總結一下,友善以後學習和運用。c語言程式中廣泛的使用宏定義,采用關鍵字define進行定義,宏隻是一種簡單的字元串替換,根據是否帶參數分為無參和帶參。宏的簡單應用很容易掌握,今天主要總結一下宏的特殊符号及慣用法。

  (1)宏中包含特殊符号:#、##.

      (2)宏定義用do{ }while(0)

2、特殊符号#、##

(1)#

 when you put a # before an argument in a preprocessor  macro, the preprocessor turns that argument into a character array. 

 在一個宏中的參數前面使用一個#,預處理器會把這個參數轉換為一個字元數組 

 簡化了解:#是“字元串化”的意思,出現在宏定義中的#是把跟在後面的參數轉換成一個字元串

error_log("add"); 轉換為 fprintf(stderr,"error: "add"\n");

error_log(devied =0); 轉換為 fprintf(stderr,"error: devied=0\n");

(2)##

  “##”是一種分隔連接配接方式,它的作用是先分隔,然後進行強制連接配接。

  在普通的宏定義中,預處理器一般把空格解釋成分段标志,對于每一段和前面比較,相同的就被替換。但是這樣做的結果是,被替換段之間存在一些空格。如果我們不希望出現這些空格,就可以通過添加一些##來替代空格。

type1(int, c); 轉換為:int  name_int_type ; (因為##号将後面分為 name_ 、type 、 _type三組,替換後強制連接配接)

type2(int, d);轉換為: int  d_int_type ; (因為##号将後面分為 name、_、type 、_type四組,替換後強制連接配接)

3、宏定義中do{ }while(0)

   第一眼看到這樣的宏時,覺得非常奇怪,為什麼要用do……while(0)把宏定義的多條語句括起來?非常想知道這樣定義宏的好處是什麼,于是google、百度一下了。

    采用這種方式是為了防範在使用宏過程中出現錯誤,主要有如下幾點:

  (1)空的宏定義避免warning:

  #define foo() do{}while(0)

  (2)存在一個獨立的block,可以用來進行變量定義,進行比較複雜的實作。

  (3)如果出現在判斷語句過後的宏,這樣可以保證作為一個整體來是實作:

      #define foo(x) \

        action1(); \

        action2();

    在以下情況下:

    if(null == ppointer)

         foo();

    就會出現action1和action2不會同時被執行的情況,而這顯然不是程式設計的目的。

  (4)以上的第3種情況用單獨的{}也可以實作,但是為什麼一定要一個do{}while(0)呢,看以下代碼:

      #define switch(x,y) {int tmp; tmp="x";x=y;y=tmp;}

      if(x>y)

        switch(x,y);

      else       //error, parse error before else

      otheraction();

在把宏引入代碼中,會多出一個分号,進而會報錯。這對這一點,可以将if和else語句用{}括起來,可以避免分号錯誤。

  使用do{….}while(0) 把它包裹起來,成為一個獨立的文法單元,進而不會與上下文發生混淆。同時因為絕大多數的編譯器都能夠識别do{…}while(0)這種無用的循環并進行優化,是以使用這種方法也不會導緻程式的性能降低

4、測試程式

  簡單寫個測試程式,加強練習,熟悉一下宏的進階用法。

C語言宏進階用法 [總結]
C語言宏進階用法 [總結]

測試結果如下:

C語言宏進階用法 [總結]

繼續閱讀