我正在写一个函数,它只是两个值的总和,
但这些值的C类型在参数
中指定它可以是int,unsigned int,char,unsigned char,float ...
我搜索一个解决方案来做到这一点,而不需要处理很多C代码来处理所有不同的混合情况。
要清楚代码是:
void addition(unsigned char type_data_1_uc, void *value_data_1_ptr,
unsigned char type_data_2_uc, void *value_data_2_ptr,
unsigned char type_result_uc, void *value_result_ptr)
{
/* types :
0 : TYPE_BIT
1 : TYPE_CHAR
2 : TYPE_UNSIGNED_CHAR
3 : TYPE_INT
4 : TYPE_UNSIGNED_INT
5 : TYPE_SHORT_INT
6 : TYPE_UNSIGNED_SHORT_INT
7 : TYPE_LONG
8 : TYPE_UNSIGNED_LONG
9 : TYPE_FLOAT */
/* INT + INT = INT */
if ((type_data_1_uc == 3)
&& (type_data_2_uc == 3)
&& (type_result_uc == 3))
{
*((int *) value_result_ptr) = *((int *) value_data_1_ptr) + *((int *) value_data_2_ptr);
}
/* FLOAT + FLOAT = FLOAT */
if ((type_data_1_uc == 9)
&& (type_data_2_uc == 9)
&& (type_result_uc == 9))
{
*((float *) value_result_ptr) = *((int *) value_data_1_ptr) + *((int *) value_data_2_ptr);
}
/* UNSIGNED CHAR + INT = INT */
if ((type_data_1_uc == 2)
&& (type_data_2_uc == 3)
&& (type_result_uc == 3))
{
*((int *) value_result_ptr) = *((unsigned char *) value_data_1_ptr) + *((int *) value_data_2_ptr);
}
/* ......... */
}
int main(int argc, char **argv)
{
int data_1;
int data_2;
int result;
data_1 = 26;
data_2 = 32;
addition(3, &data_1, 3, &data_2, 3, &result);
printf("result = %d\n", result);
return 0;
}
我认为使用union结构但它没有解决问题,因为union也需要静态转换:
/* UNION DATA */
union data_union
{
char tab_c[4];
unsigned char tab_uc[4];
int i;
unsigned int ui;
short int si;
unsigned short int usi;
long l;
unsigned long ul;
float f;
};
void addition(unsigned char type_data_1_uc, union data_union *value_data_1_ptr,
unsigned char type_data_2_uc, union data_union *value_data_2_ptr,
unsigned char type_result_uc, union data_union *value_result_ptr)
{
/* types :
0 : TYPE_BIT
1 : TYPE_CHAR
2 : TYPE_UNSIGNED_CHAR
3 : TYPE_INT
4 : TYPE_UNSIGNED_INT
5 : TYPE_SHORT_INT
6 : TYPE_UNSIGNED_SHORT_INT
7 : TYPE_LONG
8 : TYPE_UNSIGNED_LONG
9 : TYPE_FLOAT */
/* INT + INT = INT */
if ((type_data_1_uc == 3)
&& (type_data_2_uc == 3)
&& (type_result_uc == 3))
{
(*value_result_ptr).i = (*value_data_1_ptr).i + (*value_data_2_ptr).i;
}
/* FLOAT + FLOAT = FLOAT */
if ((type_data_1_uc == 9)
&& (type_data_2_uc == 9)
&& (type_result_uc == 9))
{
(*value_result_ptr).f = (*value_data_1_ptr).f + (*value_data_2_ptr).f;
}
/* UNSIGNED CHAR + INT = INT */
if ((type_data_1_uc == 2)
&& (type_data_2_uc == 3)
&& (type_result_uc == 3))
{
(*value_result_ptr).i = (*value_data_1_ptr).uc + (*value_data_2_ptr).i;
}
}
int main(int argc, char **argv)
{
static union data_union data_1_union;
static union data_union data_2_union;
static union data_union result_union;
memset(&data_1_union, 0, sizeof(union data_union));
memset(&data_2_union, 0, sizeof(union data_union));
data_1_union.i = 26;
data_2_union.i = 32;
addition(3, &data_1_union, 3, &data_2_union, 3, &result_union);
printf("result_union.i = %d\n", result_union.i);
return 0;
}
有什么想法解决这个问题吗?
答案 0 :(得分:4)
如果没有一些“痛苦”,你不能这样做,因为C是静态类型语言。编译器需要知道变量的类型才能生成正确的指令。大多数CPU都有不同的指令用于添加8位整数,32位整数,浮点数等。
那就是说,你当然可以改进界面:我会使用变量参数来制作原型:
typedef enum {
TYPE_BIT = 0,
TYPE_CHAR,
TYPE_UNSIGNED_CHAR,
TYPE_INT,
TYPE_UNSIGNED_INT,
TYPE_SHORT_INT,
TYPE_UNSIGNED_SHORT_INT,
TYPE_LONG,
TYPE_UNSIGNED_LONG,
TYPE_FLOAT,
} Type;
void addition(Type type, void *result, ...);
这期望使用四个参数调用,后两个参数应具有type
参数指示的类型。结果存储在result
,它应该是与参数相同类型的指针。
不确定如何表示单位值,可能是unsigned char
,但它有点无意义:单个位不是你可以用C算术的类型,所以你最终会做的就是添加更多位,然后屏蔽其中一些。在大多数机器上,你也没有指向内存中单个位的指针。
答案 1 :(得分:0)
解决此问题的惯用方法是使用宏尽可能地消除代码重复。不幸的是,其余部分必须手动完成。例如:
enum typecode {
TC_INT = 3,
TC_FLOAT = 9,
/* ... */
};
void addition(enum typecode type_data_1_uc, void *value_data_1_ptr,
enum typecode type_data_2_uc, void *value_data_2_ptr,
enum typecode type_result_uc, void *value_result_ptr)
{
#define DO_ADD(tc1, tc2, tcret, type1, type2, typeret) do { \
if (type_data_1_uc == tc1 && type_data_2_uc == tc2 \
&& type_result_uc == tcret) { \
*(typeret *)value_result_ptr = \
*(type1 *)(value_data_1_ptr) + *(type2 *)(value_data_2_ptr) \
return; \
} while (0)
/* INT + INT = INT */
DO_ADD(TC_INT, TC_INT, TC_INT, int, int, int);
/* FLOAT + FLOAT = FLOAT */
DO_ADD(TC_FLOAT, TC_FLOAT, TC_FLOAT, float, float, float);
/* UCHAR + INT = INT */
DO_ADD(TC_UCHAR, TC_INT, TC_INT, unsigned char, int, int);
/* ... */
#undef DO_ADD
/* none matched: abort() or set an error code, as appropriate */
}