1. 程式人生 > >它被定義了,但它卻被定義為未定義——有趣的巨集定義

它被定義了,但它卻被定義為未定義——有趣的巨集定義

    前些日子為了弄清楚巨集定義寫了個小程式,忽然發現將識別符號定義為空和將識別符號定義為未定義完全是兩碼事……然後發現原來巨集定義中還有一種狀態叫“未定義”。下面就是那個小程式以及簡單的分析,然後通過這個程式可以充分體驗一下這個“未定義”的狀態,體驗一下什麼叫“它被定義了,但它卻被定義為未定義”。
程式原始碼:

#include<stdio.h> int main() { #if (A == B) printf("define A = B\n"); #elif (A == C) printf("define A = C\n"); #else printf
("nothing is defined!\n"); #endif return 0; }


    然後下面是編譯命令和執行結果:
[[email protected] test]# gcc definetest.c -o definetest
[[email protected] test]# ./definetest
define A = B
[[email protected] test]# gcc definetest.c -o definetest -DA
[[email protected] test]# ./definetest
nothing is defined!


[[email protected] test]# gcc definetest.c -o definetest -DA=C
[[email protected] test]# ./definetest
define A = B
[[email protected] test]# gcc definetest.c -o definetest -DA=C -DC
[[email protected] test]# ./definetest
define A = C
[[email protected] test]# gcc definetest.c -o definetest -DA=C -DB

[[email protected] test]# ./definetest
define A = C

    首先簡單介紹一下gcc編譯時-D的意思,-D其實就是在預處理時進行巨集定義,和在程式碼中用#define實現的是一樣的。而D後面緊跟的就是巨集定義的內容:-DA,相當於在程式碼中#define A;而-DA=C就相當於在程式碼中的#define A C。
    首先第一種,也是最簡單的編譯方式,什麼都沒有定義。但是卻在第一個分支執行了,這是為什麼呢?因為這時A沒有被定義過,B也沒有被定義過,於是未定義等於未定義,於是在第一個分支中就執行了。
    那這時候就會考慮怎麼才能跑到第三個分支去呢?第二種編譯方式基本算是最簡單的解決方法了,巨集定義A為空,然後A被定義為空,而B和C仍是未定義,於是就會跑到第三個分支。
    第三種情況應該是最有意思的一種情況,大家一般都會認為程式應該會執行到第二個分支,打印出define A = C,但是卻仍在第一分支就實現了。其實這就是那種“它被定義了,但它卻被定義為沒定義”的情況,將A定義為C,但是C卻是“未定義”,於是A就變成了“未定義”,而B本身也是“未定義”,所以A就和B一樣了,所以在第一分支就實現了。
     然後這個時候如果把C定義一下,或者將B定義一下,只要保證兩者不都是“未定義”,就會進入到程式的第二分支了。分別對應第四和第五種編譯方式。