【问题标题】:Conditional X-MACROs to align ENUMs and String用于对齐 ENUM 和字符串的条件 X-MACRO
【发布时间】:2020-03-02 07:50:00
【问题描述】:

我有一个枚举列表:

typedef enum {
     ENUM1,
     ENUM2,
     #if FLAG
     ENUM3,
     #endif
} enum_var_t;

以及相应的要对齐的字符串列表:

typedef struct { char[50] name; int val; } name_val_map_t
name_val_map_t name_val_map_table[] = {
    {.name="string1", .val=ENUM1},
    {.name="string2", .val=ENUM2},
    #if FLAG
    {.name="string3", .val=ENUM3},
    #endif
};

FLAG 是一个构建标志,为 0 或 1。 我正在尝试使用 X-Macros 根据答案 here 对齐这些:

#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, foo) IF_ ## cond (foo)
#define IF_0(foo)
#define IF_1(foo) foo

#define var_list \
X(ENUM1, "string1"), \
X(ENUM2, "string2"), \
IF(FLAG, X(ENUM3, "string3")), \

#define X(ENUMVAL, ...) ENUMVAL
typedef enum {
    var_list
}
#undef X
#define X(ENUMVAL, NAME) {.name = NAME, .val = ENUMVAL}
name_val_map_t name_val_map_table = {
var_list
}

这会导致一个错误,提示我向 IF 宏传递的参数多于声明的参数。我认为它将 X(ENUM3, "string3") 中的逗号视为 IF 的参数分隔符。 我尝试用大括号封装 X() 调用并从 IF_IMPL 中删除大括号,但这也不起作用。如果我尝试使用 ... 和 VA_ARGS 扩展 IF() 中的参数列表,我会收到预期的表达式错误。我试图避免使用 def 文件,因为这会使我的文件不可读。像我尝试的一些解决方案对于避免代码复制和可读性来说是完美的。欢迎大家指点,谢谢!

【问题讨论】:

  • X 是什么? FLAG 是什么?请附上一个minimal, reproducible example,说明您的问题中的问题。
  • X 对于任何事情来说都是一个非常糟糕的名字。当其他人看到它时,他们不会知道X 的含义或它的作用,而无需挖掘其实际实现。而那个“其他人”包括未来的你。

标签: c conditional-statements x-macros


【解决方案1】:

使用variadic macros

#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, ...) IF_ ## cond(__VA_ARGS__)
#define IF_0(foo, ...)
#define IF_1(foo, ...) foo, __VA_ARGS__

测试:

//usr/local/bin/tcc -run "$0"; exit $?
#include <stdio.h>

#define FLAG3 1
#define FLAG4 0
#define FLAG5 1

typedef struct { char *name; int val; } name_val_map_t;

#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, ...) IF_ ## cond(__VA_ARGS__)
#define IF_0(foo, ...)
#define IF_1(foo, ...) foo, __VA_ARGS__

#define var_list               \
X(ENUM1, "string1")            \
X(ENUM2, "string2")            \
IF(FLAG3, X(ENUM3, "string3")) \
IF(FLAG4, X(ENUM4, "string4")) \
IF(FLAG5, X(ENUM5, "string5")) \

typedef enum {
#define X(ENUMVAL, str) ENUMVAL,
    var_list
#undef X
} enum_var_t;

name_val_map_t name_val_map_table[] = {
#define X(ENUMVAL, NAME) { NAME, ENUMVAL },
    var_list
#undef X
    { "sentinel value", 99 }
};

int main(void){
    int x =0;
    while(name_val_map_table[x].val != 99){
        printf("%i, %s\n", name_val_map_table[x].val, name_val_map_table[x].name);
    x++;}
    return 0;
}

/* output:
    0, string1
    1, string2
    2, string3
    3, string5
*/

另一种选择是为每种情况手动创建 IF_FLAGx( X(bla, bla) ) 宏...

如果出现 MSVC 错误,另请参阅:macro specialization based on argument

【讨论】:

    【解决方案2】:

    这似乎是不必要的复杂。我会简单地这样做:

    #if FLAG 
      #define var_list       \
      X(ENUM1, "string1")    \
      X(ENUM2, "string2")    \
      X(ENUM3, "string3")    
    #else
      #define var_list       \
      X(ENUM1, "string1")    \
      X(ENUM2, "string2")    
    #endif
    

    完整示例:

    #include <stdio.h>
    
    #define FLAG 1
    
    #if FLAG 
      #define var_list       \
      X(ENUM1, "string1")    \
      X(ENUM2, "string2")    \
      X(ENUM3, "string3")    
    #else
      #define var_list       \
      X(ENUM1, "string1")    \
      X(ENUM2, "string2")    
    #endif
    
    
    typedef enum
    {
      #define X(enum_var, str) enum_var,
        var_list
      #undef X
    
      ENUM_N
    } enum_var_t;
    
    typedef struct
    {
      char name[50];
      int  val;
    } name_val_map_t;
    
    const name_val_map_t name_val_map_table[] = 
    {
      #define X(enum_var, str) { .name = str, .val = enum_var },
        var_list
      #undef X
    };
    
    int main (void)
    {
      for(size_t i=0; i<ENUM_N; i++)
      {
        printf("%d %s\n", name_val_map_table[i].val, name_val_map_table[i].name);
      }
    }
    

    【讨论】:

    • 谢谢,但我有几个条件,这只会炸毁我的代码。
    • 抱歉之前没有提到。 “FLAG”也有很多变体,那么有没有办法像我试图做的那样在一行中做到这一点?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 2012-05-24
    • 2018-01-23
    • 2014-01-19
    相关资源
    最近更新 更多