我们什么时候使用函数指针

时间:2010-08-07 07:52:42

标签: c

我想了解现有代码。

我们什么时候去寻找功能指针?特别喜欢下面的那个。

struct xx

{
  char *a;

  (*func)(char *a, void *b);

  void *b;

}


struct xx ppp[] = { };

然后检查sizeof(ppp)/ sizeof(* ppp);

我们什么时候采用这种方式?

3 个答案:

答案 0 :(得分:6)

sizeof array / sizeof *array是一种了解数组中有多少元素的方法。 (注意它必须是数组而不是指针。)我不确定这与你的函数指针问题有什么关系。

函数指针用于存储对函数的引用,以便稍后调用它。关键是函数指针不必总是指向同一个函数。 (如果确实如此,您可以按名称引用该功能。)

以下是基于您的代码的示例(尽管如果我知道您的代码应该做什么,我可以提供更好的代码。

char *s1 = "String one";
char *s2 = "String two";

void f(char *a, void *b) {
    /* Do something with a and b */
}
void g(char *a, void *b) {
    /* Do something else with a and b */
}

struct xx {
    char *a;
    void (*func)(char *a, void *b);
    void *b;
}

struct xx ppp[] = { {s1, f, NULL}, {s2, g, NULL} };

int main(int argc, char **argv) {
    for (int i = 0; i < (sizeof ppp / sizeof *ppp); i++) {
        ppp[i].func(ppp[i].a, ppp[i].b);
    }
}

答案 1 :(得分:3)

C中的函数指针有两个主要用途(我知道)。

1。回调

你有某种事件驱动的框架(GUI是最简单的例子之一),程序希望在事件发生时做出反应。现在你可以使用事件泵,比如

while (event *e = get_one_event()) {
  switch (e->type) {
    case EVT_CLICK:
      ...
  }
}

但过了一会儿就累了。另一个主要的选择是回调。该程序定义了一组处理不同事件的函数,然后将它们与库一起注册:“当事件X发生时,调用函数Y” - 当然,库将接收一个函数指针,并在相关时间。

2。对象(函数表/ vtable)

如果你在大多数其他语言中都做过OO,那么你应该很容易想象。想象一个对象作为一个结构,包含它的成员,然后是一堆函数指针(或者更可能是它的成员和指向另一个表示其类的结构的指针,它包含一堆函数指针)。表中的函数指针是对象的方法。 GLib / GObject是这种技术的大用户,Linux内核(struct file_operationsstruct device_driverstruct bus_type以及更多内容也是如此。这使我们可以拥有任意数量的具有不同行为的对象,而不会增加代码量。

答案 2 :(得分:2)

  

我们什么时候去寻找功能指针?特别喜欢下面的那个。

当你想要更抽象的东西时,你可以使用函数指针。 例如,假设您的应用程序具有带有一定数量按钮的图形工具箱。每个按钮对应于某个结构的实例。

按钮结构可以包含函数指针和上下文:

typedef struct {
    void (*press_button) (void *context);
    void *context;
    /* Here some other stuff */
} Button;

当用户点击该按钮时,该事件类似于

void event_click (Button *b)
{
    b->press_button(b->context);
}

这样做的关键是你可以为每个按钮使用相同的结构:

Button * create_button (void (*callback) (void *), void *context, /* other params */
{
    Button *ret = malloc(sizeof(Button));
    if (ret != NULL) {
        ret->callback = callback;
        ret->context = context;
        /* Assign other params */
    }
    ...
    return ret;
}

因此,当您构建工具箱时,您可能会执行类似

的操作
Button * toolbox[N];
toolbox[0] = create_button(function1, (void *)data, ...);
toolbox[1] = create_button(function2, (void *)something, ...);
...
toolbox[N-1] = create_button(functionN, (void *)something_else, ...);

此外,当您创建一些函数指针时,始终携带一些contxt信息(就像我对结构的context字段所做的那样)。这允许您避免全局变量,因此您可以获得强大且可重入的代码!

注意: 这个方法很棒,但是如果你处理C ++,你可能更喜欢使用面向对象并用抽象类中的deriat替换回调。通过这样做,您也不需要携带上下文,因为课程将为您完成。

编辑回复第一条评论

  

我正在经历的当前代码与文件IO有关。设置环境变量并在文件之间创建符号链接,将数据从一个文件复制到另一个文件等等。我不明白为什么我们需要在运行时使用函数指针调用这些函数。我们也可以直接打电话给他们。

事实上,您可以在不使用函数指针的情况下完成所需的操作。如果我确实理解你的问题,那么你正试图理解别人的代码,这就是你用函数指针做的事情。

我个人不会使用此功能,除非我需要它,但如果你在这里发布一些额外的代码,我们可以尝试更好地理解它。