C 宏如何根据参数选择不同结构体成员?
数据小许
结论
普通 if 是 C 语言的运行时条件语句。即使 ID 是常量,编译器也会检查两个分支中的成员访问。因此,把 new.x 和 new.y 放进同一个宏,再用 if (ID == 1) 区分,仍然无法通过编译。
如果 ID 在预处理时已经确定,可以通过宏拼接选择对应的专用宏,让每种结构体只展开对自身成员的访问。
按编译期 ID 选择宏
struct s1 {
int x;
};
struct s2 {
int y;
};
#define MY_MACRO(ID, TYPE) MY_MACRO_##ID(TYPE)
#define MY_MACRO_1(TYPE) do { \
TYPE new; \
new.x = 10; \
} while (0)
#define MY_MACRO_2(TYPE) do { \
TYPE new; \
new.y = 20; \
} while (0)
int main(void)
{
MY_MACRO(1, struct s1);
MY_MACRO(2, struct s2);
return 0;
}
MY_MACRO(1, struct s1) 会展开为 MY_MACRO_1(struct s1),生成对 new.x 的访问;MY_MACRO(2, struct s2) 则展开为 MY_MACRO_2(struct s2),生成对 new.y 的访问。这样,每个展开结果都只访问对应结构体中实际存在的成员。
如果 ID 是运行时值
如果 ID 只能在程序运行时确定,预处理器就无法据此选择成员。C 也没有根据结构体成员名称自动分派的机制。可以重新设计数据或接口,例如使用带标签的 union,在访问前根据标签选择对应成员;也可以为两种结构体分别编写函数,再由调用方选择要调用的函数。
宏参数 ID 应是可用于拼接的编译期标记,例如这里的 1 和 2。宏定义末尾通常不写分号,调用时再加分号。
备注:内容仅供参考。
