Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting function pointers

I am writing a function that receives a pointer to a comparison function and an array of MyStructs and is supposed to sort the array according to the comparison function:

void myStructSort(
                  struct MyStruct *arr,
                  int size,
                  int (*comp)(const struct MyStruct *, const struct MyStruct *)) {
  qsort(arr, size, sizeof(struct MyStruct), comp);
}

Unfortunately this doesn't compile because qsort expects the comparator to receive void * arguments and not const struct MyStruct *. I thought of several bad solutions and was wondering what the correct solution is.

Option 1

Cast comp to int (*)(const void *, const void*). This compiles but is undefined behavior (see this SO question).

Option 2

Create a global variable int (*global_comp)(const struct MyStruct *, const struct MyStruct *) and set global_comp=comp inside myStructSort. Then create a function:

int delegatingComp(const void *a, const void *b) {
  return globalComp((const struct MyStruct *)a, (const struct MyStruct *)b);
}

And in myStructSort call qsort(arr, size, sizeof(struct MyStruct), delegatingComp). The problem with this is the icky global variable.

Option 3

Reimplement qsort. This is functionally safe but very bad practice.

Is there a magical perfect fourth option?

Edit

I can't change the API of myStructSort and I am compiling my code using gcc c99 -Wall -Wextra -Wvla.

like image 256
Benjy Kessler Avatar asked Aug 11 '15 13:08

Benjy Kessler


People also ask

Can you cast function pointers?

Yes, it can. This is purpose of casting function pointers, just like usual pointers. We can cast a function pointer to another function pointer type but cannot call a function using casted pointer if the function pointer is not compatible with the function to be called.

What is casting a pointer?

Using pointer casting, a pointer to one type of value can be converted to a pointer to a different type without modifying anything. But the problem here is that the result may be undefined. This happens because different types of variables have different sizes, and they are aligned differently in memory.

What does it mean to cast a pointer in C?

In the C language, casting is a construct to view a data object temporarily as another data type. When you cast pointers, especially for non-data object pointers, consider the following characteristics and constraints: You can cast a pointer to another pointer of the same IBM® i pointer type.


1 Answers

Option 2 breaks thread-safety, so I wouldn't choose that one.

Option 3 is just plain wrong as you point out. There is no reason to re-implement quicksort and potentially make a mistake.

Option 1 is UB but it will work on any sane compiler. If you choose this option be sure to add a comment.

I would also consider:

Option 4. Redesign the interface of myStructSort to take int (*)(const void *, const void*) or scrap it entirely and call qsort directly. Basically send it back to the architecht, because he made a poor design choice.

like image 59
Klas Lindbäck Avatar answered Sep 30 '22 20:09

Klas Lindbäck