我想了解现有代码。
我们什么时候去寻找功能指针?特别喜欢下面的那个。
struct xx
{
char *a;
(*func)(char *a, void *b);
void *b;
}
struct xx ppp[] = { };
然后检查sizeof(ppp)/ sizeof(* ppp);
我们什么时候采用这种方式?
答案 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中的函数指针有两个主要用途(我知道)。
你有某种事件驱动的框架(GUI是最简单的例子之一),程序希望在事件发生时做出反应。现在你可以使用事件泵,比如
while (event *e = get_one_event()) {
switch (e->type) {
case EVT_CLICK:
...
}
}
但过了一会儿就累了。另一个主要的选择是回调。该程序定义了一组处理不同事件的函数,然后将它们与库一起注册:“当事件X发生时,调用函数Y” - 当然,库将接收一个函数指针,并在相关时间。
如果你在大多数其他语言中都做过OO,那么你应该很容易想象。想象一个对象作为一个结构,包含它的成员,然后是一堆函数指针(或者更可能是它的成员和指向另一个表示其类的结构的指针,它包含一堆函数指针)。表中的函数指针是对象的方法。 GLib / GObject是这种技术的大用户,Linux内核(struct file_operations
,struct device_driver
,struct 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有关。设置环境变量并在文件之间创建符号链接,将数据从一个文件复制到另一个文件等等。我不明白为什么我们需要在运行时使用函数指针调用这些函数。我们也可以直接打电话给他们。
事实上,您可以在不使用函数指针的情况下完成所需的操作。如果我确实理解你的问题,那么你正试图理解别人的代码,这就是你用函数指针做的事情。
我个人不会使用此功能,除非我需要它,但如果你在这里发布一些额外的代码,我们可以尝试更好地理解它。