我正在尝试简化数组的声明,但遇到了我正在使用的预处理器的问题。我的初始代码如下所示:
#define REQ_ENTRY(parm_1, parm_2) \
#if defined(parm_1) \
{ parm_1, parm_2 }, \
#endif
typedef struct {
int parm1,
parm2;
} MyTypedef_t;
static const MyTypedef_t MyList[] =
{
REQ_ENTRY( ID_1, 1 )
REQ_ENTRY( ID_2, 2 )
REQ_ENTRY( ID_3, 3 )
REQ_ENTRY( ID_4, 4 )
REQ_ENTRY( ID_5, 5 )
};
当然,构建失败了,错误消息为"错误:'#'后面没有宏参数"。这里解释了这个原因(Why compiler complain about this macro declaration)
基本上,我试图避免将数组声明为如下,这确实有效:
static const MyTypedef_t MyList[] =
{
#if defined (ID_1)
{ ID_1, 1 },
#endif
#if defined (ID_2)
{ ID_2, 2 },
#endif
#if defined (ID_3)
{ ID_3, 3 },
#endif
#if defined (ID_4)
{ ID_4, 4 },
#endif
#if defined (ID_5)
{ ID_5, 5 },
#endif
};
列表可能相当长,具体取决于项目的构建类型。我曾尝试过使用x-macros,但我想我会遇到同样的问题。我希望有人可能会看到一种方法来创建预处理器宏,以便我可以实现原始的糖语法?非常感谢任何见解。
答案 0 :(得分:5)
没有很好的清洁解决方案。但是存在各种丑陋的解决方案。
如果您不介意在宏定义中同时包含 id 和序列,可以这样解决:
#define CONCAT2(x,y) x##y
#define CONCAT(x,y) CONCAT2(x,y)
#define REQ_ENTRY_YES(p1, p2) { p1 , p2 }
#define REQ_ENTRY_NO(p1)
#define IS_PAIR_HELPER(a, b, c, ...) c
#define IS_PAIR(...) IS_PAIR_HELPER(__VA_ARGS__, YES, NO)
#define REQ_ENTRY(pair) CONCAT(REQ_ENTRY_, IS_PAIR(pair))(pair)
#define ID_1 78723649, 1
#define ID_3 2347602, 3
typedef struct {
int parm1,
parm2;
} MyTypedef_t;
static const MyTypedef_t MyList[] =
{
REQ_ENTRY( ID_1 )
REQ_ENTRY( ID_2 )
REQ_ENTRY( ID_3 )
REQ_ENTRY( ID_4 )
REQ_ENTRY( ID_5 )
};
使用-std=c11 -Wall -E
运行gcc,并仅显示MyList
定义:
static const MyTypedef_t MyList[] =
{
{ 78723649 , 1 }
{ 2347602 , 3 }
};
你可以在#define ID_x
宏中使用任何第二个值来做同样的事情,只要有一个;真实参数可以添加到REQ_ENTRY
。但这需要一些额外的麻烦。
答案 1 :(得分:3)
遗憾的是,defined
运算符仅在#if
和#ifelse
的上下文中可用,但不适用于宏扩展。就目前而言,我同意rici关于不同丑陋的解决方案。
这是一个解决方案,要求定义的值被括号括起来。然后,您可以将ID用作常规值,也可以将其传递给DEF
,当宏在括号中时,它会扩展为1或者如果不是则扩展为0。 (这是我学会了here的一招。)
借助DEF
宏,您可以创建扩展或忽略给定定义的辅助宏:
/* Auxiliary macros */
#define M_CHECK(...) M_CHECK_(__VA_ARGS__)
#define M_CHECK_(a, b, ...) b
#define M_IS_PAREN(x) M_CHECK(M_IS_PAREN_ x, 0)
#define M_IS_PAREN_(...) 1, 1
#define M_CONCAT(a, b) M_CONCAT_(a, b)
#define M_CONCAT_(a, b) a ## b
/* Conditional definition macros */
#define DEF(x) M_IS_PAREN(x)
#define DEF_IF_0(id, def)
#define DEF_IF_1(id, def) {id, def},
#define COND_DEF(x, y) M_CONCAT(DEF_IF_, DEF(x))(x, y)
/* Implementation */
#define ID_1 (27)
#define ID_3 (28)
#define ID_4 (29)
static const MyTypedef_t MyList[] = {
COND_DEF(ID_1, 1)
COND_DEF(ID_2, 2)
COND_DEF(ID_3, 3)
COND_DEF(ID_4, 4)
COND_DEF(ID_5, 5)
};
这将产生:
static const MyTypedef_t MyList[] = {
{(27), 1},
{(28), 3},
{(29), 4},
};
您还可以在代码中使用DEF
宏,该代码将扩展为0或1:
printf("ID_1 is %s.\n", DEF(ID_1) ? "defined" : "undefined");
答案 2 :(得分:1)
这是我在不引入冗余的情况下能够得到的最接近的结果:
#define PREPROCESSOR_IF #if
#define PREPROCESSOR_ENDIF #endif
#define PREPROCESSOR_NEWLINE /*
*/
#define REQ_ENTRY(parm_1, parm_2) \
PREPROCESSOR_IF defined(parm_1) PREPROCESSOR_NEWLINE \
{ parm_1, parm_2 }, PREPROCESSOR_NEWLINE \
PREPROCESSOR_ENDIF
typedef struct {
int parm1,
parm2;
} MyTypedef_t;
static const MyTypedef_t MyList[] =
{
REQ_ENTRY( ID_1, 1 )
REQ_ENTRY( ID_2, 2 )
REQ_ENTRY( ID_3, 3 )
REQ_ENTRY( ID_4, 4 )
REQ_ENTRY( ID_5, 5 )
};
您只需要使用 -E
和 -CC
运行一次预处理器,然后编译第一次预处理器传递的结果,但是由于(例如)它不起作用
#if defined (ID_1) /*
*/ { ID_1, 1 }, /*
*/ #endif
不被预处理器识别为不同的行,因为注释仅被一个空格替换。
我能够想出一个使用冗余的解决方案,但它并不比你提出的更好(每次都写出整个语句):
#define PREPROCESSOR_IF #if
#define PREPROCESSOR_ENDIF #endif
#define PREPROCESSOR_DEFINE #define
#define PREPROCESSOR_NEWLINE /*
*/
#define REQ_ENTRY_1(parm_1, parm_2) PREPROCESSOR_IF defined(parm_1)
#define REQ_ENTRY_2(parm_1, parm_2) { parm_1, parm_2 },
#define REQ_ENTRY_3(parm_1, parm_2) PREPROCESSOR_ENDIF
PREPROCESSOR_DEFINE ID_1 (27)
PREPROCESSOR_DEFINE ID_3 (28)
PREPROCESSOR_DEFINE ID_4 (29)
typedef struct {
int parm1,
parm2;
} MyTypedef_t;
static const MyTypedef_t MyList[] =
{
REQ_ENTRY_1( ID_1, 1 )
REQ_ENTRY_2( ID_1, 1 )
REQ_ENTRY_3( ID_1, 1 )
REQ_ENTRY_1( ID_2, 2 )
REQ_ENTRY_2( ID_2, 2 )
REQ_ENTRY_3( ID_2, 2 )
REQ_ENTRY_1( ID_3, 3 )
REQ_ENTRY_2( ID_3, 3 )
REQ_ENTRY_3( ID_3, 3 )
REQ_ENTRY_1( ID_4, 4 )
REQ_ENTRY_2( ID_4, 4 )
REQ_ENTRY_3( ID_4, 4 )
REQ_ENTRY_1( ID_5, 5 )
REQ_ENTRY_2( ID_5, 5 )
REQ_ENTRY_3( ID_5, 5 )
};
这确实使用上述两步编译过程按需要编译。