How pointers to function as struct member useful in C?

限于喜欢 提交于 2019-11-27 21:38:25
tomahh

Providing a pointer to function on a structure can enable you to dynamically choose which function to perform on a structure.

struct newtype{
    int a;
    int b;
    char c;
    int (*f)(struct newtype*);
} var;


int fun1(struct newtype* v){
        return v->a;
    }

int fun2(struct newtype* v){
        return v->b;
    }

void usevar(struct newtype* v) {
   // at this step, you have no idea of which function will be called
   var.f(&var);
}

int main(){
        if (/* some test to define what function you want)*/) 
          var.f=fun1;
        else
          var.f=fun2;
        usevar(var);
    }

This gives you the ability to have a single calling interface, but calling two different functions depending on if your test is valid or not.

Its useful if you're trying to do some sort of "object based" programming.

If you've ever seen the Quake 3 engine's source code.. you can see clearly that most "entities" have attributes that define them, and the work they do[which are the function pointers].

Segregating attributes and functions(through function pointers in C) defines a "struct" object's attributes and actions they can do.

For example:

struct _man{
   char name[];
   int age;
   void (*speak)(char *text);
   void (*eat)(Food *foodptr);
   void (*sleep)(int hours); 
   /*etc*/
};

void grijesh_speak(char *text)
{
   //speak;
}

void grijesh_eat(Food *food)
{
   //eat
}

void grijesh_sleep(int hours)
{
   //sleep
}

void init_struct(struct _man *man)
{
    if(man == NULL){ man = malloc(sizeof(struct _man));}
      strcpy(*man.name,"Grijesh");
      man->age = 25;
      man->speak = grijesh_speak;
      man->eat = grijesh_food;
      man->sleep = grijesh_sleep;
//etc
}

//so now in main.. i can tell you to either speak, or eat or sleep.

int main(int argc, char *argv[])
{
    struct _man grijesh;
    init_struct(&grijesh);
    grijesh.speak("Babble Dabble");
    grijesh.sleep(10);
    return 0;
}

I've used this in the past to implement generic containers1 in C.

For example:

typedef struct generic_list_node {
  void *data;
  struct generic_list_node *next;
} generic_list_node_t;

typedef struct generic_list {
  generic_list_node_t *head;
  void *(*copy)(void *data);                 
  void (*delete)(void *data);                
  int (*compare)(void *lhs, void *rhs);      
  void (*display)(void *data, FILE *stream);
} generic_list_t;

The list structure itself is data-agnostic, using void * to represent data items, and delegates all type-aware operations to the functions indicated by the pointers above:

int insert(generic_list_t l, void *data)
{
  generic_list_node_t *cur = l.head;
  generic_list_node_t *new = malloc(sizeof *new);
  if (new)
  {
    new->data = l.copy(data);
    new->next = NULL;

    if (l.head == NULL)
    {
      l.head = new;
    }
    else
    {
      while (cur->next && l.compare(new->data, cur->data) > 0)
        cur = cur->next;
      new->next = cur->next;
      cur->next = new;
      printf("Successfully added ");
      l.display(data, stdout);
      printf(" to list\n");

    }
    return 1;
  }

  return 0;
}

1. For suitably loose definitions of "generic" and "container"

This can be particuarly useful in embedded system, or driver writing. The functions are called using function pointers.

e.g.

struct_my_filesystem.open=my_open;
struct_my_filesystem.read=my_read;

etc

Sometimes in C you need to call a function, without knowing its implementation upfront. E.g. if you're developing a stand-alone library used in different projects. In that case, it makes perfect sense to add a function pointer to a context struct and pass that along to the library functions. The library functions can then call your function at run-time without having to include the header files that define it.

It is indeed similar to what you do when doing Object Oriented programming. In C, you usually pass around context variables, e.g. a struct, grouping together a set of variables and possibly functions that are meaningful for that context. This is close to the eqvuivalent in OO programming, where you instantiate a class and set the required variables on the instance.

Here is a project to help explain the usefulness of function pointers. Try to create a c-based library providing inheritance and polymorphism. Or, try and recreate "C with Classes". Function pointers inside structures will be vital. http://www.cs.rit.edu/~ats/books/ooc.pdf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!