2009-11-27 373 views

回答

2

這是一個權衡額外的好處。讓我舉個例子。我在1985年左右偶然發現了differential execution的技術,我認爲這是編程用戶界面的一個非常好的工具。基本上,它需要像這樣簡單的結構化程序:

void Foo(..args..){ 
    x = y; 
    if (..some test..){ 
    Bar(arg1, ...) 
    } 
    while(..another test..){ 
    ... 
    } 
    ... 
} 

和廢石與控制結構是這樣的:

void deFoo(..args..){ 
    if (mode & 1){x = y;} 
    {int svmode = mode; if (deIf(..some test..)){ 
    deBar(((mode & 1) arg1 : 0), ...) 
    } mode = svmode;} 
    {int svmode = mode; while(deIf(..another test..)){ 
    ... 
    } mode = svmode;} 
    ... 
} 

現在,一個很好的辦法做到這一點本來是寫一個解析器C或任何基礎語言,然後遍歷解析樹,生成我想要的代碼。 (當我在Lisp中完成時,那部分很簡單。)

但是誰願意爲C,C++或其他任何語言編寫解析器?

所以,相反,我只是寫宏,以便我可以寫這樣的代碼:

void deFoo(..args..){ 
    PROTECT(x = y); 
    IF(..some test..) 
    deBar(PROTECT(arg1), ...) 
    END 
    WHILE(..another test..) 
    ... 
    END 
    ... 
} 

但是,我這樣做是在C#中的時候,有人在他們的智慧決定的宏都壞了,我不我不想寫一個C#解析器,所以我必須手工完成代碼生成。這是一種皇室般的痛苦,但與通常的編碼方式相比,它仍然值得。

+0

+1謝謝邁克。這是最好的答案:) – Viet 2009-12-01 07:31:24

5

在C或C++中,宏擴展爲臭名昭着的難以調試。另一方面,編寫代碼生成器更容易調試,因爲它本身就是一個單獨的程序。

但是,您應該知道,這僅僅是C預處理器的限制。例如,在Lisp系列語言中,宏擴展是代碼生成,它們完全一樣。要編寫一個宏,你需要編寫一個程序(在Lisp中)來將S表達式輸入轉換爲另一個S表達式,然後將其傳遞給編譯器。

+0

感謝您的回覆,Greg。編寫一個體面的代碼生成器需要花費更多的時間,並且宏看起來像是一件快速的黑客工作。 – Viet 2009-11-27 09:48:53

+0

++我的情緒正好。如果有一種方法可以逐步完成預處理,那將會很好。即便如此,如果代碼生成足夠簡單,我更喜歡宏。 – 2009-11-30 15:48:05

9

對於C++,我更喜歡模板元編程或通過宏代碼生成,但宏仍然有其用處。

您與dbtemplatelib給出的例子可以用的C++ 0x Variadic Templates覆蓋,有喜歡的類型檢查等

+0

感謝您的建議。模板也有其優點。可變參數宏在那裏,但可變參數模板尚未流行,因爲C++ 0x仍然是新的。 – Viet 2009-11-27 09:55:58

+0

嗯,確切地說,它還沒有出來,它將會是一個「C++ 1x」。但可變參數模板在某些編譯器中實現,例如,要使用它們與gcc,必須添加「-std = C++ 0x」作爲編譯器開關。 – hirschhornsalz 2009-11-27 14:19:19

3

兩者都有他們的問題。與宏不同,代碼生成可以產生可讀性和可調試性(甚至是一個單詞?)的代碼,但它不那麼靈活和難以改變。

+0

+1。感謝您的回覆。 – Viet 2009-12-10 02:15:37