web-dev-qa-db-ja.com

C関数ポインター構文

私の質問はとても簡単です。

通常、変数を宣言するときは、次のように変数の前にその型を置きます。

_int a;
_

関数ポインタは、2つの整数を取り、整数を返す関数をポイントする場合、int(*)(int,int)のような型を持つことができます。しかし、そのようなポインターを宣言するとき、その識別子は次のように型の後ではありません:

_int(*)(int,int) mypointer;
_

代わりに、中央に識別子を記述する必要があります。

_int(*mypointer)(int,int);
_

これはなぜですか?申し訳ありませんが、それは恥ずかしいほど簡単な質問です...

返信してくれてありがとう。なので。

34
user1941583

配列、ポインター、および関数のC構文がこのように設計されたのはなぜですか? に対する答えでこれを説明します。

言語の作成者は、構文を型中心ではなく変数中心にすることを好みました。つまり、プログラマーに宣言を見て、「式*func(arg)を書くとintになります; *arg[N]と書くと「func」ではなく「float」があります-thisを取り、that "を返す関数へのポインタでなければなりません。

WikipediaのCエントリ は次のように主張しています:

リッチーのアイデアは、使用法に似たコンテキストで識別子を宣言することでした。「宣言は使用法を反映しています」。

... K&R2のp122を引用。

20
detly

この構造は、通常の関数の宣言方法(および使用方法)を反映しています。

通常の関数定義を考えてみましょう:

int foo (int bar, int baz, int quux);

次に、同じシグネチャの関数への関数ポインターを定義することを検討してください。

int (*foo) (int, int, int);

2つの構造が相互にミラーリングする方法に注目してください。 *foo他の何かとしてではなく、関数ポインタとして識別するのがはるかに簡単です。

15
atomicinf

関数(関数へのポインタではない)を扱っている場合、名前も中央にあります。 return-type function-name "(" argument-list ")" ...のようになります。たとえば、int foo(int)では、intが戻り型、fooが名前、intが引数リストです。

関数へのポインタはほぼ同じように機能します。戻り値の型、名前、引数リスト。この場合、_*_を追加してポインターにし、(ポインターの_*_が接頭辞であるため)括弧のペアを使用して_*_を名前にバインドする必要があります戻り型の代わりに。たとえば、int *foo(int)は、intパラメータを受け取り、intへのポインタを返すfooという名前の関数を意味します。代わりにfooにバインドされた*を取得するには、int (*foo)(int)を与える括弧が必要です。

これは、関数へのポインターの配列が必要な場合に特に見苦しくなります。このような場合、ほとんどの人はポインター型にtypedefを使用し、その型の配列を作成するのが最も簡単だと感じています:

_typedef int (*fptr)(int);

fptr array[10];
_
9
Jerry Coffin

私はいくつかの場所で関数ポインタが

int (*foo) (int a, int b);

また、いくつかの場所ではabが言及されておらず、両方とも機能しています。

そう

int (*foo) (int, int)

正しいです。

私が覚えていることがわかった非常に簡単な方法は、次のとおりです。

関数が次のように宣言されているとします:

int function (int a , int b);

Step1:関数を括弧で囲んでください:

int (function) (int a , int b);

Step2:*関数名の前にあり、名前を変更します。

int (*funcPntr) (int a , int b);

PS:この回答では、命名規則などの適切なコーディングガイドラインに従っていません。

4