3

How can I use function pointers in a struct using the struct as argument?

I have this:

typedef struct button {
    char SizeUnit;
    char Status;
    
    int Width;
    int Height;
    
    
    char *Text;
    Color TextColor;
    Color BGColor;
    Color BorderColor;
    int BorderWidth;
    
    
    void (*ActionL)(button *bt);
    void (*ActionR)(button *bt);
    void (*ActionM)(button *bt);
    
    void (*Hover) (button *bt);
    void (*draw) (button *bt);
} button;

How can I get this working?

4
  • 4
    I should think that you simply write struct button *? Because when the function pointer definitions are encountered, the typedef hasn't been encountered yet. (Or rather, is in the middle of being processed.) Commented Jul 17, 2020 at 16:00
  • 1
    Either use struct button * as mentioned by @Peter above, or declare the typedef first, like this: typedef struct button button; struct button { ... };. Commented Jul 17, 2020 at 16:08
  • 1
    Or, just stop typedef'ing your structs. Typedefs are great for function types, and for opaque types, but frankly they are mere obfuscation when applied to structs. Commented Jul 17, 2020 at 16:11
  • Your attempt to fake C++-style member functions will result in unexpected interfaces as the following is a valid call: buttonA->draw(buttonB); Despite being called on object buttonA, it will indeed draw buttonB. And a sensible call buttonA->draw(buttonA); violates the don't-repeat-yourself rule. Commented Jul 17, 2020 at 17:28

2 Answers 2

7

The "effects" of the typedef (the symbol being recognized) are not available in the struct itself.

You have two options:

  1. Simply reference struct button when it comes to define function pointers

     void (*ActionL)(struct button *bt);`
    
  2. Write the typedef before the struct defintion (forward declaration):

     typedef struct button_s button_t;
    
     typedef  struct button_s {
         char SizeUnit;
         char Status;
    
         int Width;
         int Height;
    
         char *Text;
         Color TextColor;
         Color BGColor;
         Color BorderColor;
         int BorderWidth;
    
         void (*ActionL)(button_t *bt);
         void (*ActionR)(button_t *bt);
         void (*ActionM)(button_t *bt);
    
         void (*Hover) (button_t *bt);
         void (*draw) (button_t *bt);
     } button_t;
    

    Here I used a convention with a trailing _s for the struct before the typedef and _t for the newly defined type.

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

Comments

1

Beside Roberto's answer I want to go a little deeper on his point 1. This is one thing, where structs are more beneficial than typedefs.

When you use structure tags as references for pointers only, you can omit the forward declaration of the specific structure tag. The structure is incomplete and completed at its later following definition.

Related:

When you use a typedef instead, the alias needs to be defined before. This is a disadvantage.

Thus, This is completely valid (Proof):

Note that you can omit the typedefs here if you want to, as they are at least in this piece of code redundant. But if you use the, they don't conflict with the incomplete structure declarations as both reside in different namespaces and you need to use the struct keyword to symbolize the structure (tag).

#include <stdio.h>

typedef struct Color {
    unsigned int red;
    unsigned int green;
    unsigned int blue;
} Color;


struct button {
    char SizeUnit;
    char Status;
    
    int Width;
    int Height;
    
    
    char *Text;
    struct Color TextColor;
    struct Color BGColor;
    struct Color BorderColor;
    int BorderWidth;
    
    
    void (*ActionL)(struct button *bt);
    void (*ActionR)(struct button *bt);
    void (*ActionM)(struct button *bt);
    
    void (*Hover) (struct button *bt);
    void (*draw) (struct button *bt);
} button;

I personally tend to not use typedefs at all. This is subject to:

Comments

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.