如何通过运行时变量索引访问C语言中按序列定义的宏常量
不能直接通过运行期变量用宏拼接的方式访问对应值,原因你已经提到了,宏的所有处理(包括令牌拼接##)都发生在编译前的预处理阶段,此时运行期变量的取值完全未知,TEST(i)会被直接拼接为TESTi,而你的代码里没有定义这个宏,自然会报错。
下面是比switch分支扩展性更好的实现方案:
方案1:静态数组映射(适合序号连续的场景)
你当前的序号是0~9连续取值,直接做一个常量数组做映射是性能最高、实现最简单的方案:
// 预编译阶段就完成数组初始化 static const int test_map[] = {TEST0, TEST1, TEST2, TEST3, TEST4, TEST5, TEST6, TEST7, TEST8, TEST9}; // 运行期直接用下标访问,注意加边界校验避免越界 int get_test_val(int idx) { if (idx < 0 || idx >= sizeof(test_map)/sizeof(test_map[0])) { // 自定义错误处理,比如返回-1 return -1; } return test_map[idx]; }
访问的时候直接调用get_test_val(idx)即可,比switch写法简洁得多。
方案2:X宏(扩展性最优,适合需要频繁增删宏的场景)
如果后续需要频繁新增TEST类的宏,不想每次新增都手动改数组/switch代码,可以用X宏技巧实现一次定义多处复用:
首先统一维护所有序号列表:
#define TEST_ID_LIST \ X(0) \ X(1) \ X(2) \ X(3) \ X(4) \ X(5) \ X(6) \ X(7) \ X(8) \ X(9)
通过这个列表自动生成映射数组,完全不用手动写每个元素:
static const int test_map[] = { #define X(id) [id] = TEST##id, TEST_ID_LIST #undef X };
后续需要新增TEST10,只需要在TEST_ID_LIST里加一行X(10)即可,映射数组会自动同步新增TEST10的取值,没有冗余代码,可扩展性极强。
序号不连续的适配方案
如果序号不是连续的整数,可以把映射表改成结构体数组,用标准库的bsearch做二分查找,性能也远高于长switch分支:
typedef struct { int id; int val; } TestMap; static const TestMap test_map[] = { #define X(id) {id, TEST##id}, TEST_ID_LIST #undef X }; // 调用bsearch前先对数组按id排序即可
内容的提问来源于stack exchange,提问作者Lolo
相关产品推荐
相关产品推荐

