DEV Community

Horu
Horu

Posted on • Updated on

Repeat macro in C?

Sometimes we want to repeat something at compile time using C, although this sounds difficult to elaborate.
Trying I managed to elaborate the following example:

#include <stdio.h>

#define REPEAT_1(FN) FN(0)
#define REPEAT_2(FN) REPEAT_1(FN) FN(1)
#define REPEAT_3(FN) REPEAT_2(FN) FN(2)
#define REPEAT_4(FN) REPEAT_3(FN) FN(3)
#define REPEAT_5(FN) REPEAT_4(FN) FN(4)
#define REPEAT_6(FN) REPEAT_5(FN) FN(5)
#define REPEAT_7(FN) REPEAT_6(FN) FN(6)
#define REPEAT_8(FN) REPEAT_7(FN) FN(7)
#define REPEAT_9(FN) REPEAT_8(FN) FN(8)
#define REPEAT_10(FN) REPEAT_9(FN) FN(9)

#define REPEAT(FN, N) REPEAT_##N(FN)

#define PRINTF(N) printf("%d\n", N);

int main() {
    REPEAT(PRINTF, 10)
}
Enter fullscreen mode Exit fullscreen mode

We will find the following output:

0
1
2
3
4
5
6
7
8
9
Enter fullscreen mode Exit fullscreen mode

The main macro is called REPEAT, which takes a function/macro name and a loop count as its arguments. It then generates a call to one of the other macros (REPEAT_1, REPEAT_2, etc.) depending on the loop count.

Each of the REPEAT_X macros generates code for a loop that calls the specified function X times with different arguments. For example, REPEAT_5 generates a loop that calls the function 5 times with the arguments 0 through 4.

We can see the PRINTF macro calling printf with an integer argument. It then calls REPEAT with PRINTF and a loop count of 10, which generates code that calls printf 10 times with the arguments 0 through 9.

This will generate the assembly output we expect.

Image description

We will need to specify more REPEAT macros if we need repeating more than 10 times.

Here's the REPEAT macro which can repeat 100 times:

#define REPEAT_1(FN) FN(0)
#define REPEAT_2(FN) REPEAT_1(FN) FN(1)
#define REPEAT_3(FN) REPEAT_2(FN) FN(2)
#define REPEAT_4(FN) REPEAT_3(FN) FN(3)
#define REPEAT_5(FN) REPEAT_4(FN) FN(4)
#define REPEAT_6(FN) REPEAT_5(FN) FN(5)
#define REPEAT_7(FN) REPEAT_6(FN) FN(6)
#define REPEAT_8(FN) REPEAT_7(FN) FN(7)
#define REPEAT_9(FN) REPEAT_8(FN) FN(8)
#define REPEAT_10(FN) REPEAT_9(FN) FN(9)
#define REPEAT_11(FN) REPEAT_10(FN) FN(10)
#define REPEAT_12(FN) REPEAT_11(FN) FN(11)
#define REPEAT_13(FN) REPEAT_12(FN) FN(12)
#define REPEAT_14(FN) REPEAT_13(FN) FN(13)
#define REPEAT_15(FN) REPEAT_14(FN) FN(14)
#define REPEAT_16(FN) REPEAT_15(FN) FN(15)
#define REPEAT_17(FN) REPEAT_16(FN) FN(16)
#define REPEAT_18(FN) REPEAT_17(FN) FN(17)
#define REPEAT_19(FN) REPEAT_18(FN) FN(18)
#define REPEAT_20(FN) REPEAT_19(FN) FN(19)
#define REPEAT_21(FN) REPEAT_20(FN) FN(20)
#define REPEAT_22(FN) REPEAT_21(FN) FN(21)
#define REPEAT_23(FN) REPEAT_22(FN) FN(22)
#define REPEAT_24(FN) REPEAT_23(FN) FN(23)
#define REPEAT_25(FN) REPEAT_24(FN) FN(24)
#define REPEAT_26(FN) REPEAT_25(FN) FN(25)
#define REPEAT_27(FN) REPEAT_26(FN) FN(26)
#define REPEAT_28(FN) REPEAT_27(FN) FN(27)
#define REPEAT_29(FN) REPEAT_28(FN) FN(28)
#define REPEAT_30(FN) REPEAT_29(FN) FN(29)
#define REPEAT_31(FN) REPEAT_30(FN) FN(30)
#define REPEAT_32(FN) REPEAT_31(FN) FN(31)
#define REPEAT_33(FN) REPEAT_32(FN) FN(32)
#define REPEAT_34(FN) REPEAT_33(FN) FN(33)
#define REPEAT_35(FN) REPEAT_34(FN) FN(34)
#define REPEAT_36(FN) REPEAT_35(FN) FN(35)
#define REPEAT_37(FN) REPEAT_36(FN) FN(36)
#define REPEAT_38(FN) REPEAT_37(FN) FN(37)
#define REPEAT_39(FN) REPEAT_38(FN) FN(38)
#define REPEAT_40(FN) REPEAT_39(FN) FN(39)
#define REPEAT_41(FN) REPEAT_40(FN) FN(40)
#define REPEAT_42(FN) REPEAT_41(FN) FN(41)
#define REPEAT_43(FN) REPEAT_42(FN) FN(42)
#define REPEAT_44(FN) REPEAT_43(FN) FN(43)
#define REPEAT_45(FN) REPEAT_44(FN) FN(44)
#define REPEAT_46(FN) REPEAT_45(FN) FN(45)
#define REPEAT_47(FN) REPEAT_46(FN) FN(46)
#define REPEAT_48(FN) REPEAT_47(FN) FN(47)
#define REPEAT_49(FN) REPEAT_48(FN) FN(48)
#define REPEAT_50(FN) REPEAT_49(FN) FN(49)
#define REPEAT_51(FN) REPEAT_50(FN) FN(50)
#define REPEAT_52(FN) REPEAT_51(FN) FN(51)
#define REPEAT_53(FN) REPEAT_52(FN) FN(52)
#define REPEAT_54(FN) REPEAT_53(FN) FN(53)
#define REPEAT_55(FN) REPEAT_54(FN) FN(54)
#define REPEAT_56(FN) REPEAT_55(FN) FN(55)
#define REPEAT_57(FN) REPEAT_56(FN) FN(56)
#define REPEAT_58(FN) REPEAT_57(FN) FN(57)
#define REPEAT_59(FN) REPEAT_58(FN) FN(58)
#define REPEAT_60(FN) REPEAT_59(FN) FN(59)
#define REPEAT_61(FN) REPEAT_60(FN) FN(60)
#define REPEAT_62(FN) REPEAT_61(FN) FN(61)
#define REPEAT_63(FN) REPEAT_62(FN) FN(62)
#define REPEAT_64(FN) REPEAT_63(FN) FN(63)
#define REPEAT_65(FN) REPEAT_64(FN) FN(64)
#define REPEAT_66(FN) REPEAT_65(FN) FN(65)
#define REPEAT_67(FN) REPEAT_66(FN) FN(66)
#define REPEAT_68(FN) REPEAT_67(FN) FN(67)
#define REPEAT_69(FN) REPEAT_68(FN) FN(68)
#define REPEAT_70(FN) REPEAT_69(FN) FN(69)
#define REPEAT_71(FN) REPEAT_70(FN) FN(70)
#define REPEAT_72(FN) REPEAT_71(FN) FN(71)
#define REPEAT_73(FN) REPEAT_72(FN) FN(72)
#define REPEAT_74(FN) REPEAT_73(FN) FN(73)
#define REPEAT_75(FN) REPEAT_74(FN) FN(74)
#define REPEAT_76(FN) REPEAT_75(FN) FN(75)
#define REPEAT_77(FN) REPEAT_76(FN) FN(76)
#define REPEAT_78(FN) REPEAT_77(FN) FN(77)
#define REPEAT_79(FN) REPEAT_78(FN) FN(78)
#define REPEAT_80(FN) REPEAT_79(FN) FN(79)
#define REPEAT_81(FN) REPEAT_80(FN) FN(80)
#define REPEAT_82(FN) REPEAT_81(FN) FN(81)
#define REPEAT_83(FN) REPEAT_82(FN) FN(82)
#define REPEAT_84(FN) REPEAT_83(FN) FN(83)
#define REPEAT_85(FN) REPEAT_84(FN) FN(84)
#define REPEAT_86(FN) REPEAT_85(FN) FN(85)
#define REPEAT_87(FN) REPEAT_86(FN) FN(86)
#define REPEAT_88(FN) REPEAT_87(FN) FN(87)
#define REPEAT_89(FN) REPEAT_88(FN) FN(88)
#define REPEAT_90(FN) REPEAT_89(FN) FN(89)
#define REPEAT_91(FN) REPEAT_90(FN) FN(90)
#define REPEAT_92(FN) REPEAT_91(FN) FN(91)
#define REPEAT_93(FN) REPEAT_92(FN) FN(92)
#define REPEAT_94(FN) REPEAT_93(FN) FN(93)
#define REPEAT_95(FN) REPEAT_94(FN) FN(94)
#define REPEAT_96(FN) REPEAT_95(FN) FN(95)
#define REPEAT_97(FN) REPEAT_96(FN) FN(96)
#define REPEAT_98(FN) REPEAT_97(FN) FN(97)
#define REPEAT_99(FN) REPEAT_98(FN) FN(98)
#define REPEAT_100(FN) REPEAT_99(FN) FN(99)

#define REPEAT(FN, N) REPEAT_##N(FN)
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
omercsp profile image
Omer • Edited

I don't want to be rude, but this isn't the way to tackle such tasks.
Macros are great, and can be extremely helpful when inlining some code or do rather complex operations on arbitrary variable types (in C; C++ has also templates for this job) and can be helpful in other places, but in general, you want to avoid using them for tasks like repeat - they are harder to program and much harder to debug. Another problem here is that the both C and generated machine code are bloated (though the compiler might optimize the latter. And lastly, this approach limits the user to the max repeats the REPEAT macro author has used (in our case - you).

Hence a somewhat more robust and simple solution is due:

#include <stdio.h>  

void my_printf(int n)
{
    printf("%d\n", n);
}

typedef void (*my_printf_t)(int);
void repeat(my_printf_t fn, int n)
{
    for (int i = 0; i < n; i++)
        fn(i);
}

int main()
{
    repeat(my_printf, 10);
}

Enter fullscreen mode Exit fullscreen mode

This solution can be both easily extended to have any function even such retrieved dynamically on runtime. Also note there's no limitation to the number of repeats. This example is very simplified, as, like the original question, it is limited to to functions with a single integer parameter (rpeating things isn't really a problem, is it? this is what loops are for), but it's enough for the point I'm trying to make. It can be used a basis for cases where this sort of programming style is actually helpful.

If we must use macros (and for discussion reference), the following snippet is, again, much shorter and with no 100 (or whatever) limit:

#define PRINTF(N) printf("%d\n", N);
#define REPEAT(FN, N) \
do \
{ \
    for (int i = 0; i < N; i++) \
    { \
        FN(i); \
    } \
} while (0)


void solution_with_macros()
{
    REPEAT(PRINTF, 50);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sgf4 profile image
Horu • Edited

I understand your point but I made this repeat macro for repeating exactly the code using the preprocessor, this example wouldn't be useful if you want to use this out of functions, for example you wouldn't be able to create 10 functions using your repeat macro.