How to use a function pointer in a C struct? - c

I want to learn more about using function pointers in C structs as a way to emulate objects-oriented programming, but in my search, I've just found questions like this where the answer is simply to use a function pointer without describing how that would work.
My best guess is something like this
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create() {
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
But that give me compiler warnings warning: assignment from incompatible pointer type, so obviously I'm doing something wrong. Could someone please provide a small but complete example of how to use a function pointer in a C struct correctly?
My class taught in C does not even mention these. It makes me wonder whether these are actually used by C programmers. What are the advantages and disadvantages of using function pointers in C structs?

The answer given by Andy Stow Away fixes my compiler warning, but doesn't answer my second question. The comments to that answer given by eddieantonio and Niklas R answer my second question, but don't fix my compiler warning. So I'm pooling them together into one answer.
C is not object-oriented and attempting to emulate object-oriented design in C usually results in bad style. Duplicating methods called on structs so that they can be called using a pointer to the struct as I have in my example is no exception. (And frankly, it violates DRY.) Function pointers in structs are more useful for polymorphism. For example, if I had a struct vector that represented a generic container for a linear sequence of elements, it might be useful to store a comparison_func member that was a function pointer to allow sorting and searching through the vector. Each instance of the vector could use a different comparison function. However, in the case of a function that operates on the struct itself, it is better style to have a single separate function that is not duplicated in the struct.
This makes the answer to what is correct more complicated. Is what is correct how to make my above example compile? Is it how to reformat my above example so that it has good style? Or is it what is an example of a struct that uses a function pointer the way C programmer would do it? In formulating my question, I did not anticipate the answer being that my question was wrong. For completeness, I will provide an example of each answer to the question.
Fixing the Compiler Warning
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*, int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
Reformatting the Style
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
};
void my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
my_struct_set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
Demonstrating a Use for Function Pointer in Structs
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct my_struct
{
void* data;
int (*compare_func)(const void*, const void*);
};
int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
return m->compare_func(m->data, comparable);
}
struct my_struct* my_struct_create(void* initial_data,
int (*compare_func)(const void*, const void*))
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = initial_data;
result->compare_func = compare_func;
return result;
}
int int_compare(const void* a_pointer, const void* b_pointer)
{
return *(int*)a_pointer - *(int*) b_pointer;
}
int string_compare(const void* a_pointer, const void* b_pointer)
{
return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}
int main(int argc, const char* argv[])
{
int int_data = 42;
struct my_struct* int_comparator =
my_struct_create(&int_data, int_compare);
char* string_data = "Hello world";
struct my_struct* string_comparator =
my_struct_create(&string_data, string_compare);
int int_comparable = 42;
if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
{
printf("The two ints are equal.\n");
}
char* string_comparable = "Goodbye world";
if (my_struct_compare_to_data(string_comparator,
&string_comparable) > 0)
{
printf("The first string comes after the second.\n");
}
free(int_comparator);
free(string_comparator);
return 0;
}

In your struct definition, change it to
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*,int);
};
and now use the above function pointer in main as
thing->set_data(thing,1);

Related

Ways to illicit polymorphic properties in regular C?

Hi I am currently attempting to learn C and I was wondering if there is a way to attain polymorphism in structures which contain a list of other different type of structures?
An example case of this is as such:
#include <stdlib.h>
#include <stdio.h>
typedef void (*update_t)(void *);
typedef struct entity entity_t;
typedef struct compA compA_t;
typedef struct compB compB_t;
struct compA{
update_t update;
};
struct compB{
update_t update;
};
struct entity{
update_t update;
int curSize;
void **components;
};
void compA_update(void *c){
printf("updating: componentA\n");
}
compA_t *compA_create(){
compA_t *c = malloc(sizeof(compA_t));
c->update = compA_update;
return c;
}
void compB_update(void *c){
printf("updating: componentB\n");
}
compB_t *compB_create(){
compB_t *c = malloc(sizeof(compB_t));
c->update = compB_update;
return c;
}
void entity_update(void *en){
entity_t *e = (entity_t *)en;
for(int i = 0; i < e->curSize; i++){
//would like to somehow update all the components with one line just iterating through the array but does not seem possible
}
return;
}
entity_t *entity_create(){
entity_t *e = malloc(sizeof(entity_t));
e->curSize = 0;
e->update = entity_update;
calloc(32, sizeof(void *));
return e;
}
void add_component(entity_t *e, void *c){
printf("%d\n", e->curSize);
e->components[e->curSize] = c;
e->curSize++;
return;
}
int main(void){
entity_t *e = entity_create();
compA_t *a = compA_create();
compB_t *b = compB_create();
add_component(e, a);
add_component(e, b);
e->update(e);
return 0;
}
So far my approach to this problem has been solved with void pointer arrays of a tuple structure which contains a enum type which identifies the structure as well as the structure itself and then in a potential update function a fairly ugly switch statement has to be implemented with a case for each specific type.
Is there a better way to do this? As the switch approach will get fairly crazy pretty fast if there are a lot of different types within the array. which means one must explicitly add cases for each type and every case does exactly the same thing, which in this case is call a function pointer named "update".
You can try data polymorphism instead of function pointer. That is, different data produce different behavior, using the same code.
For example, a simple polymorphic behavior:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
typedef const char* ccstr;
typedef struct animal_attr_t
{
bool is_body_segmented;
float gill_completeness;
float lung_completeness;
} animal_attr_t;
typedef struct species
{
ccstr name, kingdom, domain;
animal_attr_t animal_attr[0];
} species;
void initialize_species_base(species *this, ccstr name, ccstr kingdom, ccstr domain)
{
this->name = name;
this->kingdom = kingdom;
this->domain = domain;
}
void initialize_animal_attr(animal_attr_t *this, bool is_body_segmented, float gill_completenss, float lung_completeness)
{
this->is_body_segmented = is_body_segmented;
this->gill_completeness = gill_completenss;
this->lung_completeness = lung_completeness;
}
void print_species(species*);
int main(int argc, char *argv[])
{
species *yeast = calloc(sizeof(species), 1);
assert(yeast);
initialize_species_base(yeast, "yeast", "fungus", "eukaryote");
print_species(yeast);
species *dog = calloc(sizeof(species) + sizeof(animal_attr_t), 1);
assert(dog);
initialize_species_base(dog, "dog", "animal", "eukaryote");
initialize_animal_attr(dog->animal_attr, true, 0.0f, 1.0f);
print_species(dog);
free(yeast);
free(dog);
}
void print_species(species *this)
{
printf("name = %s, kingdom = %s, domain = %s",
this->name, this->kingdom, this->domain);
if (strcmp(this->kingdom, "animal") == 0) {
animal_attr_t *ani_attr = this->animal_attr;
printf(", has %s, %f completeness of gill, %f completeness of lung",
ani_attr->is_body_segmented ? "segmented body" : "unsegmented body",
ani_attr->gill_completeness, ani_attr->lung_completeness);
}
printf(".\n");
}
yeast and dog is 2 completely different types, yet with species it is expressed in an unified way and print_species has polymorphic behavior.

Return Pointer from function

I am new in C and literally trying to return pointer from my function to the pointer variable and have this "[Warning] assignment makes pointer from integer without a cast" no idea why compiler defines it as an int.
Can't declare my function before main as well, it throws this "undefined reference to `free_block'".
#include <stdio.h>
#include <stdlib.h>
struct block{
int num;
};
int main(int argc, char *argv[]) {
struct block *b;
b = free_block();
struct block *free_block(){
struct block *b = NULL;
return b;
}
return 0;
}
Thank you
Yea, my fault I know not too much about c syntax and had no idea about nested functions, soz.
But what could be wrong in this case:
I am trying to make my own memory allocator without using malloc or calloc functions. In my code I have the same Warning on the line with pointer = free_space_get(size);, here I have no more nested func(), my methods defined before main(), but still have no idea do I have to declare my functions or no, coz in the answer given to me it worked fine as soon as functions were defined before the main().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct header{
size_t size;
struct header *next;
unsigned int free;
};
void *m_alloc(size_t size){
size_t total_size;
void *block;
struct header *pointer;
if(!size)
return NULL;
pointer = free_space_get(size);
if(pointer){
pointer->free = 0;
return (void*)(pointer + 1);
}
}
struct header *get_free_space(size_t size){
struct header *b = NULL;
return b;
}
int main() {
return 0;
}
Your code can be re-written as
#include <stdio.h>
#include <stdlib.h>
struct block{
int num;
};
struct block *free_block(){
struct block *b = NULL;
return b;
}
int main(int argc, char *argv[]) {
struct block *b;
b = free_block();
if(b == NULL) // Checking whether pointer is returned
printf("\n Recieved NULL \n");
return 0;
}

object oriented C - variables in struct + pro's and cons

I am a young student who learned C two years ago. I just discovered more complex things like object oriented C.
My first question is:
1) How do you access your variables? The goal would be to have specific values for those variables depending on the struct which has been instantiated.
So I'd like something like:
myStruct* myStrPtr;
myStruct2* myStrPtr;
myStrPtr = initializeStruct();
myStrPtr->printContent //prints for example 55
myStrPtr2 = initializeStruct();
myStrPtr2->printContent //prints for example 6548
example
typedef struct {
void (*sum)(int a, int b);
void (*printContent)(void);
int content;
}myStruct;
void printInhoud(void){
printf("content: %d\n", content);}
void sum(int a, int b){
/***********THIS DOESN T WORK OBVIOUSLY************/
this->content = a+b;
printf("calculated sum: %d", sum);
}
myStruct * initializeStruct(void)
{
myStruct* myStrPtr = malloc(sizeof(myStruct));
myStrPtr -> foo = foo ;
mynStrPtr->printContent = printContent;
return myStrPtr;
}
void freeMem(myStruct * myStructPtr)
{
free(myStructPtr);
}
int main (void)
{
int a= 1;
int b=33;
myStruct* myStrPtr;
myStrPtr = initializeStruct();
myStrPtr->printContent();
return 0;
}
2) my second question is: what are pro's and con's about programming in this way? I think that if I am able to add the variables in the structures and access them just like in OOP, I get a big advantage: modularity. I am active in embedded software and believe that having such an advantage of OOP on an embedded system can be very interesting. I have been criticized for trying to do this. The only reason I was given: "You have no garbage collector, so don't". Could someone give me some pro's and con's and explain why this would be "such an incredibly bad programming practice"
You can do OOP in C, but one of the major cons is that you have to pass the this pointer around. Let's say you have a pointer to a printInfo() function in your struct and you want to print the info of that particular struct. You have to do
my_struct->printInfo(my_struct);
or, if my_struct is not a pointer to your struct
my_struct.printInfo(&my_struct);
There's no way around it.
For your second question, I'm not sure doing OOP in C is really practical. I have done it out of curiosity and it's really fun. You can get inheritance, virtual base classes, polymorphism and all. If you're interested you can check it out here:
https://github.com/vladcc/object-oriented-c
Disclaimer: I'm not sure that the following is truely an answer, but it is way too long for a comment.
Is it possible to do OOP in C?
Yes it is. First C++ compilers were mere pre-processors that converted C++ source to C. Of course, you have neither contructors not destructors so you must explicitely call them, you must use composition pattern for inheritance, you must have vtables for virtual methods and must explicitely pass the this pointer.
Simple example with ctor, dtor, a dynamic array and a method:
struct __foo {
int *arr;
int n;
};
typedef struct __foo foo;
bool init_foo(foo *f, int n) {
f->arr = malloc(n * sizeof(int));
f->n = n;
return (f->arr != NULL);
}
void clean_foo(foo *f) { free(f->arr); }
bool set(int index, int value, foo *f) { // same for get...
if ((index >= f->n) || (index < 0)) return false;
f->arr[index] = value;
return true;
}
Usage:
foo f;
init_foo(8, &f);
set(5, 2, &f);
clean_foo(&f);
More complex example with inheritance and virtual method :
typedef struct {
int age;
const char *name;
const char* (*say)(void *);
} animal;
typedef struct {
animal parent;
} dog;
typedef struct {
animal parent;
} cat;
void init_animal(int age, const char *name, animal *a) {
a->age = age;
a->name = name;
}
char *pre_say(animal *this) {
char * msg = malloc(strlen(this->name) + 11);
strcpy(msg, this->name);
strcat(msg, " says ");
return msg;
const char * wow(void *an) {
animal *this = (animal *) an;
char * msg = pre_say(this);
strcat(msg, "Woof");
return msg;
}
const char* meeow(void *an) {
animal *this = (animal *) an;
char * msg = pre_say(this);
strcat(msg, "Meew");
return msg;
}
void init_dog(int age, const char * name, dog *d) {
init_animal(age, name, &(d->parent));
d->say = &woof;
}
void init_cat(int age, const char * name, cat *c) {
init_animal(age, name, &(c->parent));
d->say = &meeow;
}
Usage example:
dog d;
init_dog(2, "Rintintin", &d);
cat c;
init_cat(3, "Tom", &c);
const char *msg = (d.say)(&d); // msg <- Rintintin says Woof
free(msg);
msg = (c.say)(&c); // msg <- Tom says Meew
free(msg);
Should we do OOP in C?
Definitely NO. As you can say from previous example, as soon as you need polymorphism, pointers must be void * and you loose all possible type checking. And you also loose all the C++ goodies of automatic construtors and destructors, automatic this pointer, etc. You end with much more code, much harder to read and debug. The only acceptable use cases (IMHO) are:
interfacing C++ and C
minimal conversion of C++ code for a platform where you have only a C compiler.
low level codes (kernel or high performance libraries) in which you do not want to be bored with the overhead of C++, and still need OOP.
And just remember: if C++ was invented, it must have been to fill a gap in C language. So don't try to do what C++ was created for in C, unless you really know why you do that.
Has Garbage Collector something to do with OOP?
Here again no. C++ has no garbage collection and is indeed an OO language.
Not only encapsulation, many other OOP concepts can be implemented using C with little bit effort.
Here is an example.
//
// cobj.h
//
#ifndef __COBJ_H__
#define __COBJ_H__
struct _cobj_priv;
typedef struct _cobj {
struct _cobj_priv *priv;
void (*set_data)(struct _cobj *obj, int data);
int (*get_data)(struct _cobj *obj);
void (*print_data)(struct _cobj *obj);
} cobj_t;
cobj_t *new_struct(void);
void free_struct(cobj_t *obj);
#endif /* __COBJ_H__ */
//
// cobj.c
//
#include "cobj.h"
#include <stdio.h>
#include <stdlib.h>
//
// Internal section
//
struct _cobj_priv {
int data;
};
static void set_data (struct _cobj *obj, int data) {
struct _cobj_priv *this = (obj && obj->priv) ? obj->priv: NULL;
if (this) {
this->data = data;
}
}
static int get_data (struct _cobj *obj) {
struct _cobj_priv *this = (obj && obj->priv) ? obj->priv: NULL;
return (this)? this->data : 0;
}
static void print_data (struct _cobj *obj) {
struct _cobj_priv *this = (obj && obj->priv) ? obj->priv: NULL;
if (this)
printf("%d\n", this->data);
}
//
// APIs section
//
cobj_t *new_struct(void) {
cobj_t *obj = malloc(sizeof(cobj_t));
if (obj) {
obj->priv = malloc(sizeof(struct _cobj_priv));
if (obj->priv) {
obj->priv->data = 0;
}
obj->set_data = &set_data;
obj->get_data = &get_data;
obj->print_data = &print_data;
}
return obj;
}
void free_struct(cobj_t *obj) {
if (obj) {
if (obj->priv)
free(obj->priv);
free(obj);
obj = null;
}
}
//
// main.c
//
#include "cobj.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
cobj_t *obj = new_struct();
if (obj) {
obj->print_data(obj);
obj->set_data(obj, 100);
obj->print_data(obj);
printf("> get data return %d\n", obj->get_data(obj));
}
return 0;
}
Result:
0
100
> get data return 100
In C, struct's methods are function pointers, they do not know about the existence of struct so that they can not access to the struct members. You need to pass the struct instance to methods as a parameter in order to access to its members.

Link Multiple Declarations to Same Definition

I have implemented a linked list in C (not C++) that stores pointers to data. I would like to have multiple declarations for its functions (to provide type safety), but have each of them link to the same definition (because there is no actual difference between pointers to different data types, so using the same code reduces space).
Does anyone have any ideas on how to achieve this (or any better ways to do it)? A portable solution is obviously best, but I really just need something that works in GCC.
I believe you might be able to achieve this using typedefs for function prototypes and
casting the generic solution (which deals in void*s) to the specific prototype. This should be safe for compilation because all pointers would be the same size.
Consider this example:
do_something.h:
typedef void (*do_something_with_int_t)(int *i);
extern do_something_with_int_t do_something_with_int;
typedef void (*do_something_with_string_t)(char *s);
extern do_something_with_string_t do_something_with_string;
do_something.c
#include "do_something.h"
void do_something_generic(void* p) {
// Do something generic with p
}
do_something_with_int_t do_something_with_int =
(do_something_with_int_t)do_something_generic;
do_something_with_string_t do_something_with_string =
(do_something_with_string_t)do_something_generic;
As long as do_something_generic is truly datatype-agnostic (i.e. it really doesn't matter what p points to) then this would be OK.
If it's C (not C++), then the following will work just fine. You can adapt the concept to your needs.
tt.h
typedef struct {
int ii;
} Type_1;
typedef struct {
int ii;
} Type_2;
int foo_1(Type_1* ptr) __attribute__((alias("foo")));
int foo_2(Type_2* ptr) __attribute__((alias("foo")));
tt.c
#include <stdio.h>
#include "tt.h"
int main() {
Type_1 t_1;
Type_2 t_2;
foo_1(&t_1);
foo_2(&t_2);
}
int foo(void* arg) {
printf("foo: %p\n", arg);
}
#include <stdio.h>
struct common_type {
int type;
};
struct type1 {
int type;
int value;
};
struct type2 {
int type;
char* p;
};
int func(void *para) {
switch (((struct common_type*)para)->type) {
case 1:
printf("type1,value:%d\n",((struct type1*)para)->value);
break;
case 2:
printf("type2,content:%s\n",((struct type2*)para)->p);
break;
}
}
int main() {
char *s = "word";
struct type1 t1 = {1,1};
struct type2 t2;
t2.type = 2;
t2.p = s;
func((void*)&t1);
func((void*)&t2);
}

struct as unknown argument

I know how to pass an unknown amount of arguments from unknown types to a function.
I mean something like this:
char* plugins_entry(const char* data, ...);
Now I am trying to pass a struct besides a few other arguments to that function. I have the same struct declared (or defined?) in both files (main.c and plugins.c). But when I try to "filter" the irc struct passed from the main.c out and parse the data in the irc struct from the plugins.c, I don't get anything usefull. When I call the function I get a segementation fault.
This is the important part from the main.c:
struct irc_data {
char nick[32];
char user[32];
char host[64];
char chan[32];
char message[512];
int is_ready;
};
....
int main(int argc, char** argv) {
....
struct irc_data *irc = malloc(sizeof(struct irc_data));
....
(*lib_plugin)("r",irc); // call the function in plugins.c
....
}
And here the hole plugins.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
struct irc_data{
char nick[32];
char user[32];
char host[64];
char chan[32];
char message[512];
int is_ready;
};
char* plugins_entry(const char* data, ...) {
int i;
struct irc_data *irc = malloc(sizeof(struct irc_data));
va_list args;
va_start(args, data);
for(i=0; data[i] != '\0'; ++i){
if(data[i] == 'r'){
irc = data[i];
}
}
va_end(args);
printf("\n\n------------------------\n");
printf("What we got here: %s\n",irc->nick);
printf("\n------------------------\n\n");
return "done";
}
So, I am pretty sure that I am doing something wrong with the pointers.
Could you please help me out here?
Thank you
~ Tectu
The line irc = data[i] doesn't make any sense. You need to call va_arg:
if(data[i] == 'r') {
irc = va_arg(args, struct irc *);
}
Also, the malloc in plugins_entry is useless, it will only leak memory.
You don't extract the pointer to the struct using va_args(). With that, you should be able to directly use your struct:
struct irc_data *irc = va_args(args, struct irc *);
Note that you don't need to use malloc in this function as long as you don't want to copy explicitly. As your struct is already located on the heap (it's malloc'ed in main.c), you can just use it directly by using the pointer.

Resources