0

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]
4
  • 1
    Have you (eventually) defined the union edit_cmd type somewhere in your code? Commented Jul 27, 2011 at 23:34
  • Yes, it just needed to be moved before the edit_cmd_tab struct. Commented Jul 27, 2011 at 23:46
  • For what it's worth, a few of those consts aren't really useful. It shouldn't cause errors, but it might mean you should look into cdecl (cdecl.ridiculousfish.com) to make sure the const is where you intend it to be. (Of particular concern is union edit_cmd *const as a function argument.) Commented Jul 27, 2011 at 23:49
  • It means that the pointer to the union inside the function will never change, correct? I assume that there are compiler optimizations if this is present, or else it wouldn't be there. If I know that the pointer will never change, it is better to declare it *const, no? Commented Jul 28, 2011 at 0:07

1 Answer 1

8

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I know that you can define pointers to structures before they have been defined so I assumed that the same was true of unions. Anyways, that was it, thank you.
@bhinesley: Structs and unions are the same in this regard. The problem is that you can't refer to undefined structs and unions from function prototypes specifically. Function prototypes in C have their own internal scope (don't ask me why). Every time you refer to an undefined struct (or union) from a prototype, the compiler introduces a new local type in that internal scope. The morale: don't refer to undefined structs and unions from function prototypes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.