As the comments suggested, the most straightforward approach would be to use qsort
and a callback for each member of the struct.
You could use the offsetof
macro to create a more generic, single callback.
The dangers of a single callback is that you have to change the function whenever the struct changes. It would also require you to create a global variable, which isn't ideal either. Of course, if you use separate callbacks, you have to create a new function, too. However, you don't have a global, and forgetting to create a new function is something that is far easier to debug and fix.
But just as an example, here's a possible approach for a generic qsort
callback:
#include <stddef.h>
static size_t member_offset;
int struct_cmp(const void *a, const void *b)
{
switch(member_offset)
{
case 0://or case offsetof(struct XYZ, a):
return ((struct XYZ *)a)->a - ((struct XYZ *) b)->a;
case offsetof(struct XYZ, b):
return strcmp(
((struct XYZ *)a)->b,
((struct XYZ *)b)->b
);
case offsetof(struct XYZ, c):
return ((struct XYZ *)a)->c - ((struct XYZ *) b)->c;
default:
fprintf(stderr, "Invalid offset value %d\n", member_offset);
exit( EXIT_FAILURE );//possible bug
}
}
int main ( void )
{
struct XYZ foo[10];//create array of structs
size_t offsets[3] = { 0, offsetof(struct XYZ, b), offsetof(struct XYZ, c)};
for (int i=0;i<3;++i)
{
member_offset = offsets[i];//omit this, and you're in trouble!
qsort(
foo,
sizeof foo,
sizeof *foo,
struct_cmp
);
}
return 0;
}
As you can already see, if the struct has, say 10 member fields, the callback is going to look like an unholy mess. Owing to using a global variable, it's also bound to be more vulnerable. Not initializing the global variable, or changing the state of the global variable while another thread is sorting...
Honestly: just add a function for each member, but perhaps create a single function where you keep the qsort
calls:
void sort_structs(struct XYZ *structs[], size_t count, size_t member_offset)
{//Pass POINTER to array
switch (member_offset)
{
case 0://same cases as above:
qsort(
*structs,
count,
sizeof *structs[0],//or **structs
a_sort_callback
);
break;
case offsetof( struct XYZ, b):
qsort(
*structs,
count,
sizeof *structs[0],
b_sort_callback
);
break;
case offsetof( struct XYZ, c):
qsort(
*structs,
count,
sizeof *structs[0],
c_sort_callback
);
break;
default:
fprintf(
stderr,
"Either %d is invalid offset, or you haven't implemented a callback"
member_offset
);
exit( EXIT_FAILURE );
}
}