質問

C言語において、関数ポインタの型をtypedefで作ると、

typedef int (*MyFunc)(int*,int*);

と宣言でき、関数ポインタの変数は、

int FuncA(int* a, int* b)
{

}

void main_loop()
{
MyFunc pf = FuncA;

(*pf)(pa,pb);
}

というように使うと思います。

ここで疑問なのですが、この実際に呼び出される関数、FuncAの定義に、typedef(ここではMyFunc)を使えないものでしょうか?

同じことを2回やっているようで、無駄に思えてしまいます。

通報する

回答 (5件)

C では、式の中の関数名だけが関数を指すポインタに読み替えられます。
# これは、コンパイラが勝手に読み替えます。

関数定義やプロトタイプ宣言といった、式の中にない関数名はポインタに読み替えられることはありません。

ですので、ご質問の中にある

> typedef int (*MyFunc)(int*,int*);



> int FuncA(int* a, int* b)
> {
> ~
> }

は、別の型ということになります。

FuncA( pa, pb ); // FuncA はポインタに読み替えられている。

と関数を式の中に記述した場合にのみ、コンパイラがこの FuncA をポインタとして読み替えるんです。

式の中という意味では、以下の場合も同様です。

MyFunc pf = FuncA; // FuncA はポインタに読み替えられている。

実際、pf に FuncA を代入する場合、以下のようにしても正常に動作します。

MyFunc pf = &FuncA; // アドレス演算子 & をつけてみる。

ついでに、(*pf)() コールの箇所も、以下のようにすることができます。

pf(pa,pb); // 間接参照演算子 * をとってみた。

つまり、関数を指すポインタに「限って」いえば、間接参照演算子はあってもなくても良い存在です。
というわけで、こんなことをしてもコンパイルエラーにも実行エラーにもなりません。

(**********pf)(pa,pb); // どうせ * は何もしないし。。。

このように、関数のポインタ周りの仕様はかなり混乱しています。
配列とポインタが違うものであるように、関数と関数ポインタも別物です。
どちらも、C のコンパイラが自分の都合でポインタに読み替えているだけです。

こんな感じでいかがでしょうか。

関数ポインタに代入する関数が、1つで決まってるなら無駄といえば無駄ですね。
この場合なら
int FuncA(int* a, int* b){~}
void main_loop(){
 FuncA(pa,pb);
}
で十分です。

関数ポインタが必要になるような例は。

typedef int (*MyFunc)(int*,int*);
int FuncA(int* a, int* b){ ~ }
int FuncB(int* a, int* b){ ~ }

void main_loop(){
 MyFunc pf;
 if (flag) {
  pf = FuncA; // flagが真であればFuncAを呼び出す
 } else {
  pf = FuncB; // flagが偽であればFuncBを呼び
 }
 (*pf)(pa,pb);
}
こうゆう使い方なら納得できるとかと思います。

多分, できないと思います.
該当する例は見付ていないのですが,
The identifier declared in a function definition (which is the name of the function) shall have a function type, as specified by the declarator portion of the function definition.
とあって, ここに対する脚注として
The intent is that the type category in a function definition cannot be inherited from a typedef.
と書かれており, その例として以下が規格に挙げられています:
typedef int F(void);
F f, g; // f and g both have type compatible with F
F f { /* ... */ } // WRONG: syntax/constraint error
F g() { /* ... */ } // WRONG: declares that g returns a function
脚注部分で「the type category in a function definition cannot be inherited from a typedef」と書かれているので,
typedef int (*PF)(void);
でも
PF *f { /* ... */ }
はアウトだと思います.

この回答へのお礼

こういうものだと思うことにします^^;
ご丁寧にありがとうございました。

おそらく参考書を読みながら質問しているのかと思いますが、参考書では関数のポインタを手短に説明するために質問にあるようなコードが提示されているんだろうと思います。

もう少し発展させて・・・
MyFunc pf;
ではなく、単純なリスト構造にするために
MyFunc pf[100];
とかだったら、(配列の終わり判定を含めて)100個までの処理を並べることができますよね。
あとは添え字をインクリメントしていけば、バッチ言語処理のようなことが出来そうな気がしてくれば、C言語のプログラミングを勉強した甲斐があったというものでしょう。

もっと詳しく知りたいのならば、
「実用Cプログラミング生 粋のCプログラマへ」H.シュルト著
http://www.fukkan.com/vote.php3?no=19161
とか
「エキスパートCプログラミング - 知られざるCの深層 -」Peter van der Linden著
などといった、K&Rを卒業した中級以上のスキルを対象にする本を眺めてみることです。

MyFunc pf = FuncA;

代入(メモリ上に値を記憶するための必要な領域を確保)

(*pf)(pa,pb);

演算処理?

このQ&Aは役に立ちましたか?0 件

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

新しく質問する

注目の記事

おしトピアプリ登場記念!コメントで最大1万円分のギフト券があたる!

話題のトピックにさくっとコメントできる「おしトピ」にAndroid版アプリに続きiPhoneアプリも登場! どちらかのアプリをダウンロードして指定のオーダーにコメントした方に抽選で最大1万分のアマゾンギフト券をプレゼント! フジテレビ出身のフリーアナウンサー長谷川豊氏の質問にも回答受付中!


新しく質問する

このカテゴリの人気Q&Aランキング

毎日見よう!教えて!gooトゥディ