Search code examples
cstructfunction-pointerstypedef

Struct Has Function Pointer with Argument Of Parent Struct Type


I am trying to define a struct type (call it thing) that has a function pointer in it (call it bar), and I want that function to take an argument that is a pointer to an object of type thing.

I know from here that I can either do a forward declaration or declare the struct type in the argument list of the function pointer as shown here:

// In header

typedef struct thing thing_type;

typedef struct
{
    int a;
    int b;

    double (*bar)(thing_type *t)
} thing;

OR

// In header
typedef struct
{
    int a;
    int b;

    double (*bar)(struct thing *t)
} thing;

But when I go to initialize these values, I always get an incompatible pointer type warning.

double bar1(thing *t);
double bar2(thing *t);

// In main()

thing foo = {1, 2, bar1}; // WARNING

initialization of ‘double (*)(struct thing *)’ from incompatible pointer type ‘double (*)(thing *)’ [-Wincompatible-pointer-types]

foo.bar = bar2; // WARNING

passing argument 1 of ‘foo->bar’ from incompatible pointer type [-Wincompatible-pointer-types]

My code works the way I intend it to as far as I can tell through testing, but I would like to understand if I am doing anything "wrong" here or if there is a way to do what I want without throwing warnings for every assignment.

Note that thing foo = {1, 2, &bar1 }; (passing the address of a function pointer) makes no difference for this warning.


Solution

  • In this code:

    typedef struct thing thing_type;
    
    typedef struct
    {
        int a;
        int b;
    
        double (*bar)(thing_type *t)
    } thing;
    

    the first typedef defines thing_type to be an alias for struct thing, and the second typedef defines thing to be an alias for a structure with no tag. This second alias, thing, has no relationship with the first alias, thing_type, or with its structure type, struct thing. In particular, there is no connection between the two types thing and struct thing.

    Similarly, in this code:

    typedef struct
    {
        int a;
        int b;
    
        double (*bar)(struct thing *t)
    } thing;
    

    the typedef defines thing to be an alias for a structure with no tag, and bar is declared to be a pointer to a function with a parameter type of struct thing *. Again, there is no connection between the two types thing and struct thing.

    To refer to the same structure type in multiple places, you must use a tag for it. This is as simple as:

    // Use the structure tag while defining the structure:
    typedef struct MyTag
    {
        int a;
        int b;
        double (*bar)(struct MyTag *);
    } MyAlias;
    

    or:

    // Define an alias first, then the structure definition can use the alias:
    typedef struct MyTag MyAlias;
    struct MyTag
    {
        int a;
        int b;
        double (*bar)(MyAlias *);
    };