8

ジャンプ台の使用例をいくつか教えてください。私はウィキペディアでこの例を見ました:

#include <stdio.h>
#include <stdlib.h>

typedef void (*Handler)(void);    /* A pointer to a handler function */



/* The functions */
void func3 (void) { printf( "3\n" ); }
void func2 (void) { printf( "2\n" ); }
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }



Handler jump_table[4] = {func0, func1, func2, func3};



int main (int argc, char **argv) {
    int value;

    /* Convert first argument to 0-3 integer (Hash) */
    value = atoi(argv[1]) % 4;
    if (value < 0) {
        value *= -1;
    }

    /* Call appropriate function (func0 thru func3) */
    jump_table[value]();
}

しかし、示されているようにインデックスを使用する代わりに関数を呼び出す別の方法があるかどうか疑問に思っていました.上記の場合はjump_table[value]();

私が達成したいのは、インデックスを使用する代わりに、関数自体の名前を使用する方法があるということです。

たとえば、構造体にすべての関数ポインターがあるとします。

typedef struct _funcptrs
{
  void func1();
  void func2();
} funcptrs;

そして今、関数を呼び出したいときに、次のようなことができますfuncptrs.func1()か?

4

3 に答える 3

8

struct関数へのポインタを含む を確実に作成できます。そうする正当な理由さえあります。

一例として、オペレーティング システムと何らかのデバイス ドライバ間のインターフェイスを考えてみましょう。かなり単純化すると、これは次の順序で表示される可能性があります。

struct device { 
    int (*open)(unsigned mode);
    int (*close)(void);
    int (*read)(void *buffer, size_t size);
    int (*write)(void *buffer, size_t size);
};

次に、個々のデバイス ドライバーがこの型の構造体を作成し、個々のポインターを初期化して、特定のデバイスに関連する関数を参照します。

struct device serial_port = { 
    open_serial,
    close_serial,
    read_serial,
    write_serial
};

struct device ethernet_adapter = { 
    open_net,
    close_net,
    read_net,
    write_net
};

struct device keyboard = { 
    open_keyboard,
    close_keyboard,
    read_keyboard,
    NULL  // we'll assume no writing to the keyboard...
};

次に、上位レベルの関数がこれらのいずれかを受け取り、関係するデバイスの正確な ID を知らなくても、デバイスをオープン/クローズ/読み取り/書き込みできます。もちろん、実際の OS の場合は、これよりも少し複雑になりますが、一般的な考え方はかなり似ています (または、少なくとも似ている可能性があります)。

于 2012-03-29T20:00:52.677 に答える
7

確かに、しかし、それらを関数ポインタとして宣言し、最初に初期化する必要があります。ただし、関数名を綴る必要がある場合、これはジャンプ テーブルの目的に反します。

例えば

#include <stdio.h>

void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }

typedef struct
{
  void (*func0)(void);
  void (*func1)(void);
}  funcptrs;

int main(int argc, char *argv[])
{
   funcptrs funcs = { func0, func1 };
   funcs.func1();
   return 0;
}

関数の名前を文字列として使用して関数を呼び出す必要がある場合は、関数名と関数ポインターの間のマッピングを作成し、その関数のテーブルを検索して呼び出す必要があります。

#include <stdio.h>
#include <string.h>

void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }

#define DEFUN(name) { #name, name }

typedef struct
{
  const char *name;
  void (*func)(void);
}  funcptrs;

void call(funcptrs *ptrs, const char *name)
{
    int i;
    for(i = 0; ptrs[i].name; i++) {
      if(strcmp(ptrs[i].name, name) == 0) {
           ptrs[i].func();
           break;
       }
    }
}
int main(int argc, char *argv[])
{
   funcptrs funcs[] = {DEFUN(func0), DEFUN(func1), {NULL,NULL}};
   call(funcs, "func0");
   return 0;
}
于 2012-03-29T19:40:37.030 に答える