2009-11-27 280 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