• ベストアンサー

gcc: incompatible pointer type

以下のCソースでコンパイルすると、warning: passing arg 1 of `func_b' from incompatible pointer type となります。 void (*p_func)() は、引数を省略しているので int として扱われるということでしょうか? #include <stdio.h> #include <stdlib.h> void func_a( unsigned char x ){ printf( "x=%d\n", x ) ; } void func_b( void (*p_func)() ){ p_func( 1 ) ; } int main(){ func_b( func_a ) ; return 0 ; }

質問者が選んだベストアンサー

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

まずは訂正から。 「関数や関数へのポインタを宣言するときに仮引数リストを空にすると、仮引数はないものとして扱われます。」と書きましたが、今の C の規格では 「関数を定義するときに仮引数リストを空にすると、仮引数はないものとして扱われます。これに対し、関数の(定義ではない)宣言や関数へのポインタの宣言(定義を含む)の場合には、引数の個数や型について一切情報が与えられないことを意味します。」くらいに解釈されます。将来的には変更されるはずですが。 今の場合 void (*p_func)() となっているので「p_func は void を返す関数で、その引数の個数や型は不明」ということになります。 ではなぜ unsigned char や unsigned short のときには warning が出るのに int や char * や long では出るのかという点に移るのですが、これはおそらく過去との互換性だと思います。ANSI/ISO C 以前、つまりいわゆる K&R の時代にはプロトタイプ宣言が存在しませんでした。この時代、char 及び short の引数は int に、また float の引数は double に自動的に変更されていました。つまり、関数の仮引数として char、short、float は許されていませんでした。 今考えている例では p_func に引数の情報が与えられていないため、その引数として char、short 及び float は許されず、その結果これらの型を持つ仮引数があるような関数を渡そうとすると warning が出るのだと思います。

その他の回答 (2)

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

関数や関数へのポインタを宣言するときに仮引数リストを空にすると、仮引数はないものとして扱われます。 つまり、今の場合 func_b の仮引数である p_func は void (*p_func)() と宣言されていますが、これは void (*p_func)(void) を意味します。 一方実引数である func_a の型は(型変換の結果) void (*)(unsigned char) になります。その結果 incompatible pointer type というメッセージが表示されることになります。 従って、func_b の宣言を void func_b(void p_func(unsigned char)) または void (func_b(void (*p_func)(unsigned char)) にすればメッセージは表示されなくなります。 func_b を呼出すときは func_b(func_a); でも func_b(&func_a); でもかまいません(f を関数名とすると、ほとんどの場合に f と &f は同じです)。 また、手元では void func_a(unsigned char x) を void func_a(char *x) にしても同じメッセージが表示されましたよ。

yamaokojo2
質問者

補足

void (*p_func)()と仮引数を省略=intかと思っていたのですが、voidということでしょうか。 #shige_70さんも「intでない場合は省略するとWarningがでます」と。 文献は探してませんが何かありますでしょうか。 こちらは PC上でgccを使用していますが、void func_a(unsigned char x)のunsigned charのところを、void, int, unsigned long, char*などのポインタ全般、としてもWarningは出ません。一方、unsigned shortはWarningとなります。

  • shige_70
  • ベストアンサー率17% (168/946)
回答No.1

6行目を void func_b( void p_func(unsigned char) ){ としてください。 "()"は、関数『ポインタ』を意味します。それだけですでにポインタになっていますので、"*"をつけなくてもだいじょうぶです。 別につけても構わないのですが、その場合はその定義に合わせて10行目を func_b( &func_a ) ; とすることでWarningを抑止します。 また、関数の引数の型もおっしゃるとおりintでない場合は省略するとWarningがでます。

yamaokojo2
質問者

補足

void func_a( unsigned char x ){ printf( "x=%d\n", x ) ; } を void func_a( char *x ){ printf( "x=%d\n", *x ) ; } とかにすると、Warningが出ないのはなぜでしょう。 void func_b( void (*p_func)() ){ の"()"がint扱いだとしたら、型があっていませんが?

関連するQ&A