2012-02-17 24 views
22
#include<stdio.h> 
#include<stdlib.h> 

int fun1() 
{ 
    printf("I am fun1."); 
    return 0; 
} 

int fun2(int fun()) 
{ 
    fun(); 
    return 0; 
} 

int main() 
{ 
    fun2(fun1); 
    return 0; 
} 

上記のプログラムを実行できます。私にとっては、int fun2(int (*fun)())を理解することができますが、私はどのようにint fun2(int fun())が動作するのか分かりません。ありがとうございました。関数宣言の関数へのポインタについて

+3

C、C99 Strict、C++ 03およびC++ 11で有効です。そして私は驚いています。 –

答えて

32

、パラメータint fun()が、それはこのとまったく同じになり、int (*fun)()に変換:あなたが関数のパラメータとして宣言する場合

int fun2(int (*fun)()); 

よりfamiiar変換が配列の場合に起こります。あなたはこのしている場合たとえば、:ここでも

int f(int a[100]); 

をパラメータタイプはint*に変換し、それはこのようになります。

int f(int *a); 

関数型と配列型は、関数ポインタに変換する理由型、およびポインタ型はそれぞれ、標準で関数と配列を関数に渡すことを許可していないため、関数から関数と配列を返すこともできません。どちらの場合も、ポインタバージョンに崩壊します。

C++ 03標準は13.1/3で述べている(それはまた、C++ 11と同じである)、1つだけ異なる

パラメータ宣言は、関数型と他のです同じ関数型へのポインタです相当です。あるは、関数型は、関数型(8.3.5)へのポインタになるように調整されます。

そして、もっと興味深い議論はここにある:

+2

+1配列との類似性については、 – asaelr

+4

良い答え。また、私はこれがうまくいったのかどうかわからなかった! –

+0

ありがとうございます。私は長い間混乱してきました。 – dragonfly

6

int fun2(int (*fun)())およびint fun2(int fun())は全く同じです。関数型から関数型の引数を宣言すると、コンパイラはそれを同じ関数型へのポインタであるかのように使用します。低いレベル(およびx86ベースのアーキテクチャで)でそれを見ると

-3

int fun2(int fun()) 

int型の楽しい()のアドレスがスタックにプッシュし、fun2()関数に渡されます。

int fun2(int (*fun)()) 

int型の楽しい()ポインタアドレスがスタックにプッシュし、fun2()関数に渡されます。

結果は同じですが、2番目のものではfun()のアドレスを参照渡しし、最初のものは値渡しにします。あなたがint fun2(int fun())を書くとき

+0

関数のアドレスと関数のポインタアドレスの違いは何ですか?または、「ポインタアドレス」という語句はどういう意味ですか? –

+0

ポインタアドレスでは、私は*** p *を意味します。すなわち、関数のアドレスへのポインタのアドレス。 – m0skit0

+0

_ ** p_はどういう意味ですか? 2度間接参照されて2回転記されるようなものですか?関数へのポインタのアドレスは 'int(* fnptr)();のようになります。 int(** p)()= &fnptr; 'しかし、そのような質問には何も表示されませんか? –

3

これら二つの関数定義は、Cに等価です:

int fun2(int fun()) { ... } 

int fun2(int (*fun)()) { ... } 

最初の関数では、パラメータは関数ポインタに調整されます。 「『』関数復帰型 『としてパラメータの宣言』は6.3のように、 『』タイプを返す関数へのポインタ 『』に調整しなければならない

(C99、6.7.5.3p8):C標準段落を参照2.1。