[英]C MacroMagic - Struct Definition
我正在寻找定义结构的解决方案,用户可以在示例中启用/禁用结构成员(伪代码):
#define DEF_STRUCT_1(NAME,VAL1,VAL2) \
struct my_struct_t \
{ \
#if(NAME == TRUE) \
bool name; \
#endif \
#if(VAL1 == TRUE) \
bool val1; \
#endif \
#if(VAL2 == TRUE) \
bool val2; \
#endif \
} instance1
void main() {
DEF_STRUCT_1(TRUE,FALSE,TRUE);
instance1.name = true;
//instance1.val1 = false; // error, unavailable
instance1.val2 = false;
}
我不确定这有什么用,但是以下内容可以满足您的要求:
#define CONDITIONAL_TRUE(code) code
#define CONDITIONAL_FALSE(code)
#define DEF_STRUCT_1(NAME,VAL1,VAL2) \
struct my_struct_t \
{ \
CONDITIONAL_##NAME(bool name;) \
CONDITIONAL_##VAL1(bool val1;) \
CONDITIONAL_##VAL2(bool val2;) \
} instance1
int main() {
DEF_STRUCT_1(TRUE,FALSE,TRUE);
instance1.name = true;
//instance1.val1 = false; // error, unavailable
instance1.val2 = false;
}
所有TRUE
/ FALSE
参数都必须在编译时可用。 而且,如果您希望在同一程序中使用这些参数的多个版本,则还应该使结构名称成为参数。
由于您说这是针对库的,因此尚不清楚如何规划库代码以能够访问此结构,因为它需要知道哪些成员可用。 这大大降低了该方法的实用性。
库使用的更常见方法是拥有一个config.h文件,该文件可由库用户编辑,并带有#define USE_NAME_MEMBER 1
定义。 然后,您可以使用#if
指令进行普通的struct
定义:
//in mylibrary.h:
#include <mylibrary_config.h>
struct my_struct_t {
#if USE_NAME_MEMBER
bool name;
#endif
/...
};
然后,您还将在访问该name
成员的任何库代码周围放置#if
指令。
鉴于在某些情况下需要在编译时生成不同的结构,因此您将面临一个问题,即所有使用该结构的代码都需要进行相应的修改。 编译器开关( #ifdef FOO .... #endif
)往往会随着扩展的复杂性而严重扩展。 如果有大量的struct成员,则所有需要的编译器开关都将使程序造成可怕的,无法维护的混乱。
有一种众所周知的设计模式,称为“ X宏”,可用于将程序中的维护集中到一个位置,并允许在编译时迭代涉及的所有项目。 它们也使代码难以阅读,因此它们是最后的选择。 但是它们有点实际标准,并且它们的丑陋程度并不会随着复杂性而扩展,因此它们比某些编译器转换疯狂更为可取。 它是这样的:
#define INSTANCE_LIST \
/* name, type */ \
X(name, bool) \
X(val1, bool) \
X(val2, bool) \
typedef struct
{
#define X(name, type) type name;
INSTANCE_LIST
#undef X
} instance_t;
这段代码被预处理为:
typedef struct
{
bool name;
bool val1;
bool val2;
} instance_t;
唯一需要维护的部分是“ INSTANCE_LIST”。 通过注释掉列表中的一行,该结构成员将消失。 这意味着所有使用该结构的代码都必须相应地使用相同的列表。 例如,让我们在同一示例中添加代码,该代码列出每个成员的init值,然后对其进行设置:
#include <stdbool.h>
#include <stdio.h>
#define INSTANCE_LIST \
/* name, type, init */ \
X(name, bool, true) \
X(val1, bool, false) \
X(val2, bool, false) \
typedef struct
{
#define X(name, type, init) type name;
INSTANCE_LIST
#undef X
} instance_t;
int main (void)
{
instance_t inst;
#define X(name, type, init) inst.name = init;
INSTANCE_LIST
#undef X
printf("%d ", inst.name);
printf("%d ", inst.val1);
printf("%d ", inst.val2);
}
非常灵活且易于维护-您可以轻松添加更多的结构成员,而无需更改列表以外的任何其他宏。 但是如前所述,不利的一面是该代码看起来很神秘,尤其是对于那些不习惯这种设计模式的人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.