【问题标题】:jump table examples in CC中的跳转表示例
【发布时间】:2012-04-13 12:04:49
【问题描述】:

请给我一些跳转表使用的例子。我在维基百科上看到过这个例子:

#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() 之类的操作吗?

【问题讨论】:

  • "使用索引是否可以使用函数本身的名称" 您正在寻找的是高级语言或哈希表。哈希表将是字符串 -> 函数指针。
  • 如果你想用函数本身的名字来调用,那你为什么首先需要一个跳转表呢?
  • 我实际上并没有阅读您的最后一个示例,现在我刚刚阅读了,我相信@PavanManjunath 有一点。你到底想做什么?我假设你想要一个 char* 并基于它调用一个函数。就像在 PHP 中你可以做 $func = "strtolower";回声 $func('CORBIN');.
  • 您为什么要这样做?除了另一个层次的间接性之外,它会给你带来什么?而且您提出的不再是跳表。

标签: c jump-table


【解决方案1】:

您当然可以创建一个包含函数指针的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...
};

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

【讨论】:

  • +1 - 这与我认为 OP 所要求的非常接近。在 80 年代,当我们渴望 C++ 虚函数时,这是一种正常的技术,但只有 PC 上才有 C。
【解决方案2】:

当然可以,但是您需要将它们声明为函数指针并首先对其进行初始化。虽然如果你必须拼出函数名,这违背了跳转表的目的。

例如

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

【讨论】:

  • 嗯,它可能有意义:如果你有不同的结构实例,例如,实现一种虚函数表。
  • 那太丑了。用块代替。
【解决方案3】:

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

#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

【讨论】:

    猜你喜欢
    • 2019-05-02
    • 2014-09-19
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 2020-06-30
    • 2022-06-20
    • 2015-12-03
    相关资源
    最近更新 更多