Code Fix

上級

関数ポインタ呼び出しの優先順位ミスによる原因と直し方

*fp(a, b)と書くと、関数呼び出し()の方が間接参照*より優先順位が高いため、fp(a, b)を先に呼び出してからその戻り値に*を適用しようとしてしまいます。

エラーメッセージの読み方

main.c:7:18: error: invalid type argument of unary '*' (have 'int')
main.c
ファイル名
7
行番号
18
列番号 — この位置でgccが構文解析に失敗しました
invalid type argument of unary '*' (have 'int')
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  #include <stdio.h>
 2  
 3  int add(int a, int b) { return a + b; }
 4  
 5  int main(void) {
 6      int (*fp)(int, int) = add;
 7      int result = *fp(2, 3)  ;
                          ^
 8      printf("%d\n", result);
 9      return 0;
10  }
main.c:7:18: error: invalid type argument of unary '*' (have 'int')

()は*より優先順位が高いため、*fp(2, 3)はfp(2, 3)を先に呼び出そうとします。fpは変数(関数ポインタ)であって関数ではないため、呼び出せずエラーになります。(*fp)(2, 3)のように括弧でfpを間接参照してから呼び出す必要があります。

直し方: *fp(2, 3) を (*fp)(2, 3) にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  #include <stdio.h>
 2  
 3  int multiply(int a, int b) { return a * b; }
 4  
 5  int main(void) {
 6      int (*fp)(int, int) = multiply;
 7      int result = *fp(4, 5)  ;
                          ^
 8      printf("%d\n", result);
 9      return 0;
10  }
main.c:7:18: error: invalid type argument of unary '*' (have 'int')

関数ポインタ経由の呼び出しは(*関数ポインタ名)(引数)という形が正しい書き方です。

直し方: *fp(4, 5) を (*fp)(4, 5) にします。

この問題を解いてみる →

パターン3

 1  #include <stdio.h>
 2  
 3  int subtract(int a, int b) { return a - b; }
 4  
 5  int main(void) {
 6      int (*fp)(int, int) = subtract;
 7      int result = *fp(10, 3)  ;
                           ^
 8      printf("%d\n", result);
 9      return 0;
10  }
main.c:7:18: error: invalid type argument of unary '*' (have 'int')

実際には多くのコンパイラがfp(...)(括弧無しの間接参照)も許容しますが、*fp(...)は完全に別の意味になるため注意が必要です。

直し方: *fp(10, 3) を (*fp)(10, 3) にします。

この問題を解いてみる →

パターン4

 1  #include <stdio.h>
 2  
 3  int divide(int a, int b) { return a / b; }
 4  
 5  int main(void) {
 6      int (*fp)(int, int) = divide;
 7      int result = *fp(20, 4)  ;
                           ^
 8      printf("%d\n", result);
 9      return 0;
10  }
main.c:7:18: error: invalid type argument of unary '*' (have 'int')

()は*より優先順位が高いため、括弧で明示的にfpを間接参照してから呼び出す必要があります。

直し方: *fp(20, 4) を (*fp)(20, 4) にします。

この問題を解いてみる →

パターン5

 1  #include <stdio.h>
 2  
 3  int mod(int a, int b) { return a % b; }
 4  
 5  int main(void) {
 6      int (*fp)(int, int) = mod;
 7      int result = *fp(17, 5)  ;
                           ^
 8      printf("%d\n", result);
 9      return 0;
10  }
main.c:7:18: error: invalid type argument of unary '*' (have 'int')

関数ポインタ経由の呼び出しは(*関数ポインタ名)(引数)という形が正しい書き方です。

直し方: *fp(17, 5) を (*fp)(17, 5) にします。

この問題を解いてみる →

よくある誤解

関数ポインタを「呼び出す」つもりで*fp(a, b)と書いても、Cはfpそのものを関数として呼ぼうとはしません。まずfp(a, b)を評価しようとするため、意図と違う解釈になります。関数ポインタ経由で呼び出すときは(*fp)(a, b)と括弧でまとめるのが安全です。

実務での勘所

この優先順位の逆転は、Cの演算子優先順位表で「後置(postfix)」の演算子([]、.、->、関数呼び出しの()など)が、単項の前置演算子(*や&など)よりも優先順位が高いという一般原則の一例です。*fp(a, b)は、まず後置の()が先に結合されfp(a, b)という呼び出しが完成してから、その結果に前置の*が適用されます。この「後置は前置より強い」という原則を知っていれば、配列の添字と間接参照が絡む他の紛らわしい式(*p[i]など)も同じ考え方で読み解けます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)