Home > Net >  How to make C functions agnostic to data type
How to make C functions agnostic to data type

Time:06-02

I have been working on a simple library in C to handle arrays, dynamic arrays and linked lists. As a starting point I have been working on a function to pop a user defined index from an array. For starters I am working an an integer array and came upon this solution.

int pop_int_array(int *array, int index, int size) {
    int type = sizeof(int);
    if (index >= size) return 0;
    unsigned char *dst = (unsigned char*) array   index   type;
    memmove(dst, dst   type, type * (size - index - 1));
    return 1;
}

int main(int argc, const char * argv[]) {
    int a[5] = {1, 2, 3, 4, 5};
    pop_int_array(a, 2, 5);
    for (int i = 0; i < 4; i  ) {
        printf("%d\n", a[i]);
    }
}

This yields the following output as expected

1
2
4
5

If I wanted to pop a float array, I would need to create a new function titled pop_float_array that copied all of the contents from pop_int_array but instead of using int type = sizeof(int) I would replace it with int type = sizeof(float), and of course the array data type would be a float instead of an int. However, this violates a core principle of software development by repeating the same code several times, where each time would be an implementation for a data type. In order to get around this I re-wrote the function in the following way where the array is declared as a void data type. In addition I cast the array to a void * in the main program before or during the process of passing it to the function.

int pop_array(void *array, int index, int size, int type) {
    if (index >= size) return 0;
    unsigned char *dst = (unsigned char*) array   index   type;
    memmove(dst, dst   type, type * (size - index - 1));
    return 1;
}

int main(int argc, const char * argv[]) {
    int a[5] = {1, 2, 3, 4, 5};
    pop_array((void *)a, 2, 5);
    for (int i = 0; i < 4; i  ) {
        printf("%d\n", a[i]);
    }

    float b[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
    pop_array((void *)a, 2, 5);
    for (int i = 0; i < 4; i  ) {
        printf("%f\n", a[i]);
    }
}

As expected this yields

1
2
4
5

1.1
2.2
4.4
5.5

This allows me to only create and maintain one function. However, this seems so simple that I am surprised it is not a more widely used technique, or at least that I am aware of in my little experience. Is there some consequence of writing the function this was or casting the array to a void * that I am not seeing, or is this a legitimate way to make a function type agnostic in C?

CodePudding user response:

The way you're doing this is fine. But you do have one mistake:

unsigned char *dst = (unsigned char*) array   index   type;

You're not moving up by the right amount. This should be:

unsigned char *dst = (unsigned char*) array   (index * type);

Also, you don't need to cast to void * when you call the function:

pop_array(a, 2, 5, sizeof(int));

This technique is used in the qsort function which can sort an array of an arbitrary type. It's signature is as follows:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

As with your function, it takes a void * to the start of the array as well as the number of elements and the size of each element. It also takes a function pointer whose job is to perform the type specific comparison.

  • Related