使用泛型函数指针

bhi*_*ley 0 c arrays struct abstraction function-pointers

我有一系列结构.该struct有两个函数指针.数组的每个元素都需要函数指针指向不同的函数,以便可以在不知道特定函数名的情况下调用对应于特定元素的函数.作为函数指针的新手,在我看来,我正在做的事情不会起作用,但我不确定如何正确地做到这一点.还将理解如何调用所指向的函数之一的示例.

以下是我试图引用的函数的原型:

int edit_translate_concise(struct ged *gedp, const union edit_cmd * const cmd);
int edit_translate_add_arg(union edit_cmd * const cmd, struct edit_arg * const arg);
Run Code Online (Sandbox Code Playgroud)

结构和该结构的数组如下:

struct edit_cmd_tab {
    char *name;
    char *opt_global;
    char *usage;
    char *help;
    int (*exec_concise)(struct ged *gedp, const union edit_cmd *const cmd);
    int (*add_arg)(union edit_cmd *const cmd, struct edit_arg *const arg);
};

static const struct edit_cmd_tab edit_cmds[] = {
    ...
    {"translate",       (char *)NULL,
        "[FROM] TO OBJECT ...",
        "[[-n] -k {FROM_OBJECT | FROM_POS}]\n"
            "[-n] [-a | -r] {TO_OBJECT | TO_POS} OBJECT ...",
        &edit_translate_concise,
        &edit_translate_add_arg
    },
    ...
};
Run Code Online (Sandbox Code Playgroud)

因此,我需要指向的函数采用相同的参数并返回与结构的函数指针成员相同的类型.

我收到这些警告,指的是第一个结构的最后两行:

/home/bhinesley/brlcad-trunk/src/libged/edit.c:866:55: warning: ‘union edit_cmd’ declared inside parameter list [enabled by default]
/home/bhinesley/brlcad-trunk/src/libged/edit.c:866:55: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
/home/bhinesley/brlcad-trunk/src/libged/edit.c:867:54: warning: ‘union edit_cmd’ declared inside parameter list [enabled by default]
Run Code Online (Sandbox Code Playgroud)

这些警告指的是数组的最后两行:

/home/bhinesley/brlcad-trunk/src/libged/edit.c:1188:2: warning: initialization from incompatible pointer type [enabled by default]
/home/bhinesley/brlcad-trunk/src/libged/edit.c:1188:2: warning: (near initialization for ‘edit_cmds[1].exec_concise’) [enabled by default]
/home/bhinesley/brlcad-trunk/src/libged/edit.c:1190:5: warning: initialization from incompatible pointer type [enabled by default]
/home/bhinesley/brlcad-trunk/src/libged/edit.c:1190:5: warning: (near initialization for ‘edit_cmds[1].add_arg’) [enabled by default]
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 8

你正在做几乎所有事情.

但是,union edit_cmd在函数原型中使用它之前,必须确保声明实际的union .如果您忘记声明它,编译器将union edit_cmd视为一个全新的union类型的声明,它是函数原型的本地.即本地声明union edit_cmd将与您union edit_cmd在其他地方的实际声明无关.

这就是你的情况.这就是编译器试图警告你的内容.这同样适用struct gedstruct edit_arg.很显然,你忘了,包括包含的声明的头文件union edit_cmd,struct gedstruct edit_arg.

例如,这个简单的代码说明了这个问题

void foo(union bar *p);

union bar {
  int a;
};
Run Code Online (Sandbox Code Playgroud)

union bar在宣布foo的原型完全没有关系union bar后声明.前者是原型的本地,后者是全局的(即文件级类型).如果你以后尝试做

union bar u;
foo(&u);
Run Code Online (Sandbox Code Playgroud)

您将从编译器获得有关参数参数类型不匹配的诊断消息.同样的不匹配是导致帖子中第二组警告的原因(关于数组初始化中不兼容的指针类型).

但是如果你以这种方式重新安排声明

union bar {
  int a;
};

void foo(union bar *p);
Run Code Online (Sandbox Code Playgroud)

一切都会正常工作,因为union bar原型现在指的是先前声明的union bar.另外,您也可以转发,声明union bar

union bar;
void foo(union bar *p);

union bar {
  int a;
};
Run Code Online (Sandbox Code Playgroud)

这也将使编译器把union barfoo全球型(即文件级型),而不是作为一个地方之一.

至于通过指针调用函数,它可以作为任何一个来完成

(*edit_cmds[i].add_arg)( /* arguments go here */ );
Run Code Online (Sandbox Code Playgroud)

甚至没有*经营者

edit_cmds[i].add_arg( /* arguments go here */ );
Run Code Online (Sandbox Code Playgroud)

总结以上内容,您正在观察的问题的简单修复是在函数原型之前添加structunion类型的文件级前向声明.

struct ged;
union edit_cmd;
struct edit_arg;
int edit_translate_concise(struct ged *gedp, const union edit_cmd * const cmd);
int edit_translate_add_arg(union edit_cmd * const cmd, struct edit_arg * const arg);
Run Code Online (Sandbox Code Playgroud)

更优雅的方法是在原型声明之前包含这些类型的完整定义.