JB_DELR
JB_DELR

Reputation: 777

Store function pointer passed from a function

I'm trying to store a function pointer in a struct and can't make it works. Here's the code.

typedef enum { POUSSOIR, INTERRUPTEUR } Button_Type;
typedef struct Button {
    char name[20];
    Button_Type type;
    void(*action)(struct Button*);
    char input[20];
    char output[20];
} Button;

static Button buttons[7];

Button Button_Create(char *name, Button_Type type, void (*action), char input[20], char output[20]) {
    Button this;
    strcpy(this.name, name);
    this.type = type;
    this.action = (*action)(&this);
    strcpy(this.input, input);
    strcpy(this.output, output);
    return this;
}

void dimmer(Button *button) {
    LOG("dim!!!");
}

int init_Buttons() {
    buttons[0] = Button_Create("Salon", POUSSOIR, &dimmer, "DI04", "DMX_2");
    return 1;
}

What I want is to have many buttons with differents callbacks for on-off case or dimmable case and more. So I wan't to init each button with a callback function. Also I can't pass the Button reference to Button_Create function as it doesn't exit yet. How can I acheive this ?

EDIT : SOLUTION

Button Button_Create(char *name, Button_Type type, void (*action)(Button*), char input[20], char output[20]) {
    Button this;
    strcpy(this.name, name);
    this.type = type;
    this.action = action;
    strcpy(this.input, input);
    strcpy(this.output, output);
    return this;
}

//as example
void *fn_ButtonThread(void *p_Data) {
    printf("Starting Button Thread.\r\n"); fflush(stdout);
    while(!exitFlag) {
      if (....) {
        // Call the function with parameters here
        buttons[0].action(&buttons[0]);
      }
    }
    printf("Stopping Button Thread.\r\n"); fflush(stdout);
}

Upvotes: 0

Views: 68

Answers (2)

Twenkid
Twenkid

Reputation: 955

Aren't the buttons created automatically by their declaration: static Button buttons[7]; They are not pointers, so that struct of 7 elements would be created. Also there are no system calls to CreateWindow etc.

Thus you can send &button[0] etc. as parameters to set their values. The code below compiles and prints "DI04" and "DMX_2", VS2019. (I haven't tested the function pointers).

typedef enum { POUSSOIR, INTERRUPTEUR } Button_Type;
typedef struct Button {
    char name[20];
    Button_Type type;
    void(*action)(Button*);
    char input[20];
    char output[20];
} Button;

static Button buttons[7];

void LOG(const char* s) {
    printf_s(s);
}
void Button_Create(Button &b, const char* name, Button_Type type, void(*action)(Button*), const char input[20], const char output[20]) {
    //Button this;
    strcpy_s(b.name, name);
    b.type = type;
    b.action = action; // (*action)(&b);
    strcpy_s(b.input, input);
    strcpy_s(b.output, output);        
}

void dimmer(Button* button) {
    LOG("dim!!!");
}

int init_Buttons() {
    //buttons[0] = Button_Create("Salon", POUSSOIR, &dimmer, "DI04", "DMX_2");
    Button_Create(buttons[0], "Salon", POUSSOIR, &dimmer, "DI04", "DMX_2");
    printf_s(buttons[0].input);
    printf_s("\n");
    printf_s(buttons[0].output);
    return 1;
}

int main()
{
    init_Buttons();

    return 0; //or whatever
}
enter code here

EDIT: (Button this; Ah plain C?... It's confusing with C++ this. Without references &:

void Button_Create_Ptr(Button *b, const char* name, Button_Type type, void(*action)(Button*), const char input[20], const char output[20]) {
    //Button this;
    strcpy_s(b->name, name);
    b->type = type;
    b->action = action; // (*action)(&b);
    strcpy_s(b->input, input);
    strcpy_s(b->output, output);        
}

Then: Button_Create_Ptr(&buttons[1], "Baloon", POUSSOIR, &dimmer, "GYZ1", "BTS2");

Upvotes: 1

Ian Abbott
Ian Abbott

Reputation: 17403

The declaration of the action parameter in Button_Create and the setting of this.action is wrong. Here is a corrected version:

Button Button_Create(char *name, Button_Type type, void (*action)(Button *), char input[20], char output[20]) {
    Button this;
    strcpy(this.name, name);
    this.type = type;
    this.action = action;
    strcpy(this.input, input);
    strcpy(this.output, output);
    return this;
}

In the call to Button_Create you can change &dimmer to dimmer. It will work either way because dimmer is already considered to be a pointer to the function defined as dimmer and the & is ignored in this case. (Function pointers behave differently to object pointers in that regard.)

You could call a function defined as follows to invoke the action:

void Button_Press(Button *button) {
    button->action(button);
}

Upvotes: 1

Related Questions