-1

I am trying to learn about void pointers and functions that have a typedef (in C). I can't seem to grasp the concept.

I have this simple code:

#include <stdio.h>

typedef int (*CompareFunc)(void*, void*);

int compareints(void *a, void *b)
{
    return a-b;
}

int comparedbls(void *a, void *b)
{
    return a-b;
}

int main()
{
    int a = 1, b = 1;

    int* ptrA = &a;
    int* ptrB = &b;

    CompareFunc test = compareints;
    printf("%d\n", test(ptrA, ptrB));


    return 0;
}

The output here is "-4". I don't understand why. I know it's some kind of casting that I'm not doing because I feel like I am subtracting addresses. I would print the values of void *a and void *b with printf("%d", a) to see what values they have, but it says it can't because a is a void pointer.

And with the CompareFunc function, would I have to make a new variable to point to every function I want? I am not quite sure in what case using a typedef on a pointer function would ever be useful. Why not just call compareints() directly? Asking because I have an assignment and can't figure out why we need to code it like this.

Any help would be appreciated. Thank you!

o.o
  • 3,563
  • 9
  • 42
  • 71
  • 1
    Use `%p` to print your `void*`s. Your output of `-4` is unsurprising and you will see why once you print the addresses. You use function pointers so that you can store or pass around pointers to functions, or interchange functions with the same signature (e.g. see stdlib's [`qsort()`](http://man7.org/linux/man-pages/man3/qsort.3.html) for an example of where they are useful) – Iskar Jarak Sep 25 '15 at 03:50
  • Thanks! That confirmed I was subtracting addresses. Never knew about `%p`, very handy. – o.o Sep 25 '15 at 03:58
  • 2
    You might find [How to sort an array of structs in C](https://stackoverflow.com/questions/8721189) and [`qsort()` function — trying to use a comparator](https://stackoverflow.com/questions/10405786/) helpful. – Jonathan Leffler Sep 25 '15 at 03:59
  • Yep they are helpful, thanks! – o.o Sep 25 '15 at 04:07

2 Answers2

2

compareints() returns the difference between two pointers, whether that was your intention or not. If not, you may want to try this:

int compareints(void *a, void *b)
{
    return *(int *)a - *(int *)b;
}

and this:

double comparedbls(void *a, void *b)
{
    return *(double *)a - *(double *)b;
}

The value resulting from how you called it is implementation defined, however, because local variables can be arranged on the stack in any order.

with the CompareFunc function, would I have to make a new variable to point to every function I want?

No. A function pointer can point to any function with the same signature as the pointer.

Typedefs of function pointers can be handy, for example, if you need to pass a comparison function to a generic sort algorithm. In your instance, function pointers are completely unnecessary.

As for casting, any pointer type is allowed to be implicitly converted into a void *, and vice versa. This is done when you call compareints(). When subtracting two pointers of the same type, a value of type ptrdiff_t is returned, which is then implicitly converted into an int when returned from compareints().


owacoder
  • 4,815
  • 20
  • 47
  • I see, so I can keep redefining test to other functions that have the same header? Thanks for the explanation! – o.o Sep 25 '15 at 03:59
  • 1
    @Maru - Right, you can assign the address of any function that takes the same arguments and returns the same value as the function pointer. – owacoder Sep 25 '15 at 04:03
  • Can you also answer the question about casting I asked below? In case, ameyCU doesn't answer. – o.o Sep 25 '15 at 04:04
1
int compareints(void *a, void *b)
{
    return a-b;
}

This returns difference between two pointers a and b .What value you get is however , implementation defined .

To get difference between their values you can do this -

int compareints(void *a, void *b)
{
    return *(int *)a-*(int *)b;
}
ameyCU
  • 16,489
  • 2
  • 26
  • 41
  • Can you explain the casting? From what I see, you are casting the void pointers to integer pointers then dereferencing? – o.o Sep 25 '15 at 04:00
  • 1
    @Maru It.s because you cant dereference `void *` . That will casue error . Because compiler don't size of object this pointer points to .Therefor , we use cast. – ameyCU Sep 25 '15 at 04:10
  • 1
    @Maru to subtract integers, instead of pointers to them, you need to dereference the pointers first... but you shouldn't try to dereference `void*` (because it could point to anything...), so instead cast it to what you know it is first. – Iskar Jarak Sep 25 '15 at 04:12
  • That makes a lot of sense. Thank you both! – o.o Sep 25 '15 at 04:12