6

これは void* であるため、任意の型のポインターを渡すことができるはずです。コンパイラでエラーが発生するのはなぜですか?

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

3 に答える 3

6

重要なのは、比較関数が void ポインターも受け取るようにすることです。

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

コンパイラが警告を表示する理由に関する補遺:

ここで見つけたc99標準を引用するには

void へのポインターは、任意の不完全型またはオブジェクト型へのポインターとの間で変換できます。不完全型またはオブジェクト型へのポインターは、void へのポインターに変換され、再び元に戻される可能性があります。結果は元のポインタと等しくなります。

これは、次のようなコードを使用できることを意味し、コンパイラは表示されている警告を発行しません。

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

これは、次のものも機能することを意味すると推測しがちです (結局のところ、「void*」を「struct foo*」に置き換えているだけですよね?)

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

ただし、標準で許可されているように、ポインター型を void へのポインターに割り当てようとしていない(またはその逆) ため、これは警告を生成します。代わりに、 type の値を typeint (*)(struct foo*, struct foo*)の変数に代入しようとしていますint (*)(void*, void*)

もちろん、明示的なキャストでコンパイラを満足させようとすることもできます。これにより、自分が何をしているのかを知る必要があることをコンパイラに納得させることができます。しかし、そうすることで、「あいまいな」動作を呼び出した場合でも、これらの警告を受け取る特権と安全性を失います。

于 2012-05-06T19:31:27.813 に答える
3

あなたの質問はコードと一致しません。あなたのコードは、構造体ポインターを void ポインターとして渡しません。ある関数ポインタを別の関数ポインタとして渡しています。関数ポインターに互換性がないため、エラーが発生します。

構造体ポインターは暗黙的に void ポインターに変換できるため、void ポインターが予期される場所に構造体ポインターを渡すことは正当です。void ポインタと表現的に同一である必要はありません。(たとえば、構造体ポインタが void ポインタと同じサイズでないマシンもあります。)

類推により、long が予期されるときに int を渡す場合を考えてみましょう。暗黙的な変換があるため、これは正当ですが、int を受け入れる関数が long を受け入れる関数と交換可能であることを意味するものではありません。

于 2012-05-06T19:37:06.093 に答える
0

関数プロトタイプが関数が期待するものと一致しないため、関数ポインターをキャストする必要があります。

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

もちろん、その typedef は必須ではありませんが、コードはない場合よりもはるかに読みやすくなります (通常、この目的で typedef を使用することが許可されていない試験では、その typedef なしで行うだけです ;))

于 2012-05-06T19:30:22.187 に答える