BBS水木清华站∶精华区

 
 
       战   斗   世   家   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; \                    { 
       b=a*2; \                       (a-10)/5; \ 
       a=b;                           b=a*2;  \ 
                                      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 做结束!! 
 
--------------------------------------------------------------- 
 
                  <<< 本文版权属於作者 >>> 
     本文章可自由引用,拷贝,传阅,但需保持本文章之完整性,从标题 
  到最後版权宣告,且不能用来做商业用途!! 
 
     若有任何问题,或是错误之处,欢迎来信批评指教!! 谢谢!! 
 
 
 

BBS水木清华站∶精华区