ユーニックス総合研究所

  • home
  • archives
  • c-gengo-kansu-pointer-typedef

C言語の関数ポインタをtypedefする方法【型定義】

  • 作成日: 2022-08-26
  • 更新日: 2023-12-25
  • カテゴリ: C言語

C言語の関数ポインタをtypedef

C言語では関数ポインタを使うことができます。
そしてtypedefを行うと新しい型が定義できます。

関数ポインタをtypedefで新しい型にしておくと、記述が綺麗になりスッキリします。
関数ポインタは複雑な書き方になっていますが、typedefをうまく使うと簡単にできます。

この記事では関数ポインタをtypedefする方法について解説します。

関連記事

目が覚めるC言語のdo-while文の使い方【ループ処理、初心者向け】
明快!C言語のcontinue文の使い方
君はまだC言語のdefineのすべてを知らない【マクロ、プリプロセス】
プログラミングのポインタをわかりやすく解説【C言語】
コードで見るC言語とC++の7つの違い

関数ポインタの書き方

たとえば関数ポインタは↓のように書きます。

#include <stdio.h>  

void func(void) {  
    printf("Hello\n");  
}  

int main(void) {  
    // 関数ポインタ変数funcptrの定義  
    void (*funcptr)(void) = func;  

    funcptr();  // Hello  

    return 0;  
}  

↑のfuncptrという変数が関数ポインタです。
すごいキテレツな書き方ですよね。

void (*funcptr)(void)  

この関数ポインタfuncptrには関数funcのアドレスが入っています。
ですのでfuncptrを呼び出すと関数funcの処理が実行されます。

↑の先頭のvoidは関数の返り値の型です。
でカッコに入ってアスタリスク(*)の次のfuncptrが関数ポインタ変数名。
カッコの中のvoidは関数の引数の型です。
うーん、キテレツ!

関連記事
C言語の関数ポインタの使い方
C言語の関数ポインタを引数に渡す方法

関数ポインタをtypedefする

先ほどの関数ポインタは↓のようにtypedefできます。

#include <stdio.h>  

void func(void) {  
    printf("Hello\n");  
}  

// 関数ポインタをtypedefして新しい型MyFuncにする  
typedef void (*MyFunc)(void);  

int main(void) {  
    MyFunc funcptr = func;  

    funcptr();  // Hello  

    return 0;  
}  

↑でtypedefしているところを見てみましょう。

typedef void (*MyFunc)(void);  

↑のようになっています。
このように関数ポインタのtypedefはかなり変わった書き方をします。

↑のtypedefのすぐあとのvoidが関数の返り値の型です。
そしてカッコの中に入ってアスタリスク(*)のあとに書かれているMyFuncが型名です。
このMyFuncが新しい型です。
そしてカッコを閉じてカッコになってその中のvoidが関数の引数の型です。

このMyFuncは新しい型になるので↓のように関数ポインタ変数を書くことができます。

    MyFunc funcptr = func;  

うーん、すっきりしてて綺麗ですね。
関数ポインタの複雑な書き方がうそみたいにシンプルになりました。

このように関数ポインタはtypedefするとスッキリ書くことができます。

関連記事
C言語の構造体をtypedefする方法

色々な関数ポインタ型

ではもう少しサンプルを紹介します。
さきほどの関数ポインタは返り値もvoidで引数もvoidでした。

返り値や引数がvoidでない場合を見てみましょう。

#include <stdio.h>  

// intの返り値、intの引数  
typedef int (*MyFunc1)(int);  

// char *の返り値、複数の引数  
typedef char *(*MyFunc2)(char *, size_t, const char *);  

// voidの返り値、MyFunc1の引数  
typedef void (*MyFunc3)(MyFunc1);  

// 整数を出力する関数  
int func1(int n) {  
    return printf("%d\n", n);  
}  

// dstにsrcをコピーする関数  
char *func2(char *dst, size_t size, const char *src) {  
    snprintf(dst, size, "%s", src);  
    return dst;  
}  

// 引数fnを呼び出す関数  
void func3(MyFunc1 fn) {  
    fn(223);  
}  

int main(void) {  
    MyFunc1 funcptr1 = func1;  
    funcptr1(123);  // 123  

    MyFunc2 funcptr2 = func2;  
    char buf[100];  
    printf("%s\n", funcptr2(buf, sizeof buf, "Hello"));  // Hello  

    MyFunc3 funcptr3 = func3;  
    funcptr3(funcptr1);  // 223  

    return 0;  
}  

ここまで入り組んでくると解読もけっこう大変になってくるかもしれません。

MyFunc1intを返しintを引数に取るシンプルな関数ポインタ型です。

MyFunc2は文字列をコピーするための関数の関数ポインタ型です。
引数が多くなってますがなぜこれらの引数が必要なのかはfunc2()を見ればわかります。

MyFunc3は関数ポインタ型を引数に取る関数ポインタ型です。
関数ポインタ型を定義せずにこれを書くと非常にコードが複雑になります。
しかしtypedefしておけばそれほど複雑にはなりません。

おわりに

今回はC言語の関数ポインタのtypedefについて詳しく解説しました。
関数ポインタはtypedefしておくと扱いやすくなります。
typedefを活用してコードを綺麗にしておきましょう。

🦝 < 型を新しく定義

🐭 < typedef!