6

重複の可能性:
K&R の例をコンパイルする際の問題

最近、私は K&R の C プログラミング言語に取り組んでいます。

セクション 5.11 では、関数へのポインターについて説明し、その例 (使用したい比較関数へのポインターを提供するクイックソートの実装) を入力した後、コンパイラーから警告が表示されます: 条件式のポインター型の不一致. (私のコンパイラは OS X 10.5.6 の gcc 4.0.1 です)

警告をトリガーする例の行は次のとおりです。

 qsort((void **) lineptr, 0, nlines-1,
      (int (*)(void*, void*))(numeric ? numcmp : strcmp));

プログラムはセグメンテーション フォールトなしで実行されますが、できる限りすべての警告を滑らかにするか、少なくともその原因を理解したいと思っています。

numcmp の関数宣言は次のようになります。

 int numcmp(char *, char *);

しかし、マンページによると、stcmp には次の署名があります。

 int strcmp(const char *s1, const char *s2);

メソッドのシグネチャがわずかに異なるため、警告は単純ですか? 警告を無視すると、どのような結果になりますか?

4

3 に答える 3

6

char* を void* に暗黙的にキャストすることはできますが、これらの型の関数ポインターに対して同じことを行うことはできません (警告なしで)。コンパイラは、関数シグネチャでの型の一致により注意を払います。

qsort 内で起こっていることは言うまでもありません。つまり、void* は numcmp では char* にキャストされ、strcmp では const char* にキャストされます。

これらの場合、コンパイラは警告を発行する必要があります。パラメータと同じ型を持たない関数を実際に使用する必要がある場合は、型に一致するラッパー関数を使用し、元の関数を呼び出すときに適切な明示的なキャストを行う必要があります。

例えば:

static int strcmp_wrapper(void* s1, void* s2) {
  return strcmp((char*)s1, (char*)s2);
}

static int numcmp_wrapper(void* n1, void* n2) {
  return numcmp((char*)n1, (char*)n2);
}

qsort((void **) lineptr, 0, nlines-1,
      (numeric ? numcmp_wrapper : strcmp_wrapper));

また、qsort の最新の署名は次のとおりです。

void
qsort(void *base, size_t nel, size_t width,
      int (*compar)(const void *, const void *));

の問題はconstあなたの質問には関係ないようですが、K&R にはありませんでしたconst

于 2009-03-20T04:57:19.937 に答える
4

簡単な答え: K&R は C を知りませんでした。

長い答え: 彼らは始めたとき、誰もC を知らなかったという事実によってハンディキャップを負っていました。

(少し)長い答えの軽快な形式:K&Rが書かれて以来、言語はかなり進化しました(変更されたと言う人もいます)が、動的な例のモーフィングを備えた電子書籍版を入手しない限り、あなたのコピーの例K&R は、「新しく承認された」(「ANSI がさらに増えた!」) 言語に追いついていないでしょう。

于 2009-03-20T04:52:50.897 に答える
1

診断を試みて診断する 1 つの方法は、式を ?: の 2 つのうちの 1 つだけに置き換えるとどうなるかを確認することです。

numcmp ではなく strcmp でのみ発生する場合は、const char* が原因である可能性が非常に高くなります。char* は常に void* に変換できますが、const char* を void* に「安全に」変換することはできないと思います。

両方の場合、これはおそらく関数ポインタの問題であり、char* を void* に変換すると機能しますが、シグネチャは同一である必要があり、char ではなく void が問題になります。

于 2009-03-20T04:51:30.230 に答える