Tomáš Zato Tomáš Zato - 8 days ago 7
C Question

Can I use memcmp along with qsort?

I am making C dynamic array library, kind of. Note that I'm doing it for fun in my free time, so please do not recommend million of existing libraries.

I started implementing sorting. The array is of arbitrary element size, defined as struct:

typedef struct {
//[PRIVATE] Pointer to array data
void *array;
//[READONLY] How many elements are in array
size_t length;
//[PRIVATE] How many elements can further fit in array (allocated memory)
size_t size;
//[PRIVATE] Bytes per element
size_t elm_size;
} Array;


I originally prepared this to start with the sort function:

/** sorts the array using provided comparator method
* if metod not provided, memcmp is used
* Comparator signature
* int my_comparator ( const void * ptr1, const void * ptr2, size_t type_size );
**/
void array_sort(Array* a, int(*comparator)(const void*, const void*, size_t)) {
if(comparator == NULL)
comparator = &memcmp;
// Sorting algorithm should follow
}


However I learned about
qsort
:

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


Apparently, I could just pass my internal array to
qsort
. I could just call that:

qsort (a->array, a->length, a->elm_size, comparator_callback);


But there's a catch -
qsort
's comparator signature reads as:

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


While
memcmp
's signature is:

int memcmp ( const void * ptr1, const void * ptr2, size_t type_size );


The element size is missing in
qsort
's callback, meaning I can no longer have a generic comparator function when
NULL
is passed as callback. I could manually generate comparators up to X bytes of element size, but that sounds ugly.

Can I use
qsort
(or other sorting built-in) along with
memcpy
? Or do I have to chose between built-in comparator and built-in sorting function?

Answer

A non-thread-safe way is use private global variable to pass the size.

static size_t compareSize = 0;

int defaultComparator(const void *p1, const void *p2) {
  return memcmp(p1, p2, compareSize);
}

void array_sort(Array* a, int(*comparator)(const void*, const void*, size_t)) {
    if(comparator == NULL) {
      compareSize = a->elm_size;
      comparator = &defaultComparator;
    }
    // Sorting algorithm should follow
}

You can make it thread-safe by make compareSize thread-local variable (__thread)