物質機能のポインタC
-
09-09-2019 - |
質問
あり、以下の宣言:
void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
int strcmp(char *s, char *t);
そして、どこかのプログラムは以下の通:
qsort((void**) lineptr, 0, nlines-1,
(int (*)(void*,void*))(numeric ? numcmp : strcmp));
(無視し、第三引数と numeric
).
私はこの:
(int (*)(void*,void*))(numeric ? numcmp : strcmp)
私は理解してい qsort
ることので"ポインタ機能を取得する二つの void
ポインタを返しま int
"で第4引数がどのように、上記を満たす。うようにキャストで作られているため、自由自在に二括弧が、それは非常に奇妙でいます。で機能し、この機能は"ポインタ機能を取得する二つの void
ポインタを返しま int
".ある意味がない。
(私はこのルールとタイプ type
内前の変数を推進して変数とタイプ)です。
とは思いますが間違っていても誰かがきの仕方を教えてください。を読み、何をすることにあります。
解決
何ここで起こっていることは確かにキャストです。第二のための三元を無視し、numcmpが常に使用されていることをふりをすることができます。あなたはそれが実際にある数値の種類を見てそうであれば、この質問の目的のために、機能はCの関数ポインタとして機能することができます。
(int (*)(int*,int*))
適切qsort関数で使用される。このためには、それは無効なパラメータを持っている必要があります。ここでは、すべての種類は、パラメータや戻り値の型に関しては、同じサイズを持っているので、それは他のために代用することが可能です。必要なのはすべてのことは、コンパイラを幸せにキャストされます。
(int (*)(void*,void*))(numcmp )
他のヒント
あなたはここにトリックを見逃している - 部分
(numeric ? numcmp : strcmp)
は、のの機能を選択するための三項演算子はのqsortの内部で呼び出されている使用しています。データが数値であれば、それはnumcmpを使用しています。そうでない場合には、strcmpのを使用しています。より読みやすい実装は次のようになります:
int (*comparison_function)(void*,void*) =
(int (*)(void*,void*))(numeric ? numcmp : strcmp);
qsort((void**) lineptr, 0, nlines-1, comparison_function);
あなたは、関数ポインタのキャストせずにそれを行うことができます。ここで方法のです。あなたはキャストを使用している場合は、私の経験では、ほとんどの場所で、あなたはそれが間違ってされます。
qsort()
の標準定義はconst
を含むことに注意してください。
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
の文字列比較は、2つの「char **
」値ではなく、「char *
」値が与えられることに注意してください。
私は自分のコンパレータを書きます:
#include <stdlib.h> /* qsort() */
#include <string.h> /* strcmp() */
int num_cmp(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
if (i1 < i2)
return -1;
else if (i1 > i2)
return +1;
else
return 0;
}
int str_cmp(const void *v1, const void *v2)
{
const char *s1 = *(const char **)v1;
const char *s2 = *(const char **)v2;
return(strcmp(s1, s2));
}
あなたの機能を使用してコードでキャストを書くために人々を強制すると醜いです。しないでください。
私が書いた二つの機能を標準qsort()
によって必要な関数プロトタイプと一致します。括弧が続かない関数の名前は、関数へのポインタに相当する。
あなたが関数へのポインタが表記法を使用して使用されていること、古いコード、または古いコンパイラで育った人々によって書かれたコードにあります:
result = (*pointer_to_function)(arg1, arg2, ...);
モダンなスタイルで、それは書かれます:
result = pointer_to_function(arg1, arg2, ...);
個人的に、私は明示的なデリファレンス明確に見つけることではなく、誰もが同意しています。
誰の記事は英語で書かれた記事をコードスニペットしようとしていたもの巧みな.彼の心の中にそう考えたのは良いプログラマーによる巧妙な"ワイライナー 実際、彼はコードが読あ徴作業が、長期的 必要書き換えをより明らかに似たフォルムハーパーシェルビーのコードです。
記憶の考からはBrian Kernighan:
デバッグすることがでハードを書いたり、 このコード。この場合、コードを書くとして 巧みにできるだき、 定義は十分にスマートデバッグ ます。
いくパフォーマンスが重視される符号化と実時間の期限...いまだ見られない場緻密なワーライナーが適しています。
いても正常に動作周囲の作成とチェックのasm見た場合のライナーはより良い成asm実施がいたにライナーへの使い勝手は大きく変わります。
として指摘され、
(int (*)(void*,void*))(numeric ? numcmp : strcmp)
これにより,以下のようなタイプキャスト
(int (*)(void*,void*))
の発現は
(numeric ? numcmp : strcmp)
C宣言す可能性があることが読みにくくすることが可能でを学ぶことができます。この内部やその後に出たら右に曲がり、その後一歩、右、左、右、左、などを海外にまで終了しました。せん断外の括弧の前にすべてを評価します。のためのインスタンスに型キャスト、 (*)
ることを示しますが、ポインタです。ポインタのことの中括弧でを評価し、右側を外します。 (void*,void*)
これはポインタ機能の二つのポインタを引数になります。最後に int
を示し、戻り値の型の機能です。外側の括弧この型にキャスト製。更新:より詳しい記事: に時計回りに回/スパイラル や 読書Cの宣言:ガイドのMystified.
しかし、良いニュースでは、上記して極めて有用である.しかし,知 が極めて簡単にチ:の cdecl プログラムに変換する機能からCへの英語の説明およびその逆:
cdecl> explain (int (*)(void*,void*))
cast unknown_name into pointer to function (pointer to void, pointer to void) returning int
cdecl> declare my_var as array 5 of pointer to int
int *my_var[5]
cdecl>
約権の行使どのような変数は i
?
int *(*(*i)[])(int *)
解答 rot13 についてcdeclインストール機となりますので、御了承くださいもう!):
pqrpy> rkcynva vag *(*(*v)[])(vag *)
qrpyner v nf cbvagre gb neenl bs cbvagre gb shapgvba (cbvagre gb vag) ergheavat cbvagre gb vag
pqrpy>
私はおそらく、このようにそれを読んでいました。
typedef int (*PFNCMP)(void *, void *);
PFNCMP comparison_function;
if (numeric)
{
comparison_function = numcmp;
}
else
{
comparison_function = strcmp;
}
qsort((void**) lineptr, 0, nlines-1, comparison_function);
問題の例では、明示的な場合があります。
あなたのロジックが正しいと私は思います。それは確かにメソッドのシグネチャで必要とされるタイプである「2つのボイドポインタを取得し、int型を返す関数へのポインタ」にキャスティングされています。
numcmp
とstrcmp
両方がパラメータとして2 char*
を取り、int
を返す関数へのポインタです。 qsort
ルーチンは、パラメータとして2 void*
を取り、int
を返す関数へのポインタを受け取ります。したがって、キャスト。 void*
は、汎用ポインタとして動作するので、これは安全です。さて、宣言を読んだ上へ:のは、見てみましょう。の自分ののstrcmp
の宣言ます:
int strcmp(char *, char *);
strcmp
が実際にあるように、コンパイラはそれを読みます:
int (strcmp)(char *, char *)
2つのchar *
引数をとる関数(ほとんどの場合、関数へのポインタに減衰します)。ポインタstrcmp
のタイプことである
int (*)(char *, char *)
そのため、あなたはののにキャストするために入力すると、あなたは上記を使用したいstrcmp
する互換性のある別の関数をキャストする必要があるときます。
同様に、qsort
のコンパレータの引数から2 void *
sので、奇数キャストを取る!