C中的多类型操作功能

时间:2013-12-18 07:59:54

标签: c

我正在写一个函数,它只是两个值的总和,

但这些值的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;   

}

有什么想法解决这个问题吗?

2 个答案:

答案 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 */
}