Оцените токен препроцессора перед ## конкатенацией - PullRequest
10 голосов
/ 17 октября 2011

Я хотел бы оценить токен, прежде чем он будет соединен с чем-то другим. «Проблема» в том, что стандарт определяет поведение как

перед повторной проверкой списка замен для получения дополнительных имен макросов заменить, каждый экземпляр ## токена предварительной обработки в замене список (не из аргумента) удаляется и предыдущая предварительная обработка токен объединяется со следующим токеном предварительной обработки.

, следовательно, в следующем примере,

#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

Последнее объявление расширено до

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], };

а не

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], };

как я хочу. Есть ли способ определения макросов, который производит это? Первый набор макросов делает, но я хотел бы избежать дублирования префикса, и это будет определено только один раз. Так можно ли установить префикс с помощью #define и позволить макросам использовать это?

Ответы [ 2 ]

12 голосов
/ 17 октября 2011

Вы можете использовать макрос для объединения как

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

тогда это работает

#define A One
#define B Two
CONCAT(A, B) // Results in: OneTwo
4 голосов
/ 17 октября 2011

Для этого вы можете использовать расширение второго уровня, например.

#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)
...