程式設計工作室 (program)   
一般區 精華區 休閒聊天 個人郵件 個人設定 重新登入

←回列表   ↑上一篇   ↓下一篇           

發信人:lgwlu@ms1.hinet.net (Lgw Lu)
日期:Fri, 19 Jul 1996 00:49:30 GMT
標題:C 講座 6
信群:tw.bbs.comp.language    看板:
代號:<4sl15n$gpv@netnews.hinet.net>
組織:DCI HiNet



       戰   鬥   世   家   C 語言講座                  #6

                                 作者: Lgw Lu
                                 E-Mail: lgwlu@ms1.hinet.net
---------------------------------------------------------------

                   < 巨集之評析 >

前言:

     巨集是包括在前端處理器裡的一部份,但它重要嗎?! 當然非常重
  要!! 以下將讓你了解原來巨集有這麼多用途,這麼多陷阱!!

內文:

     巨集功用:

  1. 程式碼替換

     大部分懂 C 的人都會,這是最簡單的功能, 但也是最容易中計的
     陷阱,請看說明....

     EX:

       #define FUNC(a,b) a*b

       以這行看來,感覺沒啥問題,也許你的寫法也是類似這種, 其實
       這行裡充滿陷阱,WHY ??

       你 CALL 的方式                   結果

       FUNC(5,6)                        5*6   正確!!

       FUNC(X+1,Y+2)                    X+1*Y+2
                                        = X+Y+2  錯誤!!

       現在了解的吧!! 那要怎麼改??
       改成

       #define FUNC(a,b) (a)*(b)

       這樣的話, FUNC(X+1,Y+2) 結果就是我們想要的 (X+1)*(Y+2)
       這樣沒錯了吧!!
       錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯錯
       為啥還是錯??
       請看:

       X/FUNC(Y,Z)  原本是想得到 X/(Y*Z),但結果卻是

       X/(Y)*(Z) = (X*Z)/Y 這實在是.......

       正確改法:

       #define FUNC(a,b) ((a)*(b))

       結論:
            (1) 若用 C++ ,請用 inline function 方式,取代巨集
            (2) 每個變數都必須用 () ,最後也要加 () ,如本例!!

  2. 多行程式碼替換

     大部分人可能不知道巨集可不只一行,所以功能就相對被忽略了!

     EX:

     #define FUNC1(a,b)              #define FUNC2(a,b)
       (a-10)/5; \                    {
                                      (a-10)/5; \
       b=a*2; \                       b=a*2;  \
       a=b;                           a=b;
                                      }

     這兩個巨集功用相同,但 FUNC1 卻有陷阱,請看

     for(i=0;i<100;i++)
        FUNC1(x[i],y[i]);

     這結果是啥?! 是 (a-10)/5 這行做了 100 次,而 b=a*2; a=b;
     卻都只做一次,現在知道為何要加 { } 了吧!!

  3. 資料替換

     當你某部份資料需要常常變動時,就可使用此法,如果可省下欲找
     尋資料,並且不會發生某處未修改到之情況!!

     EX:

     #define COLOR 0x20

     ............
     fun(COLOR,x);
     ......
     if(COLOR >0x10) .....

     .....

     P.S. 雖然可如此用,但我建議還是使用 const 方式,至於原因為
          何,請參考 #1 說明!!

  4. ANSI C 新功能

     ANSI C 比 K&R C 功能多了 # 及 ## ,這部份其實是 #2 的續篇
     在 #2 中說到 ANSI 及 K&R 差異,現在再加上此部份,ANSI C 又
     勝一籌!!

     說明1:參數前有 # ,則用 " " 括住參數,若是參數中有 "  則加
     上一 \ .

     EX:

        原來寫法:

        puts("在 C: 下有一 \"TEST.COM\" 檔案");

        輸出結果: 在 C: 下有一 "TEST.COM" 檔案

        改用巨集:

        #define STR(X) #X

        puts(STR(在 C: 下有一 "TEST.COM" 檔案));

        你看!! 是不是以後寫起來方便多了,且看起來清楚多了!!

     說明2:## 會將前後兩語法單元連接

     EX:

       #define STR(X,Y) #X ## #Y

       puts(STR(This is "A",This is "B"));

       輸出結果: This is "A"This is "B"

  其實若是複雜的 Function 盡量不要使用巨集方式,因為太危險了,
  就算用 { } 一樣會有危險!!

  EX:
     #define FUNC(X)
        {
        F1(X);
        F2(X);
        }

     程式中若為 FUNC(a--); 其實你是想用 a-- 後的值去 F1() 及
     F2() 中運算,但實際結果卻為

     F1(a--);
     F2(a--);   <=== 這行結果是錯的,並 a 被減了 2 ,而非 1

  好了!!巨集就說到這!! 總之一句話,用巨集小心點!!!

預告:
     下篇介紹浮點數的使用須知, < 要命的浮點數 >

  P.S. 若各位有啥想知道的,或某篇想知道更深入的話,請來信告訴我
       因為若無任何問題,本講座將於 #8 做結束!!

---------------------------------------------------------------

                  <<< 本文版權屬於作者 >>>
     本文章可自由引用,拷貝,傳閱,但需保持本文章之完整性,從標題
  到最後版權宣告,且不能用來做商業用途!!

     若有任何問題,或是錯誤之處,歡迎來信批評指教!! 謝謝!!





←回列表   ↑上一篇   ↓下一篇