Search code examples
carraysmemcpyqsort

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?


Solution

  • 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)