views:

104

answers:

4

I have a struct with a callback function, the callback function needs a pointer to the structure in order to do its operation. How do I properly define these elements such that is will compile without warnings?

typedef struct {

    // some fields required for processing...

    int (*doAction)(struct pr_PendingResponseItem *pr);
} pr_PendingResponseItem;

If I remove the "struct" attribute on the pr parameter, I get an error. If I leave it in, I get a warning: "its scope is only this definition or declaration, which is probably not what you want"

It all works, but I would like to know the proper way to define such a structure.

Also related, is defining a self referential structure:

typedef struct LinkedItem_ {
    LinkedItem_ * prev;
    LinkedItem_ * next;
    void * data;
} LinkedItem;

(I think this is correct, but additional thoughts are welcome if it is related to the question.)

+6  A: 

Your function pointer references a struct pr_PendingResponseItem, but you haven't declared a struct pr_PendingResponseItem. You just have an unnamed structure typedef'ed to the name pr_PendingResponseItem (and that name isn't established yet).

Give the struct a name:

struct pr_PendingResponseItem {

    // some fields required for processing...

    int (*doAction)(struct pr_PendingResponseItem *pr);
} ;
typedef struct pr_PendingResponseItem pr_PendingResponseItem;
nos
+2  A: 

something like this

typedef struct _pr_PendingResponseItem_ {

    // some fields required for processing...

    int (*doAction)(struct _pr_PendingResponseItem_ *pr);
} pr_PendingResponseItem;

should fix it.

(Tested & works)

slashmais
A: 

Adding to the answer by nos above.

The key insight here is that when dealing with a declaration like "typedef struct name1 {} name2;", you are actually declaring two types i.e. "struct name1 {};" and then "typedef struct name1 name2;", where "struct name1" is a type and you have to use the syntax "struct name1" to refer to it, and "name2" is a type, and you refer to it as "name2". You are allowed to leave "name1" out, in which case you just define the second type and the first one remains a anonymous struct.

Now, in the first case, if you want to refer to the type "struct pr_PendingResponseItem", you need to declare that type, instead of the anonymous struct you have declared. So, change your struct declaration to "struct pr_PendingResponseItem".

In the second case, you are trying to refer to a struct type as a forward reference (i.e. referring to it before its definition is complete), which is allowed, but to refer to a struct type, the required syntax is "struct name". So you need to replace forward references to "LinkedItem_" in your definition with "struct LinkedItem_".

Ziffusion
You mean "nos", not "27k". The latter is the reputation count.
Mike DeSimone
tl;dr..........
Matt Joiner
+3  A: 

There are two ways to do it - for both your example structures. They are essentially isomorphic.

  1. Use a structure tag, as already shown in various other answers.

    typedef struct pr_PendingResponseItem
    {
        // some fields required for processing...
        int (*doAction)(struct pr_PendingResponseItem *pr);
    } pr_PendingResponseItem;
    
    
    typedef struct LinkedItem
    {
        LinkedItem_ *prev;
        LinkedItem_ *next;
        void * data;
    } LinkedItem;
    
  2. Use typedef to give a name to an incomplete structure type and use the typedef in the structure definition.

    typedef struct pr_PendingResponseItem pr_PendingResponseItem;
    struct pr_PendingResponseItem
    {
        // some fields required for processing...
        int (*doAction)(pr_PendingResponseItem *pr);
    };
    
    
    typedef struct LinkedItem LinkedItem;
    struct LinkedItem
    {
        LinkedItem *prev;
        LinkedItem *next;
        void * data;
    };
    

Note that the struct tags are in a different namespace from the typedef names, so there is no need to use different names for the typedef and struct. Also note that in C++ the typedef would be unnecessary.

Jonathan Leffler
This is the only answer that actually identified that you could forward declare the `typedef`.
Matt Joiner