Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multi-type operation function in C

Tags:

c

I'm writing a function which just make the sum of two values,

but the C type of these values is specified in parameter,

it can be int, unsigned int, char, unsigned char, float ...

I search a solution to do that without making a lot of C code to process to all different mixed cases.

To be clear the code is :

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;   

}

I have think to use the union structure but it doesn't solve the problem, because union also need to be statically casted :

/* 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;   

}

Any idea to solve this ?

like image 974
user3114142 Avatar asked Mar 03 '26 09:03

user3114142


1 Answers

You cannot do that without some "pain", since C is statically typed language. The compiler needs to know the types of variables in order to generate the proper instructions. Most CPU:s have distinct instructions for adding 8-bit integers, 32-bit integers, floats, and so on.

That said, you can certainly improve on the interface: I would use variable arguments to make the prototype:

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, ...);

This expects to be called with four arguments, the two latter of which should have the type indicated by the type argument. The result is stored at result, which should be a pointer to the same type as the arguments.

Not sure how to represent single-bit values, probably as unsigned char but it's kind of pointless: single bits is not a type that you can do arithmetic with in C so you're just going to end up doing the add with more bits, then masking some of them off. You also can't have a pointer to a single bit in memory on most machines.

like image 124
unwind Avatar answered Mar 05 '26 21:03

unwind



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!