使用通用函数指针

发布于 2024-11-26 16:58:50 字数 2110 浏览 1 评论 0原文

我有一个结构数组。该结构有两个函数指针。数组的每个元素都需要函数指针指向不同的函数,这样就可以在不知道具体函数名的情况下调用特定元素对应的函数。作为函数指针的新手,在我看来,我所做的事情是行不通的,但我不确定如何正确地做到这一点。如何调用所指向的函数之一的示例也将受到赞赏。

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

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);

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

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

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

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

/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]

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

/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]

I have an array of structs. The struct has two function pointers. Each element of the array needs the function pointers to point to different functions, so that the function corresponding to a particular element can be called without knowing the specific function name. Being new to function pointers, it seems to me that what I'm doing is not going to work, but I'm not sure how to do it correctly. An example of how to call one of the functions being pointed to would also be appreciated.

Here are the prototypes of the functions I'm trying to reference:

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);

The struct and the array of that struct are as follows:

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

So, the functions I need to point to take the same arguments and return the same type as the function pointer members of the struct.

I'm getting these warnings, referring to the last two lines of the first struct:

/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]

And these warnings referring to the last two lines of the array:

/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]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不即不离 2024-12-03 16:58:51

你[几乎]做的每件事都是正确的。

但是,您必须确保在函数原型中使用实际的 union union edit_cmd 之前已对其进行了声明。如果您忘记声明它,编译器会将 union edit_cmd 视为全新联合类型的声明,该类型对于函数原型来说是本地。即,union edit_cmd本地声明与您在其他地方拥有的union edit_cmd 的实际声明没有关系。

这就是你的情况发生的情况。这就是编译器试图警告您的内容。这同样适用于struct gedstruct edit_arg。显然,您忘记包含包含 union edit_cmdstruct gedstruct edit_arg 声明的头文件。

例如,这段简单的代码说明了

void foo(union bar *p);

union bar {
  int a;
};

foo 原型中声明的 union bar 与后面声明的 union bar 完全没有关系的问题。前者是原型的本地,后者是全局(即文件级类型)。如果您稍后尝试这样做,

union bar u;
foo(&u);

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

但是,如果您以这种方式重新排列声明,

union bar {
  int a;
};

void foo(union bar *p);

一切都会正常工作,因为原型中的 union bar 现在引用了之前声明的 union bar。或者,您可以前向声明 union bar,如下所示。

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

union bar {
  int a;
};

这也将使编译器将 foo 中的 union bar 视为全局< /em> 类型(即文件级类型),而不是本地类型。

至于通过指针调用函数,可以使用 * 运算符

(*edit_cmds[i].add_arg)( /* arguments go here */ );

,甚至可以不用 * 运算符

edit_cmds[i].add_arg( /* arguments go here */ );

来完成。 总结以上内容,解决您所观察到的问题的简单方法是添加文件级前向在函数原型之前声明 struct 和 union 类型

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);

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

You are doing [almost] everything correctly.

However, you have to make sure that the actual union union edit_cmd is declared before you use it in function prototype. If you forget to declare it, the compiler will treat union edit_cmd as a declaration of a completely new union type, which is local to function prototype. I.e. this local declaration of union edit_cmd will have no relation to the actual declaration of your union edit_cmd you'll have elsewhere.

This is what happens in your case. This is what the compiler is trying to warn you about. The same applies to struct ged and to struct edit_arg. Apparently, you forgot to include the header files that contain declarations of union edit_cmd, struct ged and struct edit_arg.

For example, this simple code illustrates the problem

void foo(union bar *p);

union bar {
  int a;
};

the union bar declared in the foo's prototype has absolutely no relation to union bar declared later. The former is local to the prototype, the latter is global (i.e. file-level type). If you later try to do

union bar u;
foo(&u);

you'll get a diagnostic message from the compiler about argument-parameter type mismatch. The very same mismatch is what causing the second group of warnings in your post (about incompatible pointer types in array initialization).

But if you rearrange the declarations in this way

union bar {
  int a;
};

void foo(union bar *p);

everything will work fine, since union bar in the prototype now refers to previously declared union bar. Alternatively, you can forward-declare union bar as in

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

union bar {
  int a;
};

This will also make the compiler treat union bar in foo as a global type (i.e. file-level type), not as a local one.

As for calling your functions through the pointers, it can be done as either

(*edit_cmds[i].add_arg)( /* arguments go here */ );

or even without the * operator

edit_cmds[i].add_arg( /* arguments go here */ );

To summarize the above, the easy fix to the problems you are observing is to add the file-level forward declarations for the struct and union type before the function prototypes

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);

A more elegant approach would be to include the full definitions of these types before the prototype declarations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文