Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I pass a structure into a function that takes void*?

Since this is a void* I should be able to pass a pointer of anytype right? Why is the compiler giving me errors?

int cmp_func(void *, void *));

typedef struct word_{
  char key[WORD_SIZE];
  int *frequency;
} word;

Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *\
, void *));

int comp_function(struct word_ *word1,struct word_ *word2){
  if( word1->frequency < word2->frequency){
    return -1;
  }
  if(word1->frequency <  word2->frequency){
      return 1;
  }
  if(word1->frequency == word2->frequency){
    return 0;
  }
}


project4_functions.c:47:3: warning: passing argument 3 of 'new_hash' from incompatible pointer type [enabled by default]
hash.h:38:13: note: expected 'int (*)(void *, void *)' but argument is of type 'int (*)(struct word_ *, struct word_ *)'
like image 703
Learning C Avatar asked May 06 '12 19:05

Learning C


1 Answers

The key is to make your compare function take void pointers as well:

int comp_function(void *a, void *b){
  struct word *word1 = a;
  struct word *word2 = b;
  // Use word1 and word2 as before.
}

Addendum, concerning why the compiler is giving you warnings:

To quote the c99 standard which I found here

A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

This means that you can have code like the following, and the compiler won't issue the warning you're seeing:

void *a = NULL;
int (*f)(int a, char *b) = NULL;
a = f;
f = a;

It's tempting to extrapolate that this means the following will also work (after all, we're just substituting "void*" with "struct foo*", right?)

int (*f1)(void*, void*);
int (*f2)(struct foo*, struct foo*);
f1 = f2;

However, this generates your warning since it is not trying to assign a pointer type to a pointer to void (or vice-versa) as is allowed by the standard. Instead it is trying to assign a value of type int (*)(struct foo*, struct foo*) to a variable of type int (*)(void*, void*).

Of course, you could try to make the compiler happy with an explicit cast, which convinces the compiler that you must know what you're doing. But in doing so you lose the privilege and safety of getting these warnings even when invoking "iffy" behavior.

like image 141
Chris Rice Avatar answered Nov 15 '22 09:11

Chris Rice