プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

私の知らなかったcallbackの世界

callbackとは、関数を関数の引数として渡すことが出来るテクニックです。

例として、以下のようなものがあります。
最終的にprintf("Hello xx")をしていますが、関数が変数のように扱われて引数で渡され、実行されています。

#include <stdio.h>

typedef void (*callback_t)(int *);
typedef void (*func)(void *);
callback_t result_callback = NULL;

void set_callback(func cb)
{
  result_callback = (callback_t)cb;
}

void cb_func(void *data)
{
  // dataはアドレス、sもアドレス
  int *s = (int *)(data);
  printf("Hello %d", *s);
}

// int t=1; //これもOK

int main(void)
{
  set_callback(cb_func);
  if (result_callback != NULL)
  {
    int t = 23;
    result_callback(&t);
  }
  return 0;
}

これは当然ファイル間でも可能で、ファイル分割が出来ます。

// main.c
#include <stdio.h>
#include "lib.c"

int main(void)
{
  set_callback(cb_func);
  if (result_callback != NULL)
  {
    int t = 24;
    result_callback(&t);
  }
  return 0;
}
// lib.c
typedef void (*callback_t)(int *);
typedef void (*func)(void *);
callback_t result_callback = NULL;

void set_callback(func cb)
{
  result_callback = (callback_t)cb;
}

void cb_func(void *data)
{
  int *s = (int *)(data);
  printf("Hello %d", *s);
}

このとき、lib.cというファイルをmain.cから読み込んでおり基本的なモジュール化の手法といえます。

あるとき、あるファイルにある関数を使いたいが、includeが複雑でループしてしまっていて、上記のようなmain.cからの読み込みが出来ないファイルがありました。
このとき、逆にmain.c(実際はmain.cではないが、ここでは説明の簡略化のため"main.c"というファイル名を使っている)をlib.cからincludeすると動かすことが出来ます。
こうすると、main.cでlib.cの関数を呼び出しているのにincludeは逆転しているという形で実現することが出来ています。

// main.c
#include <stdio.h>
// #include "lib.c"    // ------> 出来ないケースがあったとする

typedef void (*callback_t)(int *);
typedef void (*func)(void *);
void cb_func(void *data);
void set_callback(func cb);
callback_t result_callback = NULL;

int main(void)
{
  set_callback(cb_func);
  if (result_callback != NULL)
  {
    int t = 22;
    result_callback(&t);
  }
  return 0;
}
// lib.c
#include "main.c"   // ------> 出来る

void set_callback(func cb)
{
  result_callback = (callback_t)cb;
}

void cb_func(void *data)
{
  // dataはアドレス、sもアドレス
  int *s = (int *)(data);
  printf("Hello %d", *s);
}

まとめ

また困ったことが合ったら使うかもしれない手法をメモとして残しておきます。