Evaluate preprocessor token before ## concatenation
Asked Answered
K

2

13

I would like to evaluate a token before it is concatenated with something else. The "problem" is that the standard specifies the behaviour as

before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.

hence in the following example,

#include <stdlib.h>

struct xy {
    int x;
    int y;
};

struct something {
    char * s;
    void *ptr;
    int size;
    struct xy *xys;
};
#define ARRAY_SIZE(a) ( sizeof(a) / sizeof((a)[0]) )

#define DECLARE_XY_BEGIN(prefix) \
struct xy prefix ## _xy_table[] = {

#define XY(x, y) {x, y},

#define DECLARE_XY_END(prefix) \
    {0, 0} \
}; \
struct something prefix ## _something = { \
    "", NULL, \
    ARRAY_SIZE(prefix ## _xy_table), \
    &(prefix ## _xy_table)[0],  \
};

DECLARE_XY_BEGIN(linear1)
    XY(0, 0)
    XY(1, 1)
    XY(2, 2)
    XY(3, 3)
DECLARE_XY_END(linear1)


#define DECLARE_XY_BEGIN_V2() \
struct xy MYPREFIX ## _xy_table[] = {

#define DECLARE_XY_END_V2() \
    {0, 0} \
}; \
struct something MYPREFIX ## _something = { \
    "", NULL, \
    ARRAY_SIZE(MYPREFIX ## _xy_table), \
    &(MYPREFIX ## _xy_table)[0],  \
};

#define MYPREFIX linear2
DECLARE_XY_BEGIN_V2()
    XY(0, 0)
    XY(2, 1)
    XY(4, 2)
    XY(6, 3)
DECLARE_XY_END_V2()
#undef MYPREFIX

The last declaration is expanded into

struct xy MYPREFIX_xy_table[] = {
 {0, 0},
 {2, 1},
 {4, 2},
 {6, 3},
{0, 0} }; struct something MYPREFIX_something = { "", 0, ( sizeof(MYPREFIX_xy_table) / sizeof((MYPREFIX_xy_table)[0]) ), &(MYPREFIX_xy_table)[0], };

and not

struct xy linear2_xy_table[] = {
 {0, 0},
 {2, 1},
 {4, 2},
 {6, 3},
{0, 0} }; struct something linear2_something = { "", 0, ( sizeof(linear2_xy_table) / sizeof((linear2_xy_table)[0]) ), &(linear2_xy_table)[0], };

like I want to. Is there some way of defining macros that produces this? The first set of macros does, but I would like to avoid the prefix duplication and only have this defined once. So is it possible to set the prefix with #define and let the macros use that?

Katherinkatherina answered 17/10, 2011 at 14:49 Comment(1)
possible duplicate of How to concatenate twice with the C preprocessor and expand a macro as in "arg ## _ ## MACRO"? Please try to minimize examples :-)Glaudia
R
4

You can use second level expansion for this, eg.

#define XY_HLP1(a) DECLARE_XY_BEGIN(a)
#define XY_HLP2(a) DECLARE_XY_END(a)
#define DECLARE_XY_BEGIN_V2() XY_HLP1(MYPREFIX)
#define DECLARE_XY_END_V2() XY_HLP2(MYPREFIX)
Regine answered 17/10, 2011 at 15:9 Comment(1)
Yes, I like this. No need to change the old macros and create possible merge problems for others, and also even if the double expantion might not be intuitively to understand it is still obvious that the same prefix is used both places.Katherinkatherina
M
14

You can use a macro for concatenation like

#define CONCAT_(A, B) A ## B
#define CONCAT(A, B) CONCAT_(A, B)

this works then

#define A One
#define B Two
CONCAT(A, B) // Results in: OneTwo
Monjan answered 17/10, 2011 at 15:10 Comment(2)
I never understood why such things require two levels. Is the first level for macro expansion, and the second one for the actual concatenation?Rossman
It is because the concatenation operator ## and the stringizing operator # in the #define directive inhibit macro expansion.Nothingness
R
4

You can use second level expansion for this, eg.

#define XY_HLP1(a) DECLARE_XY_BEGIN(a)
#define XY_HLP2(a) DECLARE_XY_END(a)
#define DECLARE_XY_BEGIN_V2() XY_HLP1(MYPREFIX)
#define DECLARE_XY_END_V2() XY_HLP2(MYPREFIX)
Regine answered 17/10, 2011 at 15:9 Comment(1)
Yes, I like this. No need to change the old macros and create possible merge problems for others, and also even if the double expantion might not be intuitively to understand it is still obvious that the same prefix is used both places.Katherinkatherina

© 2022 - 2024 — McMap. All rights reserved.