-1

For some reason (related to performance measurements), I need to repeat a code segment 1000 times (1024 times would be OK too), but WITHOUT "for" or any other loop.

Obviously, I could most likely write a macro that would look something like this:

#define RUN_1000_TIMES(x)   \
x                           \
x                           \
x                           \
...
...  /* (999+1 times the same line) */
...
x                           \
x

... and than apply that macro to my code segment.

But is there a more elegant solution than 1000 lines long macro?

VividD
  • 10,456
  • 6
  • 64
  • 111

5 Answers5

3
#define RUN_1024_TIMES(x) do {RUN_512_TIMES(x); RUN_512_TIMES(x); } while(0)
#define RUN_512_TIMES(x) do {RUN_256_TIMES(x); RUN_256_TIMES(x); } while(0)
#define RUN_256_TIMES(x) do {RUN_128_TIMES(x); RUN_128_TIMES(x); } while(0)
#define RUN_128_TIMES(x) do {RUN_64_TIMES(x); RUN_64_TIMES(x); } while(0)
#define RUN_64_TIMES(x) do {RUN_32_TIMES(x); RUN_32_TIMES(x); } while(0)
#define RUN_32_TIMES(x) do {RUN_16_TIMES(x); RUN_16_TIMES(x); } while(0)
#define RUN_16_TIMES(x) do {RUN_8_TIMES(x); RUN_8_TIMES(x); } while(0)
#define RUN_8_TIMES(x) do {RUN_4_TIMES(x); RUN_4_TIMES(x); } while(0)
#define RUN_4_TIMES(x) do {RUN_2_TIMES(x); RUN_2_TIMES(x); } while(0)
#define RUN_2_TIMES(x) do {x; x; } while(0)

the do{ ... } while(0) is only for the case that you call it with if (....) RUN_1024_TIMES(...);. You can remove it when you do not need it.

You could also do it with 3 times per macro:

#define RUN_1000_TIMES(x) do {RUN_729_TIMES(x); RUN_243_TIMES(x); RUN_27_TIMES(x); x; } while(0)
#define RUN_729_TIMES(x) do {RUN_243_TIMES(x); RUN_243_TIMES(x); RUN_243_TIMES(x); } while(0)
#define RUN_243_TIMES(x) do {RUN_81_TIMES(x); RUN_81_TIMES(x); RUN_81_TIMES(x); } while(0)
#define RUN_81_TIMES(x) do {RUN_27_TIMES(x); RUN_27_TIMES(x); RUN_27_TIMES(x); } while(0)
#define RUN_27_TIMES(x) do {RUN_9_TIMES(x); RUN_9_TIMES(x); RUN_9_TIMES(x); } while(0)
#define RUN_9_TIMES(x) do {RUN_3_TIMES(x); RUN_3_TIMES(x); RUN_3_TIMES(x); } while(0)
#define RUN_3_TIMES(x) do {x; x; x; } while(0)
mch
  • 9,424
  • 2
  • 28
  • 42
1

in a Python file, put:

print("//header of the code")
for i in range(1000):
    print("x;")
print("//bottom of the code")

and then:

./gen.py > file.c

that will be simpler that what ever you can do with the C preprocessor, that cannot perform things like a loop!

Kevin
  • 4,618
  • 3
  • 38
  • 61
1
#define RUN_10_TIMES(X) X X X X X X X X X X
#define RUN_1000_TIMES(X) RUN_10_TIMES(RUN_10_TIMES(RUN_10_TIMES(X)))

Note that you get to recursively "call" a macro in "invocation" like syntax (so FOO(FOO(FOO(X))) is okay); this is because the first step of a function-like macro invocation uses argument substitution, which has no restrictions on recursion. Argument substitution specifically involves evaluating any argument whose corresponding parameter appears in a replacement list (and isn't stringified or part of a paste), as if it were on a line by itself, and then using the resulting expansion to replace each such parameter. After argument substitution (and paste/stringifications), the resulting replacement list is rescanned in a rescan and further replacement step; it's during this step that the macro is marked with "blue paint" (meaning, additional invocations are ignored). Invocation-like recursion is entirely a function of argument substitution, so it's allowed.

H Walters
  • 2,634
  • 1
  • 11
  • 13
1

You can write your loops normally, and then just tell the compiler you want the loops to be unrolled. It's nicely written, and as optimal as if you wrote the 1000 lines.

The way to do this depends on your compiler. I'll write the answer for GCC which is the compiler I use normally, but other compilers should be similar.

If you want to unroll all loops in your code, it is easier: you just need to add an option or two to the command line:

-funroll-loops
-funroll-all-loops

If you want to know more about the behaviour of these options, refer to the compiler manual. There are also questions about them here on SO.

If you just want to unroll a specific loop, and keep all other loops, it is more difficult, but it can also be done. Check this SO answer for that: https://stackoverflow.com/a/14251545/6872717

1

You can use P99 for that: http://p99.gforge.inria.fr/p99-html/group__preprocessor__for_gaec0c87b336a5fa2a8230e207af5cc1f0.html#gaec0c87b336a5fa2a8230e207af5cc1f0

The "sad" part is that maybe a smart enough compiler... make it a loop!

eugenioperez
  • 627
  • 7
  • 15