1

I have one function:

int compare(char * c1, char * c2){
...
...
}

What are the various styles in which I can write a function int ret_compare(void * item) that returns a pointer to compare?

Bruce
  • 33,927
  • 76
  • 174
  • 262

1 Answers1

6

There are two main styles, one using a typedef and one not (with two variants of the typedef). Your comparator should take constant pointers, as below:

int compare(const char *c1, const char *c2) { ... }

// Raw definition of a function returning a pointer to a function that returns an int
// and takes two constant char pointers as arguments
int (*ret_compare1(void *item))(const char *, const char *)
{
    // Unused argument - item
    return compare;
}

// More usual typedef; a Comparator2 is a pointer to a function that returns an int
// and takes two constant char pointers as arguments
typedef int (*Comparator2)(const char *, const char *);

// And ret_compare2 is a function returning a Comparator2
Comparator2 ret_compare2(void *item)
{
    // Unused argument - item
    return compare;
}

// Less usual typedef; a Comparator3 is a function that returns an int
// and takes two constant char pointers as arguments
typedef int Comparator3(const char *, const char *);

// And ret_compare3 is a function returning a pointer to a Comparator3
Comparator3 *ret_compare3(void *item)
{
    // Unused argument - item
    return compare;
}

Note that these comparators cannot be used with bsearch() and qsort() (unless you use fairly gruesome casts) because those comparators are expected to take const void * arguments.

Note, too, that for comparing strings, as opposed to single characters, the function used by qsort() or bsearch() should be similar to:

int string_comparator(const void *v1, const void *v2)
{
    const char *s1 = *(char **)v1;
    const char *s2 = *(char **)v2;
    return(strcmp(s1, s2));
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Shouldn't the argument of compare functions be void *? – Bruce Oct 21 '11 at 03:57
  • @Bruce That is the same compare function you used as an example. – pmr Oct 21 '11 at 03:59
  • 2
    The second variation of `typedef` is often overlooked. I like it because then header files can declare comparator functions as `Comparator2 compare1; Comparator2 compare2;` which makes it 100% clear that the function is meant to be used as a `Comparator2`. (Also, when passed _to_ a function, `func(Comparator2 cmp)` is the same as `func(Comprator2 *cmp)`.) – Chris Lutz Oct 21 '11 at 04:00
  • 1
    @Bruce - It depends on the API. The `qsort` API requires `int (*)(const void *, const void *)`. The API of your example code is `int (*)(char *, char *)`. The (much saner) API of this answer uses `const char *` to prevent accidental modification of the values in the comparator. – Chris Lutz Oct 21 '11 at 04:03
  • @Bruce: it depends on the context. If you're planning to use the comparators with the standard `bsearch()` or `qsort()` functions, then yes, the arguments should be `const void *` (and typically, the underlying value for string comparisons is `char **` rather than `char *`). However, since the original function was `int compare(char *c1, char *c2) { ... }`, I kept the type of the original function and added the `const` type qualifier. This would be used in custom code rather than with `qsort()`. – Jonathan Leffler Oct 21 '11 at 04:06
  • @pmr: Sorry I wanted to say ret_compare – Bruce Oct 21 '11 at 04:13
  • @Bruce: having edited your question to make the `ret_compare()` function stand out better, I edited my answer to make my `ret_compareN()` functions accept the `void *item` argument, which is unused in my skeleton code. – Jonathan Leffler Oct 21 '11 at 04:21