繁体   English   中英

C MacroMagic-结构定义

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM