我们可以有recursionmacros吗?

我想知道如果我们可以在C / C ++中有recursionmacros吗? 如果是,请提供一个示例。

第二件事:为什么我不能执行下面的代码? 我在做什么错误? 是因为recursionmacros吗?

# define pr(n) ((n==1)? 1 : pr(n-1)) void main () { int a=5; cout<<"result: "<< pr(5) <<endl; getch(); } 

您的编译器可能提供了一个选项,只有预处理,而不是实际编译。 如果您试图在macros中查找问题,这非常有用。 例如使用g++ -E

 > g++ -E recursiveMacro.c # 1 "recursiveMacro.c" # 1 "<built-in>" # 1 "<command line>" # 1 "recursiveMacro.c" void main () { int a=5; cout<<"result: "<< ((5==1)? 1 : pr(5 -1)) <<endl; getch(); } 

正如你所看到的,它不是recursion的。 pr(x)在预处理过程中只被replace一次。 要记住的重要一点是,所有的预处理器都是盲目地用另一个replace一个文本string,它实际上并不像(x == 1)那样计算expression式。

你的代码不能编译的原因是pr(5 -1)没有被预处理器所取代,所以它在源代码中作为未定义函数的调用而结束。

macros不会直接recursion扩展,但有解决方法。 当预处理器扫描并扩展pr(5)

 pr(5) ^ 

它创build了一个禁用的上下文,所以当它再次看到pr时:

 ((5==1)? 1 : pr(5-1)) ^ 

无论我们尝试什么,它都变成蓝色,不能再扩大。 但是我们可以通过使用延迟expression式和一些间接的方法来防止我们的macros变成蓝色:

 # define EMPTY(...) # define DEFER(...) __VA_ARGS__ EMPTY() # define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() # define EXPAND(...) __VA_ARGS__ # define pr_id() pr # define pr(n) ((n==1)? 1 : DEFER(pr_id)()(n-1)) 

所以现在它会像这样扩展:

 pr(5) // Expands to ((5==1)? 1 : pr_id ()(5 -1)) 

这是完美的,因为pr从未被涂成蓝色。 我们只需要应用另一个扫描来进一步扩展:

 EXPAND(pr(5)) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : pr_id ()(5 -1 -1))) 

我们可以应用两个扫描来进一步扩展:

 EXPAND(EXPAND(pr(5))) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : ((5 -1 -1==1)? 1 : pr_id ()(5 -1 -1 -1)))) 

但是,由于没有终止条件,我们永远不能应用足够的扫描。 我不确定你想完成什么,但是如果你对如何创buildrecursionmacros感兴趣,下面是一个如何创build一个recursion重复macros的例子。

首先应用大量的扫描macros:

 #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__))) #define EVAL5(...) __VA_ARGS__ 

接下来,一个对模式匹配有用的concatmacros:

 #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) #define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ 

递增和递减计数器:

 #define INC(x) PRIMITIVE_CAT(INC_, x) #define INC_0 1 #define INC_1 2 #define INC_2 3 #define INC_3 4 #define INC_4 5 #define INC_5 6 #define INC_6 7 #define INC_7 8 #define INC_8 9 #define INC_9 9 #define DEC(x) PRIMITIVE_CAT(DEC_, x) #define DEC_0 0 #define DEC_1 0 #define DEC_2 1 #define DEC_3 2 #define DEC_4 3 #define DEC_5 4 #define DEC_6 5 #define DEC_7 6 #define DEC_8 7 #define DEC_9 8 

一些对条件有用的macros:

 #define CHECK_N(x, n, ...) n #define CHECK(...) CHECK_N(__VA_ARGS__, 0,) #define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x)) #define NOT_0 ~, 1, #define COMPL(b) PRIMITIVE_CAT(COMPL_, b) #define COMPL_0 1 #define COMPL_1 0 #define BOOL(x) COMPL(NOT(x)) #define IIF(c) PRIMITIVE_CAT(IIF_, c) #define IIF_0(t, ...) __VA_ARGS__ #define IIF_1(t, ...) t #define IF(c) IIF(BOOL(c)) #define EAT(...) #define EXPAND(...) __VA_ARGS__ #define WHEN(c) IF(c)(EXPAND, EAT) 

把它放在一起,我们可以创build一个重复的macros:

 #define REPEAT(count, macro, ...) \ WHEN(count) \ ( \ OBSTRUCT(REPEAT_INDIRECT) () \ ( \ DEC(count), macro, __VA_ARGS__ \ ) \ OBSTRUCT(macro) \ ( \ DEC(count), __VA_ARGS__ \ ) \ ) #define REPEAT_INDIRECT() REPEAT //An example of using this macro #define M(i, _) i EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7 

所以,是的,有一些解决方法,你可以在C / C ++中有recursionmacros。

你不应该在C或C ++中有recursionmacros。

C ++标准的相关语言,第16.3.4节第2段:

如果在扫描replace列表期间(不包括源文件的预处理标记的其余部分)find正在replace的macros的名称,则不会replace它。 此外,如果任何嵌套replace遇到被replace的macros名称,则不会被replace。 这些未replace的macros名预处理令牌不再可用于进一步的replace,即使它们在其中macros名预处理令牌将被replace的上下文中稍后(重新)检查。

这种语言有一些摆动的空间。 有多个相互调用的macros,有一个灰色的地方,这个措辞并不完全说明应该做什么。 这个语言律师问题对于C ++标准有一个积极的问题; 请参阅http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268

忽略那个语言律师的问题,每个编译器厂商都明白这个意图:

recursionmacros在C或C ++中是不允许的。

你很可能无法执行它,因为你不能编译它。 另外,如果它能正确编译,它总是会返回1.你的意思是(n==1)? 1 : n * pr(n-1) (n==1)? 1 : n * pr(n-1)

macros不能recursion。 根据第16.3.4.2节(感谢Loki Astari),如果在replace列表中find当前macros,它将保持原样,因此定义中的pr不会改变:

如果在replace列表扫描过程中(不包括源文件的预处理标记的其余部分)find正在replace的macros的名称,则不会replace它。 此外,如果任何嵌套replace遇到被replace的macros的名称,则不会被replace。 这些未replace的macros名预处理令牌不再可用于进一步的replace,即使它们在其中macros名预处理令牌将被replace的上下文中稍后(重新)检查。

你的来电:

 cout<<"result: "<< pr(5) <<endl; 

被预处理器转换成:

 cout<<"result: "<< (5==1)? 1 : pr(5-1) <<endl; 

在这期间, prmacros的定义是'lost',并且编译器显示一个像'pr'没有在这个范围(事实)中声明的错误“,因为没有名字为pr函数。

在C ++中不鼓励使用macros。 你为什么不写一个函数呢?

在这种情况下,您甚至可以编写一个模板函数,以便在编译时parsing,并且将performance为一个常量值:

 template <int n> int pr() { pr<n-1>(); } template <> int pr<1>() { return 1; } 

C或C ++中不能有recursionmacros。