Reputation: 2289
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]
Upvotes: 0
Views: 3002
Reputation: 320531
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.
Upvotes: 8