我可以将结构传递给一个带有void *的函数吗?

时间:2012-05-06 19:28:17

标签: c data-structures structure void-pointers

因为这是一个空*我应该能够传递任何类型的指针吗?为什么编译器会给我错误?

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_ *)'

3 个答案:

答案 0 :(得分:6)

关键是让你的比较函数也采用无效指针:

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

附录,关于为什么编译器会给你警告:

引用我发现的here

的c99标准
  

指向void的指针可以转换为指向任何不完整或对象的指针   类型。指向任何不完整或对象类型的指针可以转换为指向void的指针   又回来了;结果应该等于原始指针。

这意味着你可以拥有如下代码,编译器不会发出你所看到的警告:

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

很有可能推断出这意味着以下内容也会起作用(毕竟,我们只是用“struct foo *”代替“void *”,对吗?)

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

然而,这会产生警告,因为尝试将指针类型指定给指向void的指针(反之亦然),这是标准所允许的。相反,它尝试将类型int (*)(struct foo*, struct foo*)的值分配给int (*)(void*, void*)类型的变量。

当然,可以尝试使编译器对显式转换感到满意,这使编译器相信您必须知道自己在做什么。但是这样做即使在调用“iffy”行为时也会失去获得这些警告的特权和安全性。

答案 1 :(得分:3)

您的问题与您的代码不符。您的代码不会将结构指针作为void指针传递。它将一个函数指针作为另一个传递。函数指针不兼容,因此错误。

传递结构指针是合法的,因为结构指针可以隐式地转换到void指针。它不需要在表示上与void指针相同。 (例如,有些机器的结构指针与void指针的大小不同。)

通过类比考虑在期望long时传递int的情况。这是合法的,因为存在隐式转换,但这并不意味着接受int的函数可以与接受long的函数互换。

答案 2 :(得分:0)

您需要转换函数指针,因为函数原型与函数期望的函数原型不匹配:

typedef int (cmp_f)(void *, void *));
new_hash(..., ..., (cmp_f*)cmp_func_p);

当然,typedef不是必需的,但是它使你的代码比没有你的代码更具可读性(你通常只在不允许为此目的使用typedef的考试中没有那个typedef的情况下执行;)