Kaio1012
Kaio1012

Reputation: 25

Why does nested expanding with concatenation fail inside a C preprocessor macro?

I am currently automating the creation of multiple functions with almost the same content. This is the minimal sample of this project:

#include <stdio.h>

#define _macro_print(m) printf("Value: %x\n", test_##m);
#define _macro_var_def(m) int test_##m = m;

// Repeat macro d n-times
#define BSV_REPEAT(n, d) _BSV_REPEAT_##n(d)
#define _BSV_REPEAT_1(d) _macro_##d(0)
#define _BSV_REPEAT_2(d) _BSV_REPEAT_1(d)_macro_##d(1)
#define _BSV_REPEAT_3(d) _BSV_REPEAT_2(d)_macro_##d(2)
#define _BSV_REPEAT_4(d) _BSV_REPEAT_3(d)_macro_##d(3)

#define NUMBER_OF_TIMES 4

int main() {
    BSV_REPEAT(4, var_def)
    // NUMBER_OF_TIMES
    BSV_REPEAT(4, print)
    //BSV_REPEAT(NUMBER_OF_TIMES, print)
    return 0;
}

The actual macro behind _macro_print is a lot more complex, so it is not possible to do it at runtime with a for-loop or something similar.

In the real project I use the BSV_REPEAT macro multiple times with different macros but always with the same number of repetitions. Naturally I wanted to create a define for this number so that I can change it easily later on.

When I use the define NUMBER_OF_TIMES CLion reports the following message and the program can not longer be compiled.

My question is now how to solve this problem? Is there a way to force the evaluation of NUMBER_OF_TIMES earlier?

Upvotes: 2

Views: 105

Answers (1)

Yunnosch
Yunnosch

Reputation: 26703

You need to control the expanding order.
To do that introduce a dedicated additional layer of expanding and concatenating:

#define _macro_print(m) printf("Value: %x\n", test_##m);
#define _macro_var_def(m) int test_##m = m;

#define CONCAT(x,y) x##y
// Repeat macro d n-times
#define BSV_REPEAT(n, d) CONCAT(_BSV_REPEAT_,n)(d)
#define _BSV_REPEAT_1(d) CONCAT(_macro_,d)(0)
#define _BSV_REPEAT_2(d) _BSV_REPEAT_1(d)CONCAT(_macro_,d)(1)
#define _BSV_REPEAT_3(d) _BSV_REPEAT_2(d)CONCAT(_macro_,d)(2)
#define _BSV_REPEAT_4(d) _BSV_REPEAT_3(d)CONCAT(_macro_,d)(3)

#define NUMBER_OF_TIMES 4

int main() {
    BSV_REPEAT(4, var_def)
    NUMBER_OF_TIMES
    BSV_REPEAT(4, print)
    BSV_REPEAT(NUMBER_OF_TIMES, print)
    return 0;
}

Output of above with -E option:

int main() {
    int test_0 = 0;int test_1 = 1;int test_2 = 2;int test_3 = 3;
    4
    printf("Value: %x\n", test_0);printf("Value: %x\n", test_1);printf("Value: %x\n", test_2);printf("Value: %x\n", test_3);
    printf("Value: %x\n", test_0);printf("Value: %x\n", test_1);printf("Value: %x\n", test_2);printf("Value: %x\n", test_3);
    return 0;
}

And please shed the habit of using identifiers wich start with "_", they are reserved.

Upvotes: 2

Related Questions