Store function pointer passed from a function - c

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);
}

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);
}

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");

Related

Alternating behaviour of a function: How to detect function caller?

I have a function that toggles a flag everytime when it is called, which is done repeatedly, to have a alternating behaviour everytime the function is called. But what if i call the function multiple times, with different parameters? Of course my toggle-flag should only be toggled by the same function call. Is there a way to detect, have kind of a static behaviour of the flag, but one behaviour for each function caller?
void showText(uint8_t col, uint8_t line, const char *text, bool blinking)
{
if(blinking)
{
static bool flag = false;
if(flag)
{
lcd_setcursor(col, line);
for(int i = 0; i < strlen(text); i++)
{
lcd_data(' ');
}
}
else
{
lcd_setcursor(col, line);
lcd_string(text);
}
flag = !flag;
}
else
{
lcd_setcursor(col, line);
lcd_string(text);
}
}
void showText( uint8_t col, uint8_t line, const char *text, bool blinking, bool* flag_ptr ) {
...
if ( *flag_ptr ) { ... } else { ... }
*flag_ptr = !*flag_ptr;
...
}
Call site A:
static bool flag = false;
showText( ..., &flag );
Call site B:
static bool flag = false;
showText( ..., &flag );
You could also have the flag pointer be the decision for blinking itself:
static bool blinkstat1 = false;
static bool blinkstat2 = false;
// Show with blinking
showText(col1, line1, text1, &blinkstat1);
// Show with blinking
showText(col2, line2, text2, &blinkstat2);
// Show text1 again w/o blinking
showText(col1, line1, text1, NULL);
void showText(uint8_t col, uint8_t line, const char *text, bool* blinking ) {
lcd_setcursor(col, line);
if (blinking != NULL) {
// Blink
if ( *blinking ) {
for(int i = 0; i < strlen(text); i++) {
lcd_data(' ');
}
} else {
lcd_string(text);
}
*blinking = !*blinking;
} else {
// Just show text non-blinking
lcd_string(text);
}
}

Calling a function with a pointer does not change value of that pointer? [duplicate]

This question already has answers here:
Pointers as function arguments in C
(7 answers)
Closed 3 years ago.
When I call the "InitAnimation" function, I pass the the address of my object RG. When I assign the "animationName" field of that object, I can successfully print that field.
But when I return to main and call the function "ReportAnimation", I am unable to print that value and my program crashes ?
How come when I assigned that objects field it is not changed globally but only in the local function ?
I have tried allocating memory for the animationName field as well but that does not work.
struct Frame {
char* frameName;
struct Frame* pNext;
};
typedef struct {
char* animationName;
struct Frame* frames;
}Animation;
int main(void) {
char response;
BOOL RUNNING = TRUE;
Animation RG;
InitAnimation(&RG);
while (RUNNING) {
printf("MENU\n Enter 1 to ReportAnimation\n");
scanf("%c", &response);
switch (response) {
case '1':InsertFrame(&RG);
break;
}
}
return 0;
}
void InitAnimation(Animation* pointer) {
pointer = (Animation*)malloc(sizeof(Animation));
char* input;
input = (char*)malloc(sizeof(input));
printf("Please enter the Animation name:");
fgets(input, 32, stdin);
//pointer->animationName = (char*)malloc(sizeof(char)*10);
//Setting animation name
pointer->animationName = input;
//This print function works
printf("\nThe name is %s", pointer->animationName);
}
void ReportAnimation(Animation* pointer) {
//This print function does not work
printf("Animation name is %s\n", pointer->animationName);
}
I want the initAnimation function to change the field of the Animation struct
and I want the reportAnimation function to print out the field, proving its changed
Changing the value of a function's variable (including those declared as parameters) has no effect on the caller.
void bad1(int i) {
i = 1; // No effect on the caller.
}
void bad2(void* p) {
p = NULL; // No effect on the caller.
}
If you want to change a variable in the caller, you will need to pass a pointer to it.
void good1(int* i_ptr) {
*i_ptr = 1;
}
void good2(void** p_ptr) {
*p_ptr = NULL;
}
So either pass a pointer to a pointer, or pass a pointer to an-already allocated structure. You could use
Animation ani;
Animation_init(&ani, name);
...
Frame* frame = Frame_new(name);
Animation_append_frame(&ani, frame);
...
Animation_destroy(&ani);
or
Animation* ani = Animation_new(name);
...
Frame* frame = Frame_new(name);
Animation_append_frame(ani, frame);
...
Animation_delete(ani);
assuming you had
typedef struct Frame {
char* name;
struct Frame* next;
} Frame;
typedef struct {
char* name;
Frame* first_frame;
Frame* last_frame;
} Animation;
void Animation_init(Animation* self, const char* name) {
self->name = strdup(name);
self->first_frame = NULL;
self->last_frame = NULL;
}
void Animation_destroy(Animation* self) {
Frame* head = self->first_frame;
while (head != NULL) {
Frame* next = head->next;
Frame_delete(head);
head = next;
}
free(self->name);
}
Animation* Animation_new(const char* name) {
Animation* self = malloc(sizeof(Animation));
Animation_init(self, name);
return self;
}
void Animation_delete(Animation* self) {
Animation_destroy(self);
free(self);
}
void Animation_append_frame(Animation* self, Frame* frame) {
if (self->last_frame == NULL) {
self->first_frame = frame;
} else {
self->last_frame->next = frame;
}
while (frame->next != NULL)
frame = frame->next;
self->last_frame = frame;
}

How to get pointer address in function that called through this pointer

I read this article but it doesn't answer my question.
file: hero.h
typedef struct {
int id;
void (*setId)();
int (*getId)();
} Hero, *HeroPtr;
file: hero.c
#include "hero.h"
static void setId(int id);
Hero obj = {
.setId = setId,
.getId = getId,
};
void setId(int id) {
HeroPtr hero_obj = 0x0; //TODO how get address: hero_obj1 (1 > ) OR
// hero_obj2 (2 > )
hero_obj->id = id;
}
void getId() {
HeroPtr hero_obj = 0x0; //TODO how get address: hero_obj1 (1 > ) OR
// hero_obj2 (2 > )
return hero_obj->id;
}
file: main.c
#include "hero.h"
int main() {
Hero hero_obj1, hero_obj2;
//1 >
hero_obj1->setId(1);
//2 >
hero_obj2->setId(2);
return 0;
}
You could do the equivalent of what C++ does behind the scenes.
file: hero.h
typedef struct hero {
int id;
void (*setId)(struct hero*, int);
int (*getId)(struct hero*);
} Hero, *HeroPtr;
void constructHero(HeroPtr this);
file: hero.c
#include "hero.h"
static void setId(HeroPtr this, int id);
static int getId(HeroPtr this);
Hero initObj = {
.setId = &setId,
.getId = &getId,
};
void constructHero(HeroPtr this)
{
*this = initObj;
}
void setId(HeroPtr this, int id) {
HeroPtr hero_obj = this;
hero_obj->id = id;
}
int getId(HeroPtr this) {
HeroPtr hero_obj = this;
return hero_obj->id;
}
file: main.c
#include "hero.h"
#include "stdio.h"
int main() {
Hero hero1;
Hero hero2;
HeroPtr hero_obj1=&hero1;
HeroPtr hero_obj2=&hero2;
constructHero(hero_obj1);
constructHero(hero_obj2);
hero_obj1->setId(hero_obj1, 1);
hero_obj2->setId(hero_obj2, 2);
printf("hero_obj1 id = %d\n", hero_obj1->getId(hero_obj1));
printf("hero_obj2 id = %d\n", hero_obj2->getId(hero_obj2));
return 0;
}
It looks like you are trying to implement virtual functions in C, by using function pointers. In object-oriented programming languages like C++ or Java such functions or methods inside classes have an implicit this pointer as argument, which is hidden. That means that the int getId() function actually has the signature int getId(Hero* this) and the void setId(int id) function actually has the form void setId(Hero* this, int id). As I have already said, in object-oriented programming languages you don't see or add the this pointer and you also don't pass the argument when you invoke the function. The compiler does this for you. It always automatically passes the pointer to the instance as this pointer, on which the function was invoked. In C, however, these features don't exist. So you have to add the this argument and pass it when invoking the function by yourself.

How to reduce the complexity of a GUI program

There is a problem confused me a lot.
I use C language to display GUI in the Embedded device.Just like the following example.
  title
1.xxxx 2.xxxx
3.xxxx 4.xxxx
5.xxxx 6.xxxx
I use the keypad to choose which item i need.but the item often has is's sub-item and I have to draw the menu and set the function again.Just like the follwing shows.
  title             title             title
1.xxxx 2.xxxx  press 1  1.xxxx 2.xxxx press 2   1.xxxx 2.xxxx
3.xxxx 4.xxxx --------------> 3.xxxx 4.xxxx --------------> 3.xxxx 4.xxxx
5.xxxx 6.xxxx       5.xxxx 6.xxxx       5.xxxx 6.xxxx
Now I use the following code temple to set the function i need.
GrawAndGetKeyCode( "0.xxxx||1.xxxx||2.xxxx||3.xxxx||4.xxxx", "title", &nSelect);
switch(nSelect)
{
case 0:
fuction();
break;
case 1:
fuction();
break;
case 2:
fuction();
break;
case 3:
fuction();
break;
case 4:
fuction();
break;
default:
break;
}
I wonder if there is some way i can use the menu1.item1.subitem2() to figure out the function i need?
Thanks a lot!!!
A simple menu system like that could be implemented using a simple state-machine.
Maybe something like this (warning: pseudo-ish code):
typedef void (*handler_t)(void); // Menu handler function type
handler_t * current_handlers;
char *current_menu;
// The top-level menu
handler_t top_menu_handlers[] = {
top_menu_1,
top_menu_2,
top_menu_3
};
char *top_menu = "..."; // Menu text for the top menu
// One sub-menu
handler_t sub_menu_1_handlers[] = {
sub_menu_1_1,
sub_menu_1_2,
sub_menu_1_3
};
char *sub_menu_1 = "...";
// Another sub-menu
handler_t sub_menu_2_handlers[] = {
sub_menu_2_1,
sub_menu_2_2,
sub_menu_2_3
};
char *sub_menu_2 = "...";
// ...
// Initialization
current_handlers = top_menu_handlers;
current_menu = top_menu;
// The state machine
for (;;) // Infinite loop
{
clear_screen();
print_menu(current_menu);
int selection = get_input();
current_handlers[selection](); // Call menu function
}
// ...
void top_menu_1(void)
{
// When user selects `1` in the top menu, go to first sub-menu
current_handlers = sub_menu_1_handlers;
current_menu = sub_menu_1;
}
// ...
void sub_menu_1_3(void)
{
// When the user select `3` in the first sub-menu, go back to top menu
current_handlers = top_menu_handlers;
current_menu = top_menu;
}
It's a lot of work to set up initially, but then it makes the code more general, and it's easier to add new alternatives or menus. And most importantly, it can be much more automated (by e.g. making the menu tree into an actual tree structure, and making the state-machine code handle the menu changing instead of having handler functions change it).
You may have a structure for menu items, each structure contains a label to be shown and a function pointer to be invoked. Then, your DrawMenuAndExecute function may take an array of menu_items and draw them, take the input and execute the corresponding function. Here is a working example:
#include <stdio.h>
#include <stdlib.h>
typedef void (* MENUFUNCPTR)();
struct menu_item {
const char *menu_item;
MENUFUNCPTR func;
};
void DrawMenuAndExecute(struct menu_item *items, size_t n) {
size_t i;
int opt;
int cont = 1;
// draw the menu
for (i = 0; i < n; ++i) {
printf("%3d: %s\n", (int)(i+1), items[i].menu_item);
}
printf("Your selection: ");
while (cont) {
scanf("%d", &opt);
if (opt > 0 && opt <= n) {
cont = 0;
}
else {
printf("Wrong selection, your selection again: ");
}
}
opt--;
if (items[opt].func != NULL) {
(*(items[opt].func))();
}
}
void main_menu();
void item1_item1();
void item1_item2();
void item1();
void item2();
void item3();
void item4();
void main_menu() {
struct menu_item items [] = {
{ "Item 1 (has submenu)", &item1 },
{ "Item 2 (count to ten)", &item2 },
{ "Item 3 (write something)", &item3 },
{ "Exit", &item4 }
};
DrawMenuAndExecute(items, 4);
}
void item1_item1() {
printf("Hello, how're you? (since I don't care, I won't let you type.)\n");
item1();
}
void item1_item2() {
main_menu();
}
void item1() {
// item1 has a sub menu
struct menu_item items [] = {
{ "Write something", &item1_item1 },
{ "Previous Menu", &item1_item2 }
};
DrawMenuAndExecute(items, 2);
}
void item2() {
int i = 1;
for (; i <= 10; ++i) {
printf("%d ", i);
}
printf("\n");
main_menu();
}
void item3() {
printf("Something.\n");
main_menu();
}
void item4() {
exit(0);
}
int main(int argc, char **argv) {
main_menu();
}

How to implement a stack containing function call for a PIC in C

I'm currently programming a PIC in C with MPLAB X (+ compiler XC8)
In my code, I have some interruptions (inter1, inter2, ..) which are each composed of urgent and non-urgent operations (urg1, urg2, .., n_urg1, n_urg2, ..).
So I'd like a code with the following structure :
stack s; // FIFO or other
main() {
while (true) {
if (!isEmpty(s)) {
doNextFunction(s);
}
}
}
void interrupt inter1() {
urg1(); // urgent code
addStack(n_urg1);
}
void n_urg1() {
// non-urgent code
}
How can I implement that kind of stack ? Is there something in the standard library ?
If I remember correct, then that compiler is rather primitive, I don't think you can use the std library.
If you need to implement it all by yourself, you can use an array of function pointers:
#include <string.h> // for memmove()
#define STACK_MAX 10
typedef enum
{
Int,
Boolean
} VariantType;
typedef struct
{
VariantType type;
union {
int intValue;
bool booleanValue;
} value;
} Variant;
typedef bool (*FunctionPtr)(Variant data);
typedef struct
{
FunctionPtr ptr;
Variant var;
} FunctionCall;
FunctionCall functionStack[STACK_MAX];
int functionStackUse = 0;
bool addStack(FunctionPtr ptr, Variant var)
{
if (functionStackUse >= STACK_MAX)
return false; // stack full
functionStack[functionStackUse].ptr = ptr;
functionStack[functionStackUse].var = var;
functionStackUse++;
return true;
}
bool callNextFunction(void)
{
// TODO: disable inter1
if (functionStackUse > 0)
{
// get first function on stack
FunctionCall functionCall = functionStack[0];
functionStackUse--;
// remove first function from stack
memmove((void*)functionStack, (void*)(functionStack + 1), functionStackUse * sizeof(functionStack[0]));
// TODO: re-enable inter1
// call function with arguments
return (*functionCall.ptr)(functionCall.var);
}
else
{
// TODO: re-enable inter1
return false; // no more functions
}
}
void main()
{
while (1)
{
callNextFunction();
// TODO add some delay otherwise you're constantly disabling inter1 (in doNextFunction)
}
}
bool n_urg1(Variant var)
{
if (var.type == Int)
{
int i = var.value.intValue;
// do something
return true;
}
return false;
}
void inter1(void)
{
Variant var;
var.type = Int;
var.value.intValue = 45;
addStack(n_urg1, var);
}

Resources