如何简化计算LHS/RHS操作数表达式的嵌套switch语句?
简化动态类型比较函数的嵌套Switch实现
问题描述
我正在编写一个函数,用于计算由LHS(左操作数)、RHS(右操作数)和测试操作符构成的数学表达式结果,例如X == Y、Z > W、U < Q这类表达式,其中X、Y等可为任意标准C类型的值。
下方是该函数的初步实现,但嵌套switch语句重复度极高:
- 每种LHS类型对应结构相似的代码块,需根据RHS类型和测试操作符计算结果;
- 每种RHS类型又对应结构相似的代码块,需根据测试操作符计算结果。
这种结构不仅冗长,还极易出错。考虑到所有标准C类型(如char、int、long、float、double等)至少有14种,每个LHS类型对应至少14个RHS分支,每个分支内还有测试操作符分支,代码量极大。
我尝试用宏实现简化,但遇到无法解决的类型提升问题——需对LHS或RHS类型适当提升以避免编译器警告。请问该如何简化这类嵌套switch语句?
原实现代码:
#include <stdint.h> #include <stdbool.h> struct operand { enum op_type { u8,i8,u16,i16,u32,i32,u64,i64,f,d } type; union op_value{ uint8_t u8; int8_t i8; uint16_t u16; int16_t i16; /*etc...*/ } value; }; enum operator { equal, greater, lesser }; bool test_operands(struct operand lhs, struct operand rhs, enum operator test) { bool test_result; switch (lhs.type) { /* lhs */ case u8: /* rhs */ switch (rhs.type) { case u8: /* test */ switch (test) { case equal: test_result = lhs.value.u8 == rhs.value.u8; break; case greater: test_result = lhs.value.u8 > rhs.value.u8; break; case lesser: test_result = lhs.value.u8 < rhs.value.u8; break; } break; case i8: /* test * same as above but with rhs.value.i8 used instead */ break; case u16: /* test * need to promote lhs.value.u8 to u16 to avoid compiler warnings */ switch (test) { case equal: test_result = (uint16_t)lhs.value.u8 == rhs.value.u16; break; case greater: test_result = (uint16_t)lhs.value.u8 > rhs.value.u16; break; case lesser: test_result = (uint16_t)lhs.value.u8 < rhs.value.u16; break; } break; case i16: break; /* etc...*/ } break; /* lhs */ case i8: /* same as above but with lhs.value.i8 used instead */ break; /* etc... */ } return test_result; }
解决方案
方法1:统一类型提升到最大兼容类型
核心思路是将所有操作数转换到一个足够大的公共类型(整数用int64_t/uint64_t,浮点数用double),再在统一类型上执行比较,避免逐个类型分支处理。
#include <stdint.h> #include <stdbool.h> #include <math.h> struct operand { enum op_type { u8,i8,u16,i16,u32,i32,u64,i64,f,d } type; union op_value{ uint8_t u8; int8_t i8; uint16_t u16; int16_t i16; uint32_t u32; int32_t i32; uint64_t u64; int64_t i64; float f; double d; } value; }; enum operator { equal, greater, lesser }; // 辅助函数:将操作数转换为统一类型 double operand_to_double(struct operand op) { switch(op.type) { case u8: return (double)op.value.u8; case i8: return (double)op.value.i8; case u16: return (double)op.value.u16; case i16: return (double)op.value.i16; case u32: return (double)op.value.u32; case i32: return (double)op.value.i32; case u64: return (double)op.value.u64; case i64: return (double)op.value.i64; case f: return (double)op.value.f; case d: return op.value.d; default: return 0.0; } } bool test_operands(struct operand lhs, struct operand rhs, enum operator test) { double lhs_val = operand_to_double(lhs); double rhs_val = operand_to_double(rhs); switch(test) { case equal: return fabs(lhs_val - rhs_val) < 1e-9; // 浮点数相等需容错 case greater: return lhs_val > rhs_val; case lesser: return lhs_val < rhs_val; default: return false; } }
注意:若需要严格精确的整数比较,可拆分逻辑:先判断是否均为整数类型,用int64_t/uint64_t比较,否则用double。
方法2:使用函数跳转表
构建二维函数表(LHS类型 × RHS类型),每个表项对应类型组合的比较函数,将类型提升逻辑封装到函数中,避免嵌套switch。
#include <stdint.h> #include <stdbool.h> struct operand { enum op_type { u8,i8,u16,i16,u32,i32,u64,i64,f,d, OP_TYPE_COUNT } type; union op_value{ uint8_t u8; int8_t i8; uint16_t u16; int16_t i16; uint32_t u32; int32_t i32; uint64_t u64; int64_t i64; float f; double d; } value; }; enum operator { equal, greater, lesser }; // 定义比较函数类型 typedef bool (*CompareFunc)(struct operand lhs, struct operand rhs, enum operator test); // 具体类型组合的比较函数 bool compare_u8_u8(struct operand lhs, struct operand rhs, enum operator test) { uint8_t a = lhs.value.u8; uint8_t b = rhs.value.u8; switch(test) { case equal: return a == b; case greater: return a > b; case lesser: return a < b; default: return false; } } bool compare_u8_u16(struct operand lhs, struct operand rhs, enum operator test) { uint16_t a = (uint16_t)lhs.value.u8; uint16_t b = rhs.value.u16; switch(test) { case equal: return a == b; case greater: return a > b; case lesser: return a < b; default: return false; } } // 填充其他类型组合的比较函数... // 构建函数表 CompareFunc compare_table[OP_TYPE_COUNT][OP_TYPE_COUNT] = { [u8][u8] = compare_u8_u8, [u8][u16] = compare_u8_u16, // 填充其他表项... }; bool test_operands(struct operand lhs, struct operand rhs, enum operator test) { if(lhs.type >= OP_TYPE_COUNT || rhs.type >= OP_TYPE_COUNT) { return false; } CompareFunc func = compare_table[lhs.type][rhs.type]; return func ? func(lhs, rhs, test) : false; }
方法3:宏生成重复代码
用宏遍历所有类型组合,自动生成分支代码和类型提升逻辑,避免手动编写重复代码。
#include <stdint.h> #include <stdbool.h> struct operand { enum op_type { u8,i8,u16,i16,u32,i32,u64,i64,f,d } type; union op_value{ uint8_t u8; int8_t i8; uint16_t u16; int16_t i16; uint32_t u32; int32_t i32; uint64_t u64; int64_t i64; float f; double d; } value; }; enum operator { equal, greater, lesser }; // 定义类型对应的C类型和提升目标类型 #define TYPE_LIST \ TYPE(u8, uint8_t, uint64_t) \ TYPE(i8, int8_t, int64_t) \ TYPE(u16, uint16_t, uint64_t) \ TYPE(i16, int16_t, int64_t) \ TYPE(u32, uint32_t, uint64_t) \ TYPE(i32, int32_t, int64_t) \ TYPE(u64, uint64_t, uint64_t) \ TYPE(i64, int64_t, int64_t) \ TYPE(f, float, double) \ TYPE(d, double, double) // 宏:生成单个RHS类型的处理分支 #define GEN_RHS_CASE(LHS_ENUM, LHS_TYPE, LHS_PROMOTE) \ case LHS_ENUM: \ switch(rhs.type) { \ TYPE_LIST \ TYPE(RHS_ENUM, RHS_TYPE, RHS_PROMOTE) \ { \ case RHS_ENUM: { \ LHS_PROMOTE lhs_val = (LHS_PROMOTE)lhs.value.LHS_ENUM; \ RHS_PROMOTE rhs_val = (RHS_PROMOTE)rhs.value.RHS_ENUM; \ switch(test) { \ case equal: test_result = lhs_val == rhs_val; break; \ case greater: test_result = lhs_val > rhs_val; break; \ case lesser: test_result = lhs_val < rhs_val; break; \ } \ break; \ } \ } \ default: test_result = false; break; \ } \ break; bool test_operands(struct operand lhs, struct operand rhs, enum operator test) { bool test_result = false; switch(lhs.type) { TYPE_LIST TYPE(LHS_ENUM, LHS_TYPE, LHS_PROMOTE) { GEN_RHS_CASE(LHS_ENUM, LHS_TYPE, LHS_PROMOTE) } default: test_result = false; break; } return test_result; } // 清理宏定义 #undef TYPE #undef GEN_RHS_CASE #undef TYPE_LIST
内容的提问来源于stack exchange,提问作者user1806687
相关产品推荐
相关产品推荐

