在 X 宏 C 中定义相同的元素

defining same elements in X macro C

提问人:ro88 提问时间:3/2/2023 最后编辑:ro88 更新时间:3/3/2023 访问量:82

问:

我一直在探索 X 宏,并创建了这张表

#define FAULT_TABLE(FAULT) \
FAULT(INVALID,                            FAULT_CATEGORY_NONE, action_none) \
FAULT(COMMS_FAILURE,                       FAULT_CATEGORY_1, action_1) \
FAULT(QUEUE_FAILURE,                        FAULT_CATEGORY_1, action_1) \
FAULT(SENSOR_FAILURE,                FAULT_CATEGORY_1, action_1) \
FAULT(FAILED_OP                     FAULT_CATEGORY_1, action_1) 

我只是想知道我是否可以具有相同的值并从中生成一个枚举。我的意思是表中第二列的枚举。

以及如何为上面的故障代码分配相同的函数调用

更新只是为了增加更清晰和上下文:当报告这些错误中的任何一个时,我的错误处理程序将查看要执行的类别和函数。有些故障具有相同的动作,属于同一类别。所以我试图弄清楚这是否可以通过 X 宏 .

所以我只想将枚举扩展为

typedef enum {
FAULT_CATEGORY_NONE,
FAULT_CATEGORY_1,
FAULT_CATEGORY_N,
}

此外,我会将表中定义的函数扩展为跳转表。

C X-宏

评论

0赞 Lundin 3/2/2023
只需在此 X 宏之外生成枚举即可。发布的 X 宏中没有任何内容可用于创建枚举。它似乎假设枚举已经创建。例如,你考虑过写作吗?如果不是,那为什么不呢?太简单了,太可读了?typedef enum { FAULT_CATEGORY_NONE, FAULT_CATEGORY_1, FAULT_CATEGORY_N, } my_type;

答:

1赞 John Bollinger 3/2/2023 #1

我只是想知道我是否可以具有相同的值并从中生成一个枚举。我的意思是表中第二列的枚举。

不能复制枚举常量,但可以为不同的枚举常量赋予相同的值。因此,例如,您可以这样做:

#define FAULT_CATEGORY_NONE 0
#define FAULT_CATEGORY_1 1

#define FAULT_TABLE(FAULT) \
FAULT(INVALID,                            FAULT_CATEGORY_NONE) \
FAULT(COMMS_FAILURE,                       FAULT_CATEGORY_1) \
FAULT(QUEUE_FAILURE,                        FAULT_CATEGORY_1) \
FAULT(SENSOR_FAILURE,                FAULT_CATEGORY_1) \
FAULT(FAILED_OP,                     FAULT_CATEGORY_1)

#define FAULT(x, y) x ## _CAT = (y),

enum category {
FAULT_TABLE(FAULT)
DUMMY_CAT
};

这扩展到

enum category {
    INVALID_CAT = (0),        COMMS_FAILURE_CAT = (1), QUEUE_FAILURE_CAT = (1),
    SENSOR_FAILURE_CAT = (1), FAILED_OP_CAT = (1),     DUMMY_CAT
};

(为清楚起见,添加了额外的空格)。

但我看不出 X 宏实际上是如何帮助你的。特别是,您对有关分配函数的子问题提出了不同的定义,这是可疑的。FAULT_TABLE

当您可以将同一列表(此处)重用于 () 的多个定义时,X 宏方法提供了一些牵引力。但是,您的示例似乎不太适合此,因为每种用途似乎都需要列表提供不同的数据。我想你可以通过依赖接受一个额外的参数来将它们全部塞进同一个列表中,但你最好只创建常规表。例如:FAULT_TABLEXFAULTFAULT

enum fault {
    INVALID, COMMS_FAILURE, QUEUE_FAILURE, SENSOR_FAILURE, FAILED_OP 
};

const int fault_category[] = {
    [INVALID] = FAULT_CATEGORY_NONE,
    [COMMS_FAILURE] = FAULT_CATEGORY_1,
    [QUEUE_FAILURE] = FAULT_CATEGORY_1,
    [SENSOR_FAILURE] = FAULT_CATEGORY_1,
    [FAILED_OP] = FAULT_CATEGORY_1
};

const void (*fault_action[])(void) = {
    [INVALID] = action_none,
    [COMMS_FAILURE] = action_1,
    [QUEUE_FAILURE] = action_1,
    [SENSOR_FAILURE] = action_1,
    [FAILED_OP] = action_2
};

你当然可以使用 X 宏来生成这样的代码,但我认为你不会节省太多空间,而且我认为结果会不太清楚。


关于问题更新

您似乎希望使用 X 宏方法仅在某个给定的传递列表中为宏的某个参数的每个不同值选择和生成输出。我不敢说这是不可能的,因为聪明的人已经从预处理器中挤出了一些相当令人惊讶的行为,但我有信心说,没有直接的方法可以让预处理器做到这一点X

跳转表更容易,因为您希望每次调用都有类似的输出。因此,您可能会这样做......FAULT

#define FAULT_TABLE(FAULT) \
FAULT(INVALID,                            FAULT_CATEGORY_NONE, action_none) \
FAULT(COMMS_FAILURE,                       FAULT_CATEGORY_1, action_1) \
FAULT(QUEUE_FAILURE,                        FAULT_CATEGORY_1, action_1) \
FAULT(SENSOR_FAILURE,                FAULT_CATEGORY_1, action_1) \
FAULT(FAILED_OP,                     FAULT_CATEGORY_1, action_1) 

#define ENUM_CONST(fault, cat, action)   fault,
#define ACTION_ENTRY(fault, cat, action) [fault] = action,

enum fault {
    FAULT_TABLE(ENUM_CONST)
    DUMMY_FAULT
};

const void (*fault_action[])(void) = {
    FAULT_TABLE(ACTION_ENTRY)
    0
};

但同样,我认为与直接编写枚举和跳转表相比,没有太大优势。

评论

0赞 ro88 3/2/2023
谢谢你的回答。我已经编辑了这个问题以使其更清楚.希望你现在能更好地理解它。我必须创建一个具有多个参数的故障表。我不想每次更改错误时都编写枚举或更新表
0赞 John Bollinger 3/2/2023
@ro88,我已经更新了此答案,以解决您对问题所做的更改。
0赞 Lundin 3/2/2023
小错误:应该是.或者更好的是:......void (* const fault_action[])(void)typedef void fault_action_t (void);const fault_action_t* fault_action[] = ...
1赞 John Bollinger 3/3/2023
@ro88,我在表中有零,因为否则,由于最后一个实数项后面的尾随逗号,代码无效。它实际上是一个空函数指针。有一些方法可以解决 X 宏的此类问题,但都需要以一种或另一种方式修改您的定义。fault_actionFAULT_TABLE
1赞 John Bollinger 3/3/2023
@ro88,是的,您的评论中提出的变体正是我在示例代码中通过在定义末尾包含 0 来解决的问题:初始值设定项列表中有一个尾随逗号。如果扩展到小于初始值设定项数量的数字,也可能会出现问题。fault_actionNUM_FAULTS