6

このコードを3つの異なる関数呼び出しセマンティクスで検討します。

void f(void){
   puts("OK");
}

int main(void){
   f();
  (*f)();
  (&f)();

  return 0;
}

1つ目は、fを呼び出す標準的な方法です。

2つ目は、関数ポインターを逆参照するためのセマンティクスです。

しかし、3番目では、関数名に&演算子を適用しており、正常に機能しているようです。

2番目と3番目のケースでは何が起こりますか?

ありがとう。

4

2 に答える 2

9

関数呼び出しは、常に関数ポインターを介して実行されます。C99 セクション 6.5.2.2 から:

呼び出された関数を表す式は、関数へのポインタ型を持つ必要があります。

ただし、ほとんどの場合、関数型は関数ポインタ型に崩壊します。C99 セクション 6.3.2.1 から:

sizeof演算子または単項演算子のオペランドである場合を除き、型が「関数を返す&」の関数指定子は、型が「関数を返すへのポインタ」の式に変換されます。

したがって、3 つの呼び出しは次のように評価されます。

(&f)();
(&(*(&f)))();
(&f)();

すべて有効です。しかし、明らかに、最初のもの ( f()) が最もクリーンで読みやすいです。

于 2012-06-24T17:50:13.907 に答える
1

2 番目のケースでは、関数ポインタを使用しています。関数ポインターは、関数への参照を記憶し、呼び出しの他の場所で呼び出すことができるようにするために使用されます。これらは通常、コールバックを実装するために使用されます。したがって、関数へのポインターを格納している場合は、最初の表記を使用する必要があります。

1番目と3番目は同等だと思います。実際、関数ポインタを宣言すると、次の両方の方法で初期化できます。

void AFunction();
void (*funcPtr)() = NULL;

funcPtr = AFunction; 
funcPtr = &AFunction;
于 2012-06-24T17:52:00.627 に答える