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...
};

然后一些更高级别的函数可以接收其中之一,并打开/关闭/读取/写入某些设备,而无需知道所涉及设备的确切身份。当然,对于一个真正的操作系统,它会比这更复杂一些,但总体思路是(或至少可以)非常相似。

于 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 回答
0

您可以使用枚举来表示数组的索引,并为它们赋予有意义的名称。

#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" ); }

enum{
    FUNC0,
    FUNC1,
    FUNC2,
    FUNC3
};

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

int main (int argc, char **argv) {
    /* Call appropriate function (func0 thru func3) */
    jump_table[FUNC0]();
    jump_table[FUNC1]();
    jump_table[FUNC2]();
    jump_table[FUNC3]();
    return 0;
}

这将输出

0
1
2
3
于 2018-07-07T08:38:32.533 回答