2013年9月23日 星期一

[ C / C++ ] #define do { ... } while ( 0 ) 為何而用?

    在上班時間看到這篇文章,就很想紀錄一下。底下會有link。

    主要是看到一篇文章問,為何 #define do { ... } while ( 0 )  跟inline會交叉互用,本來提問者以為是等同的意思。但以我對inline的初淺了解,inline內的code展開與否的決定權仍然在compiler上。#define則是前處理器要處理的,所以勢必得展開了。

    問題來了,為何要用 #define do { ... } while ( 0 ) 這樣的方式去定義一個function呢?回答的前輩有趣得以一個問題當開頭:

    假設一個function以#define來看

#define sq(a) (a*a)

int answer = sq(5); // 答案是 25

    好像一般簡單的應用沒什麼問題,假設變成以下呢?

int answer = sq(5+1) // 答案不是 36 啊.....

    因為基本上前處理器會幫我們展開,但是不會幫我們注意括號,因而變成 5 + 1 * 5 + 1 變成11了。

    所以我們得注意#define時候括號的重要性。變成以下就不會產生錯誤的答案:

#define sq(a) ((a)*(a))

    但是inline時候就不會發生這類的問題了。

    回到此篇的主軸,為何要使用 #define do { ... } while ( 0 ) 去定義我們的函數呢?它是有其特殊意義的。

#define swap(x,y) { int tmp_n ; tmp_n = x ; x = y ; y = tmp_n; }

    這樣的函數代入以下會如何呢?

if ( x > y )
  swap(x,y);
else
  otherthing();

    展開它。

if ( x > y )
   { int tmp_n ; tmp_n = x ; x = y ; y = tmp_n; };
else
  otherthing();

    聰明的你,發現問題了嗎?多出了一個分號!

if ( x > y ) {
   int tmp_n ; 
   tmp_n = x
   x = y
   y = tmp_n; 
  } 
; <---- 這邊多分號,慘了 ~~~~
else
  otherthing();

    這邊就會產生編譯錯誤了,所以才導入 #define do { ... } while ( 0 )來解決,此段程式碼就會變成:

if ( x > y )
   do { 
                int tmp_n ;
                tmp_n = x;
                x = y;
                y = tmp_n; 
          } while(0);
else
  otherthing();

    神奇吧!跟我一樣佩服這位前輩替咱們解惑吧!

出自:http://phorum.study-area.org/index.php?topic=56407.0

    Enjoy it.


沒有留言:

張貼留言