c-确保#define语句集中的唯一值



我有一组优先级不同的任务。我将优先级管理为.h文件中的#define语句:

#define PRIO_TASK_A 1
#define PRIO_TASK_B 2
#define PRIO_TASK_C 3
// ...

由于任务列表相当长,因此确保没有两个任务具有相同的优先级很容易出错。检查唯一性的最佳方法是什么?例如,以下情况不会发生:PRIO_TASK_A=4和PRIO_TASK_B=4。

这里有一个宏解决方案!免责声明,我不认为它是干净的,它依赖于__COUNTER__宏(它是gcc特定的(,这个问题听起来像是由枚举处理得更好,而且它可能会扰乱使用__COUNTER__宏的程序的任何其他区域。

这是一个带有一些解释的示例程序。


//  macro for using compile time checks
//// The "_H" Helper macro defines a unique type with the priority of the task baked into the typename
//// The __COUNTER__ macro makes this typedef name a different type from all other SA_UNIQUE_PRIO_CALLS
//// We need a helper macro so that the VAL argument can be expanded to its int literal value
#define SA_UNIQUE_PRIO_H(VAL) typedef char static_assertion_uniq_prio_##VAL[__COUNTER__]
//// This macro is what should be called - guarantees that all asserts to it at compile time take a different value
#define STATIC_ASSERT_UNIQUE_PRIO(VAL) SA_UNIQUE_PRIO_H(VAL)
//  end macro

// Define your priorities here
#define PRIO_TASK_A 1
#define PRIO_TASK_B 2
#define PRIO_TASK_C 3
#define PRIO_TASK_D 1

// check for uniqueness here.
STATIC_ASSERT_UNIQUE_PRIO(PRIO_TASK_A);
STATIC_ASSERT_UNIQUE_PRIO(PRIO_TASK_B);
STATIC_ASSERT_UNIQUE_PRIO(PRIO_TASK_C);
STATIC_ASSERT_UNIQUE_PRIO(PRIO_TASK_D);
int main() {
return 0;
}

注意-我认为您必须将STATIC_ASSERT_UNIQUE_PRIO调用放在一个c文件中,因为如果它包含在多个文件中,那么就会有冲突的typedef。

您可以使用XMacro来管理常量。这种方法允许在一个地方定义所有常量。此外,可以使用任意的常数表达式。该解决方案在C99及以上版本中工作,没有任何编译器特定的扩展。主要的缺点是所有常数的值必须适合int

#define PRIO_TASK__XMACRO(X) 
X(PRIO_TASK_A, 1) 
X(PRIO_TASK_B, 2) 
X(PRIO_TASK_C, 3) 
X(PRIO_TASK_D, 1+1)

将常量实例化为匿名枚举:

#define DECLARE_ENUM(NAME,VALUE) NAME = VALUE,
enum {
PRIO_TASK__XMACRO(DECLARE_ENUM)
};

正如Jonathan Leffler在评论中所建议的,使用switch来检测某个值是否重复。

static inline void check_unique_enums(int c) {
switch (c) {
#define CASE_ENUM(NAME, VALUE) case NAME: break;
PRIO_TASK__XMACRO(CASE_ENUM)
}
}

用gcc编译产生错误:

so.c: In function ‘check_unique_enums’:
so.c:15:32: error: duplicate case value
15 | #define CASE_ENUM(NAME, VALUE) case NAME: break;
|                                ^~~~
so.c:5:3: note: in expansion of macro ‘CASE_ENUM’
5 |   X(PRIO_TASK_D, 1+1)
|   ^
so.c:16:1: note: in expansion of macro ‘PRIO_TASK__XMACRO’
16 | PRIO_TASK__XMACRO(CASE_ENUM)
| ^~~~~~~~~~~~~~~~~
so.c:15:32: note: previously used here
15 | #define CASE_ENUM(NAME, VALUE) case NAME: break;
|                                ^~~~
so.c:3:3: note: in expansion of macro ‘CASE_ENUM’
3 |   X(PRIO_TASK_B, 2) 
|   ^
so.c:16:1: note: in expansion of macro ‘PRIO_TASK__XMACRO’
16 | PRIO_TASK__XMACRO(CASE_ENUM)
| ^~~~~~~~~~~~~~~~~

最新更新