• 締切済み

関数ポインタの型をtypedefしたとき

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回やっているようで、無駄に思えてしまいます。

みんなの回答

  • ency
  • ベストアンサー率39% (93/238)
回答No.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 のコンパイラが自分の都合でポインタに読み替えているだけです。 こんな感じでいかがでしょうか。

回答No.4

関数ポインタに代入する関数が、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); } こうゆう使い方なら納得できるとかと思います。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

多分, できないと思います. 該当する例は見付ていないのですが, 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 { /* ... */ } はアウトだと思います.

racoon_asia
質問者

お礼

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

noname#198419
noname#198419
回答No.2

おそらく参考書を読みながら質問しているのかと思いますが、参考書では関数のポインタを手短に説明するために質問にあるようなコードが提示されているんだろうと思います。 もう少し発展させて・・・ 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を卒業した中級以上のスキルを対象にする本を眺めてみることです。

  • skbler
  • ベストアンサー率9% (69/692)
回答No.1

MyFunc pf = FuncA; 代入(メモリ上に値を記憶するための必要な領域を確保) (*pf)(pa,pb); 演算処理?

関連するQ&A

  • 関数ポインタを返す関数の型をtypedefする方法

    C言語について質問します。 ある関数を定義するとします。 その関数は引数としてintを一つ取り、返値としてその関数と同じ型の関数へのポインタを返すようにしたいのですが、どのように書けばよいのでしょうか? そして、その関数の型をtypedefで定義したいです。 例えば、FNをtypedefしたいその関数の型だとすると、 typedef FN (*FN)(int); のようなFNを定義したいのですが、上のように書いても当然コンパイラ(VC9)に怒られます。 最悪、 typedef void* (*FN)(int); とvoidポインタを返すように定義しておいて、そのポインタを返値として受け取った側でFNにキャストし直す方法で対処できなくもないですが、ちょっと強引過ぎる気がします。 何かいい方法はあるのでしょうか? boost::functionあたりを使えばできそうな、そうでもないような気がしますが、できれば純粋なCでの解決法を望みます。 よろしくお願いします。

  •  ポインタを使って関数の値のやり取り

    c言語の問題なのですが、2つの異なる1次元配列の積をseki関数を使って計算してもうひとつの配列に入れてmain関数で表示するのですが、うまく走りません原因がわかる人がいた教えてください。 作った実行文は、 #include<stdio.h> int seki(int *pa,int *pb,int *pc); main(){ int a[]={5,2,3,5,3,2,4,8,9,9,7},b[]={4,3,8,4,6,2,8,9,1,6,4},c[11]={0}; int i,*pa,*pb,*pc; pa=&a; pb=&b; pc=&c; seki(pa,pb,pc); for(i=0;i<11;i++) printf("%d,",*(pc+i)); } int seki(int *pa,int *pb,int *pc){ int j; for(j=0;j<11;j++) *(pc+j)=*(pa+j) * *(pb+j); } こんな表示が出てきます。 toi2.c: In function `main': toi2.c:7: warning: assignment from incompatible pointer type toi2.c:8: warning: assignment from incompatible pointer type toi2.c:9: warning: assignment from incompatible pointer type たぶんmain関数内で書いたseki関数の引数の型に問題があると思うのですが。

  • 関数の戻り値にその関数のポインタを返すには?

    関数ポインタの使い方について質問したいです. 関数で,自分自身のポインタを(void*)ではなく関数と同じ型のポインタで返すことは可能でしょうか? (自分自身の関数ポインタと同じ型??) fucn (){ return fucn; } int main(){ fucn()()()(); return 0; } このようにmain関数の中でfucn()()・・・ のように任意個の()を書いたりできないでしょうか?  詳しい方いたらよろしくお願いします.

  • ポインタのポインタが引数にある関数の使い方。

    ポインタのポインタが引数にある関数の使い方。 現在、このポインタのポインタが引数にある関数の動きがわからず困っています。 int test(int ** head) { int * pTail = (int *)*head; pTail = pTail + 1; } もし、この関数を呼び出して使用した場合どのような動きをするのでしょうか? int * comm_msg; これをグローバルポインタ変数として宣言させて、 test((void **)&comm_msg); このように呼び出したとした場合とさせていただきます。

  • ポインタの疑問点

    ポインタで分からないことがあります。 void swap(int* x, int* y){ int tmp; tmp = *x; *x = *y; *y = tmp; } /* int main(){ int *pA,*pB; *pA=5; *pB=10; cout << *pA << " , " << *pB <<"\n"; swap(pA,pB); cout << *pA << " , " << *pB <<"\n"; } */ int main(){ int a,b; a=5; b=10; cout << a << " , " << b <<"\n"; swap(&a,&b); cout << a << " , " << b <<"\n"; } 上のメイン関数ではエラーが起きます。どうしてなんでしょう? 下のと意味は同じだと思うのですが・・・

  • C言語のtypedefの質問

    Cビギナーです。 私のプログラムが長くなるのは、 ファイルの分割をしてないからだと知った今日この頃なのですが、 それを勉強するためにあるホームページを見ていたのですが、 次のようなサンプルプログラムがありました。 /* main.c */ #include <stdio.h> extern int func(int); typedef int (*pf)(int); extern pf getaddress(void); int main(void) { printf("%d\n",(getaddress())(4)); return 0; } /* sub.c */ static int func(int c) { return c*10; } typedef int (*pf)(int); pf getaddress(void) { return func; } ここで、typedef int (*pf)(int);の部分が分かりません。 intを(*pf)(int)で置き換えているのでしょうが、 それ自体がどういう意味か分かりません… どなたか教えて下さい。

  • ポインタのポインタの関数受け渡しについて

    現在ポインタのポインタを利用したプログラムを作成しています。 main関数で int **dt; と宣言したとして、配列のセットにはset関数を、 表示に関する処理をpt関数で行いたいと思っています。 void set(int ??); void pt(int ???); int main(void){ int **dt; set(??); pt(???); } void set(int ??){ dt = (int**)malloc(sizeof(int*) * k); for(i = 0; i < k; i++){ dt[i] = (int*)malloc(sizeof(int*) * k); } のように配列サイズの動的確保が目的 } void pt(int ???){ 二重forループ{ printf(dt[i][j]); } } ??、???には何を入れるべきかが理解できません。 ご教示のほどよろしくお願いいたします。

  • 関数ポインタについて

    関数ポインタを使用する際に、 指定する先の関数でデフォルト引数が指定されている場合、 関数ポインタを用いて、その引数を省略して呼び出すことはできるのでしょうか? 以下例とします。 void function(int a = 10){}; typedef void (*test)(int a); test a = &function; a(); //このように呼び出したい

  • 関数ポインタについて

    C言語によるUNIXシステムにプログラミング入門という本を読みながらC言語を勉強しています。 しかし、サンプルとして提示された下記の内容の意味がわかりません。 分からない箇所が「関数ポインタ」と呼ばれるものがついているということが分かった程度で、どういう意図で記述されているのかがわかりません。 分からないプログラムの処理内容は、ファイル内のデータを16進数で表示するというものです。 分からない箇所を記します。 #include <stdio.h> #define BUFF 17 /*buffer*/ #define ERR -1 /*system call error*/ void usage(void); /*put usage message*/ char *command_name /*command name*/ FILE *fpin; /*file pointer*/ main(int argc,char *argv[ ]){ char *rindex(const char*s,int c); /*末尾から文字列検索*/ void hexdump(void); ... ... } void hexdump(void){ ... ... } void usage(){ ... ... } 不明なのは、main関数の中の char *rindex(const char*s,int c); /*末尾から文字列検索*/ void hexdump(void); です。 Cについて、不明なところが多いので、利用する関数は使う前に宣言しなければいけない程度の理解ですが、そうだとしてもusageメソッドはmain関数の外であるのに、rindexとhexdumpは何故main関数の中で宣言されているのでしょうか。 上記の不明点とは別で、rindexの前にポインタが付いていると思うのですが、hexdumpやusageにはついていません。 知人からは、関数までのポインタを返すとのことでしたが、用途もいまいち理解できません。 全てではなくてもいいので、ヒントをいただけるとうれしいです。 よろしくお願いします。

  • 不透明なデータのポインタ宣言

    ライブラリ内で使用し、ライブラリの外には、 中身を公開したくない構造体があります。 ライブラリ関数には必ず、ポインタとしてやりとりされます。 これを外部向けに不透明なデータのポインタとして宣言したいのですが・・ typedef const void *PRIVATE_DATA ; このように宣言してみたのですが、 これでは、否応にもvoidポインタとなってしまい、 char *等と暗黙のキャストが行われてしまいます。 たとえば・・ int lib_func( PRIVATE_DATA priv ) ; こんなライブラリ関数に対して、 lib_func( "HELLO" ) ; こんなおかしな呼び出し方が書けてしまいます。 不透明で、他の型へ暗黙のキャストが行われないポインタの宣言の仕方って、 ありませんでしょうか。。? ちなみに、コンパイラは gcc version 3.4.4 です。

専門家に質問してみよう