带有连接参数的X-Macro

时间:2016-09-14 03:56:51

标签: c c-preprocessor x-macros

我使用X-Macro使用以下代码

创建枚举
#define WIDGET_OFFSETS                                                               \
     X_WIDGET_OFFSET(OFFSET_HEIGHT_WA, 1, OFFSET_HEIGHT_WB, 2, OFFSET_HEIGHT_WC, 3)  \
     X_WIDGET_OFFSET(OFFSET_WIDTH_WA,  1, OFFSET_WIDTH_WB,  2, OFFSET_WIDTH_WC,  3)  \
     X_WIDGET_OFFSET(OFFSET_LENGTH_WA, 1, OFFSET_LENGTH_WB, 2, OFFSET_LENGTH_WC, 3)


#define X_WIDGET_OFFSET(a, b, c, d, e, f) a = b,
typedef enum { WIDGET_OFFSETS } Offsets_WA_e;
#undef X_WIDGET_OFFSET

我想更多地概括一下,使X-Macro表只有四个参数。第一个参数是通用/基本名称,然后将其与其他参数连接。我已经将宏定义为以下,它试图完成刚刚显示的代码。

#define WIDGET_OFFSETS                         \
     X_WIDGET_OFFSET(OFFSET_HIEGHT_, 1, 2, 3)  \
     X_WIDGET_OFFSET(OFFSET_WIDTH_,  1, 2, 3)  \
     X_WIDGET_OFFSET(OFFSET_LENGTH_, 1, 2, 3)

#define EXPAND_NAME(x,y)   x##y
#define EXPAND_ENUM_TYPE(z) typedef enum { WIDGET_OFFSETS } Offsets_##z_e;

#define X_WIDGET_OFFSET(a, b, c, d) EXPAND_NAME(a,WA) = b,
EXPAND_ENUM_TYPE(WA)
#undef X_WIDGET_OFFSET

编译器向我提供了以下错误消息:

  

错误:'('token

)之前的预期标识符

所以,似乎我的问题出现在" EXPAND_NAME(a,WA)= b,"表达。我尝试了几种不同的方法,但迄今为止都没有。最后,理想情况下,我只想指定" WA"," WB"和#34; WC"一次而不是这里的代码的两倍。

我确实找到了类似的问题,Concatenate multiple tokens for X macro,但如果可能的话,我不想做我想做的事情。非常感谢任何有关我所做错事的见解。 感谢。

编辑:更正了第一个X-Macro定义,因为它包含复制/粘贴错误

1 个答案:

答案 0 :(得分:1)

修复第一个代码块

您的第一个示例代码应该在宏的第三行和第四行中始终使用WIDTH和LENGTH:

#define WIDGET_OFFSETS                                                               \
     X_WIDGET_OFFSET(OFFSET_HEIGHT_WA, 1, OFFSET_HEIGHT_WB, 2, OFFSET_HEIGHT_WC, 3)  \
     X_WIDGET_OFFSET(OFFSET_WIDTH_WA,  1, OFFSET_WIDTH_WB,  2, OFFSET_WIDTH_WC,  3)  \
     X_WIDGET_OFFSET(OFFSET_LENGTH_WA, 1, OFFSET_LENGTH_WB, 2, OFFSET_LENGTH_WC, 3)

#define X_WIDGET_OFFSET(a, b, c, d, e, f) a = b,
typedef enum { WIDGET_OFFSETS } Offsets_WA_e;
#undef X_WIDGET_OFFSET
#undef WIDGET_OFFSETS

省略了噪音线和重复的空白行,产生:

typedef enum { OFFSET_HEIGHT_WA = 1, OFFSET_WIDTH_WA = 1, OFFSET_LENGTH_WA = 1, } Offsets_WA_e;

修复第二个代码块

您的第二个示例存在问题,特别是使用Offsets_ ## z_e代替下面显示的Offsets_ ## z ## _e。通常最好将分号留在宏定义的末尾,并让它们在宏调用之后出现。这是一个指导方针;有很多例外。

#define WIDGET_OFFSETS                        \
     X_WIDGET_OFFSET(OFFSET_HEIGHT, 1, 2, 3)  \
     X_WIDGET_OFFSET(OFFSET_WIDTH,  1, 2, 3)  \
     X_WIDGET_OFFSET(OFFSET_LENGTH, 1, 2, 3)

#define EXPAND_NAME(x,y)   x ## _ ## y
#define EXPAND_ENUM_TYPE(z) typedef enum { WIDGET_OFFSETS } Offsets_ ## z ## _e

#define X_WIDGET_OFFSET(a, b, c, d) EXPAND_NAME(a,WA) = b,
EXPAND_ENUM_TYPE(WA);
#undef X_WIDGET_OFFSET

#define X_WIDGET_OFFSET(a, b, c, d) EXPAND_NAME(a,WB) = c,
EXPAND_ENUM_TYPE(WB);
#undef X_WIDGET_OFFSET

#define X_WIDGET_OFFSET(a, b, c, d) EXPAND_NAME(a,WC) = d,
EXPAND_ENUM_TYPE(WC);
#undef X_WIDGET_OFFSET

#undef WIDGET_OFFSETS
#undef EXPAND_ENUM
#undef EXPAND_NAME

那产生了:

typedef enum { OFFSET_HEIGHT_WA = 1, OFFSET_WIDTH_WA = 1, OFFSET_LENGTH_WA = 1, } Offsets_WA_e;

typedef enum { OFFSET_HEIGHT_WB = 2, OFFSET_WIDTH_WB = 2, OFFSET_LENGTH_WB = 2, } Offsets_WB_e;

typedef enum { OFFSET_HEIGHT_WC = 3, OFFSET_WIDTH_WC = 3, OFFSET_LENGTH_WC = 3, } Offsets_WC_e;

避免重复后缀

您担心的是后缀WA,WB和WC会在代码中重复出现,而您也不会像那样重复自己。可以解决它。一种方法是将参数传递给WIDGET_OFFSETS宏,如下所示:

#define WIDGET_OFFSETS(sx)                    \
     X_WIDGET_OFFSET(EXPAND_NAME(OFFSET_HEIGHT, sx), 1, 2, 3)  \
     X_WIDGET_OFFSET(EXPAND_NAME(OFFSET_WIDTH,  sx), 1, 2, 3)  \
     X_WIDGET_OFFSET(EXPAND_NAME(OFFSET_LENGTH, sx), 1, 2, 3)

#define EXPAND_NAME(x,y)   x ## _ ## y
#define EXPAND_ENUM_TYPE(z) typedef enum { WIDGET_OFFSETS(z) } Offsets_ ## z ## _e

#define X_WIDGET_OFFSET(a, b, c, d) a = b,
EXPAND_ENUM_TYPE(WA);
#undef X_WIDGET_OFFSET

#define X_WIDGET_OFFSET(a, b, c, d) a = c,
EXPAND_ENUM_TYPE(WB);
#undef X_WIDGET_OFFSET

#define X_WIDGET_OFFSET(a, b, c, d) a = d,
EXPAND_ENUM_TYPE(WC);
#undef X_WIDGET_OFFSET

#undef WIDGET_OFFSETS
#undef EXPAND_ENUM
#undef EXPAND_NAME

这产生以下内容,与之前相同,但WA,WB和WC仅在源中出现一次。

typedef enum { OFFSET_HEIGHT_WA = 1, OFFSET_WIDTH_WA = 1, OFFSET_LENGTH_WA = 1, } Offsets_WA_e;

typedef enum { OFFSET_HEIGHT_WB = 2, OFFSET_WIDTH_WB = 2, OFFSET_LENGTH_WB = 2, } Offsets_WB_e;

typedef enum { OFFSET_HEIGHT_WC = 3, OFFSET_WIDTH_WC = 3, OFFSET_LENGTH_WC = 3, } Offsets_WC_e;