C言語プログラミング・Callback(コールバック)関数の実装

C言語プログラミングの基礎・Callback関数(コールバック関数)の実装をご紹介します。
Callback関数を使用することで、非同期処理の応答を取得することができ、また依存関係の低減に貢献できます。

Callback関数とは

Callback(コールバック)関数とは呼び直してほしい関数のことです。
言葉の由来は電話のかけ直と同じことから来ているそうです。

電話で例えると、電話をすると相手側の電話機に電話番号が記録されます。相手側は後でその電話番号をたどってかけ直すことができます。

プログラムで言うと、相手側となる他スレッドに対してコールバック関数を登録することで他スレッドから登録されたコールバック関数を呼ぶことができます。

用途・どんな時に使えるの?

主に以下の目的で使用します。

  • 非同期要求に対して応答する
  • 下位モジュールが上位モジュールへ通知する

用途はC++のオブザーバパターンと同じです。コールバック関数はC++でいう基底クラスの関数の使用やオーバーライドの役割をもっています。オブザーバパターンをコールバック関数で代替できます。

配置図

Callback(コールバック)関数

C言語にはクラス概念はありませんが、説明のために配置図を作りました。

図ではファイル名を示しています。各ファイルの関係性としてはcontents_frameworkが上位モジュール、contentsが下位モジュールとなります。

contents_frameworkがコールバック関数であるupdate関数をcontentsへ登録します。contentsはhandlerであるcall_back_wrapper関数をコールすることで上位モジュールのupdate関数をコールすることができます。

※ExCallbackはただのmain関数であり、使用者です。

コールバック関数を使う理由

非同期処理の応答を受けるためモジュール間の依存関係(相互参照を防ぐ)を減らすためです。
この記事では後者の依存関係を減らすことに着目します。

モジュール間の依存関係を減らす

コールバック関数を使わなくてもcontentsがcontents_frameworkをコールすることはできます。何故ややこしいコールバック関数を使うのかというと、冒頭で述べた通り依存関係を減らすためです。

コールバック関数を使用しない場合はcontents_frameworkとcontentsは相互に依存関係を持つこととなり、コード変更に弱くなります。具体的に言うとcontents_frameworkのupdate関数名が変更になればcontents側も修正が必要になり、修正の規模が大きくなってしまいます。

コールバック関数を使用する場合はcontentsはcontents_frameworkで定義している関数を意識する必要がないため、update関数名が変更になってもcontents_frameworkのみの修正で対応することができコード変更に強いです。コールバック関数を使うことでコード変更の規模を小さくできます。

実装の解説

C言語で実装したサンプルコードを解説します(ファイル名はcppですが中身はC言語です)。
このサンプルコードはコールバック関数(update関数)を下位モジュールへ設定し、下位モジュールからコールバック関数をコールします。

まずtypedefを使用して戻り値void, 引数charポインタの関数ポインタをp_funcに置き換えます。contents_runの引数にはupdate関数のポインタが指定されているので、一度内部の関数ポインタに登録します。

call_back_wrapper関数で関数ポインタをコールすることで、上位モジュールであるcontents_frameworkのupdate関数がコールされます。

■ contents_framework.cpp

■ contents_framework.h

■ contents.cpp

■ contents.h

■ ExCallback.cpp

サンプルコード

Visual C++ 2017で作成したサンプルコードをGitHubで公開しています。
GitHub – ExCallback

実行結果は以下の通りです。コールバック関数であるupdate関数がコールされていることが確認できます。

参考

コールバック (情報工学) – Wikipedia

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。

コメントを残す

*

Translate »