Search code examples
ctype-conversionvoid-pointers

In C, what is the most efficient way to do math on a void* variable


Let's say I have a function like:

void myfunc(void* x, void* y){
   for(i=0; i<n;i++)
       y[i] = x[i]+1;
}

where my goal is to take vector x, do some math and store it in y. In this scenario I know x will be memory allocated as an array of ints.

I know we can't do math directly on x as it's cast as void, but I was curious about the most efficient way around this blocker. My current method is to memcpy x to an int* temp, do my math, then memcpy to y. Obviously this is not a particularly efficient process with multiple memcpy. I'm sure there is a better way, I just don't know enough about C memory allocation rules to figure it out.


Solution

  • You can avoid the memcpy. If you wish to work with integers or bytes or whatever other type, then just do the appropriate casting, for example in case x and y refer to arrays of int:

    void myfunc(void* x, void* y){
       int *xp = x;
       int *yp = y;
    
       // By the way, what is n here? Maybe define it somewhere.
       for(size_t i = 0; i < n; i++)
           yp[i] = xp[i] + 1;
    }
    

    And in such case, you don't really need to pass them as void * at all:

    void myfunc(int* x, int* y){
       // By the way, what is n here? Maybe define it somewhere.
       for(size_t i = 0; i < n; i++)
           y[i] = x[i] + 1;
    }
    

    In general, void * is only useful when you do not care about the size and type of objects you are pointing to, or when you need to do generic operations depending on different sizes/types only known at runtime (still, always with appropriate casts).

    If you want to allow different types, then you can do something like this:

    enum Type { INT, FLOAT, /* ... */ };
    
    void myfunc(void* x, void* y, size_t n, enum Type t) {
        switch (t) {
            case INT: {
                int *xi = x;
                int *yi = y;
    
                for(size_t i = 0; i < n; i++)
                    yi[i] = xi[i] + 1;
                
                break;
            }
    
            case FLOAT: {
                float *xf = x;
                float *yf = y;
    
                for(size_t i = 0; i < n; i++)
                    yf[i] = xf[i] + 1;
                
                break;
            }
    
            // case ...: {
            // ...
            // }
        }
    }
    

    Note that this is not really good practice in C though. If you are able to know the type at compile time, then by all means just define different functions taking different types as arguments, it will be the fastest option.