0

I want to generate nested for-loops instead of using recursion using the C preprocessor. The depth of this loop structure is bounded. An example nested for-loop with depth 3 is as below:

for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < p; k++) { // do_computation() } } } 

The depth can be between 2 to 10. I have many variations of do_computation() function, so manually writing code for every depth with the combination of the function is making the code look bloated. Some of the answers in stack overflow point to using the boost preprocessor but unfortunately I will not be able to include boost in my application.

6
  • This is preprocessor. You will have to write it all anyway, one way or another. but unfortunately I will not be able to include boost in my application. why? I want to generate nested for-loops .. using the C preprocessor Great. How do you want the API to look like? MAKE_3_LOOPS(i, j, k, m, n, p)? Commented Jul 17, 2022 at 10:15
  • I don't own the application, and generally the lead developers want to keep external libraries to the minimum as our user base is varied, and the machines we run on are also of various architectures (scientific computing). From what I understand from your comment - you mean to say I will have to write all combination myself and the preprocessor will not generate code like this? Commented Jul 17, 2022 at 10:20
  • 2
    You can do #define MAKE_3_LOOP(i, j, k, m, n, p) for (...) for (...) for (...). There are no loops in preprocessor, you can only use macros to replace code. Replace as in replace, literally, one for the other, with almost no logic. So, how do you want the preprocessor API to look like? What have you tried? Commented Jul 17, 2022 at 10:22
  • 2
    I don't think this is the best way to do it. Instead, do only one for loop and calculate the relative indices from there. Way cleaner and scales arbitrarily Commented Jul 17, 2022 at 10:58
  • 1
    Boost is not a monolithic library. You can cherry pick what you want. Boost::preprocessor is literally a bunch of preprocessor macros. AFAICT it doesn't even generate any non-preprocessor C++ code of its own, it only massages data you give it. There isn't a single int or { or struct in the entire thing for example. Commented Jul 17, 2022 at 11:58

1 Answer 1

3

having #define MAKE_N_LOOP() would have been great!

First generate MAKE_LOOP_# macros overloads for every count of arguments. Then write a MAKE_LOOP macro overloaded on number of arguments that redirects to each overload.

#include <stdio.h> #define MAKE_LOOP_2(i, mi) for(int i = 0; i < mi; ++i) #define MAKE_LOOP_4(i, mi, ...) MAKE_LOOP_2(i, mi) MAKE_LOOP_2(__VA_ARGS__) #define MAKE_LOOP_6(i, mi, ...) MAKE_LOOP_2(i, mi) MAKE_LOOP_4(__VA_ARGS__) #define MAKE_LOOP_8(i, mi, ...) MAKE_LOOP_2(i, mi) MAKE_LOOP_6(__VA_ARGS__) // etc. #define MAKE_LOOP_N(_8,_7,_6,_5,_4,_3,_2,_1,N,...) MAKE_LOOP_##N #define MAKE_LOOP(...) MAKE_LOOP_N(__VA_ARGS__,8,7,6,5,4,3,2,1)(__VA_ARGS__) int main() { MAKE_LOOP(i, 5, j, 4, k, 10) { printf("%d-%d-%d\n", i, j, k); } } 

You might also be interested in Generating Nested Loops at Run Time in C .

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. This works beautifully! There is a small typo in: #define MAKE_LOOP_8(i, mi, ...) MAKE_LOOP_2(i, mi) MAKE_LOOP_8(VA_ARGS) it should be #define MAKE_LOOP_8(i, mi, ...) MAKE_LOOP_2(i, mi) MAKE_LOOP_6(VA_ARGS) For someone trying to figure out how MAKE_LOOP_N picks the appropriate macro, it is implemented as a sliding window tuned to pick the 9th argument always.
how MAKE_LOOP_N I imagine __VA_ARGS__ pushing 8,7,6,5,4,3,2,1 arguments to the right, so the proper number aligns with N.
Thank you. I had one follow up question. Is it possible to pass the parameters itself as a string (constant). i.e. have MAKE_LOOP(CONST_STRING) where CONST_STRING="i,5,j,4,k,10" From what I have understood, this is not possible. But I was assuming that since I can call MAKE_LOOP(i, var_x, j, var_y, k, var_z) where var_i gets evaluated to its runtime value, there should be a way to evaluate the string to its runtime value, and then evaluate its included values i,j,k (with nested MACRO calls?)?
CONST_STRING="i,5,j,4,k,10" it's not possible to do anything with a string. Once it's a string it's a string. I do not understand the a way to evaluate the string to its runtime value part. A string has a "runtime value" of the string. You can do #define PARAMS i, 5, j, 4, k, 10 with a call like MAKE_LOOP_EXTRA(PARAMS), but then you might as well do #define MY_LOOP MAKE_LOOP(i,5,j,4,k,10).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.