Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we have recursive macros?

I want to know if we can have recursive macros in C/C++? If yes, please provide a sample example.

Second thing: why am I not able to execute the below code? What is the mistake I am doing? Is it because of recursive macros?

# define pr(n) ((n==1)? 1 : pr(n-1)) void main () {     int a=5;     cout<<"result: "<< pr(5) <<endl;     getch(); } 
like image 287
user1367292 Avatar asked Sep 16 '12 14:09

user1367292


People also ask

What is recursive macro in system software?

21.5. 1 Macro Expansion Is RecursiveWhen text contains other macros, those other macros are also expanded. This process is recursive and continues until all macros have been expanded. For example, consider the following: DAxxx DByyy DC$A.$B DD$C.zzz.

Why macros should not be used?

"Using macros can reduce the readability of your code. When you use them, you're basically creating a set of nonstandard language features."

Can a macro call itself?

A recursive macro is one that calls itself over and over to perform a specific task.

What is __ Va_opt __?

The key to making this work is a new pre-processor feature in C++20, __VA_OPT__(x) , which expands to x when a variable-argument macro has more than zero arguments and to nothing otherwise.


1 Answers

Macros don't directly expand recursively, but there are workarounds. When the preprocessor scans and expands pr(5):

pr(5) ^ 

it creates a disabling context, so that when it sees pr again:

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

it becomes painted blue, and can no longer expand, no matter what we try. But we can prevent our macro from becoming painted blue by using deferred expressions and some indirection:

# 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)) 

So now it will expand like this:

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

Which is perfect, because pr was never painted blue. We just need to apply another scan to make it expand further:

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

We can apply two scans to make it expand further:

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

However, since there is no termination condition, we can never apply enough scans. I'm not sure what you want to accomplish, but if you are curious on how to create recursive macros, here is an example of how to create a recursive repeat macro.

First a macro to apply a lot of scans:

#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__ 

Next, a concat macro which is useful for pattern matching:

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

Increment and decrement counters:

#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 

Some macros useful for conditionals:

#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) 

Putting it all together we can create a repeat macro:

#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 

So, yes with some workarounds you can have recursive macros in C/C++.

like image 82
Paul Fultz II Avatar answered Oct 12 '22 21:10

Paul Fultz II