1

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?

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
  • 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.) – Peter - Reinstate Monica Jul 17 '20 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 { ... };`. – Ian Abbott Jul 17 '20 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. – William Pursell Jul 17 '20 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. – bitmask Jul 17 '20 at 17:28

2 Answers2

5

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.

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
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: