cstringmacros

Macro's depth in C


Is there a limit to macro's depth in C?

I wrote a macro to stringify n macro arguments by calling a string##n macro. However, when I try to use it in another macro it seems to not evaluate propery.

E.g.

#include <stdint.h>

#define NARGS(ARGS...) NARGS_HELPER1(ARGS, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define NARGS_HELPER1(ARGS...) NARGS_HELPER2(ARGS)
#define NARGS_HELPER2(X1, X2, X3, X4, X5, X6, X7, X8, X9, N, ...) N

#define STRINGIFY(N, ARGS...) STRING##N(ARGS)
#define STRING1(X1) {#X1}
#define STRING2(X1, X2) {#X1, #X2}
#define STRING3(X1, X2, X3) {#X1, #X2, #X3}
#define STRING4(X1, X2, X3, X4) {#X1, #X2, #X3, #X4}
#define STRING5(X1, X2, X3, X4, X5) {#X1, #X2, #X3, #X4, #X5}
#define STRING6(X1, X2, X3, X4, X5, X6) {#X1, #X2, #X3, #X4, #X5, #X6}
#define STRING7(X1, X2, X3, X4, X5, X6, X7) {#X1, #X2, #X3, #X4, #X5, #X6, #X7}
#define STRING8(X1, X2, X3, X4, X5, X6, X7, X8) {#X1, #X2, #X3, #X4, #X5, #X6, #X7, #X8}
#define STRING9(X1, X2, X3, X4, X5, X6, X7, X8, X9) {#X1, #X2, #X3, #X4, #X5, #X6, #X7, #X8, #X9}

#define CLOSURE(NAME, ARGS...)                                                 \
const uint8_t NAME##_args_n = NARGS(ARGS);                                     \
const char *NAME##_args_types[NARGS(ARGS)] = STRINGIFY(NARGS(ARGS), ARGS)

CLOSURE(func, int, float, char);

Upon calling the CLOSURE macro I get some garbage value at STRINGIFY evaluation:

const uint8_t func_args_n = 3;
const char *func_args_types[3] = STRINGNARGS(int, float, char)(int, float, char);

Also interesting to me is why parenthesis around ARGS vanish, and why arguments appear to be duplicated?


Solution

  • Is there a limit to macro's depth in C?

    There are implementation limits in C preprocessor implementations, and there are constraints specified in the C Standard, but these are not causing your problem.

    The problem is in the macro #define STRINGIFY(N, ARGS...) STRING##N(ARGS):

    For the token sequence substituted for N to be expanded before token pasting is applied by ##, you must use an intermediary macro and pass STRING and N as macro arguments:

    #define CONCAT(a,b) a##b
    #define STRINGIFY(N, ARGS...) CONCAT(STRING,N)(ARGS)
    

    This might not suffice for your goal but should help achieve it.