Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this C syntax mean?

This is from a 'magic' array library that I'm using.

void
sort(magic_list *l, int (*compare)(const void **a, const void **b))
{
    qsort(l->list, l->num_used, sizeof(void*),
         (int (*)(const void *,const void *))compare);
}

My question is: what on earth is the last argument to qsort doing?

(int (*)(const void *, const void*))compare) 

qsort takes int (*comp_fn)(const void *,const void *) as it's comparator argument, but this sort function takes a comparator with double pointers. Somehow, the line above converts the double pointer version to a single pointer version. Can someone help explain?

like image 781
Chris Avatar asked Sep 08 '11 20:09

Chris


1 Answers

That's exactly what the cast you quoted does: it converts a pointer of type

int (*)(const void **, const void **)

to a pointer of type

int (*)(const void *, const void *)

The latter is what is expected by qsort.

Thing like this are encountered rather often in bad quality code. For example, when someone wants to sort an array of ints, they often write a comparison function that accepts pointers to int *

int compare_ints(const int *a, const int *b) {
  return (*a > *b) - (*a < *b);
}

and when the time comes to actually call qsort they forcefully cast it to the proper type to suppress the compiler's complaints

qsort(array, n, sizeof *array, (int (*)(const void *,const void *)) compare_ints);

This is a "hack", which leads to undefined behavior. It is, obviously, a bad practice. What you see in your example is just a less direct version of the same "hack".

The proper approach in such cases would be to declare the comparison function as

int compare_ints(const void *a, const void *b) {
  int a = *(const int *) a;
  int b = *(const int *) b;
  return (a > b) - (a < b);
}

and then use it without any casts

qsort(array, n, sizeof *array, compare_ints);

In general, if one expects their comparison functions to be used as comparators in qsort (and similar functions), one should implemnent them with const void * parameters.

like image 192
AnT Avatar answered Nov 06 '22 23:11

AnT