-1

I'm trying to write a generic function in c that takes two arguments of unknown type and compares them but apparently I'm de referencing from void* to void which is a stupid thing to do but how can i cast 'a' and 'b' if i don't know what type they will be?

int compare(void* a,void* b)
{
    if(*a < *b)
    {
        return -1;
    }
    else if(*a > *b)
    {
        return 1;
    }
    return 0;
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
Serofin
  • 57
  • 1
  • 5
  • The `<` and `>` operators need to know the type of the operands, so they know how many bytes to compare. – Barmar Aug 29 '20 at 14:36
  • 1
    Have a look at [`memcmp()`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/memcmp.html) – pmg Aug 29 '20 at 14:37
  • 1
    It's not possible to do this generically. That's why `qsort()` requires the caller to provide the comparison function. – Barmar Aug 29 '20 at 14:37
  • @pmg `memcmp()` needs to know how many bytes are in the object. – Barmar Aug 29 '20 at 14:38
  • "how can i cast 'a' and 'b' if i don't know what type they will be"? You pass that responsability to the caller and replace your function with `memcmp()` ie, the caller does `memcmp(a, b, sizeof *a)` (or similar) rather than `compare(a, b)` – pmg Aug 29 '20 at 14:41
  • Is this function being passed as an argument to `qsort`? If so you know what the type is. That means for each type of list you want to sort you need to make a corresponding compare function. – dbush Aug 29 '20 at 15:00
  • the only things you can do are compare known n first bytes, or by address, latter is useless though in most cases – Antti Haapala -- Слава Україні Aug 29 '20 at 16:28

1 Answers1

0

Given that you don't know the type you can use memcmp as suggested by @pmg.

#include <string.h>
//...
int compare(void* a,void* b, size_t size)
{
    return memcmp(a, b, size); 
}

In the size argument you'd want to pass the size of the larger object if their size is different, like for instance, two strings of different length.

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

Return value:

<0 the first byte that does not match in both memory blocks has a lower value in ptr1 than in ptr2 (if evaluated as unsigned char values).

0 the contents of both memory blocks are equal.

>0 the first byte that does not match in both memory blocks has a greater value in ptr1 than in ptr2 (if evaluated as unsigned char values)

You can specify different return values if you'd like but these seem to match pretty well with what you need if you're not boud to specifically -1, 0 and 1.

Sample use case:

int x = 10;
int y = 20;

int res = compare(&x, &y, sizeof x);

res value will be <0, -1 most likely.

When you know the types simply recast those back to whatever the type of the arguments you pass to the function, let's say those are int's:

//...
if(*(int*)a < *(int*)b)
{
    return -1;
}
else if(*(int*)a < *(int*)b)
//...

Note that if this is to use as qsort compare function it does not apply because one of the arguments of qsort is precisely the type size, so you would need a compare function for each type you want to compare.

anastaciu
  • 23,467
  • 7
  • 28
  • 53