I've been playing with C today, and something I never had the chance to play with, that is use a struct with pointers to functions...well all went good, until I started to get some strange bug, when I was cleaning the whole thing (BTW: I was compiling in x86_64 arch, in a Mac)
Looking and looking I figured out that is the memory alignment, in the node_vtable struct.
In i386, it works fine..no issues whatsoever. However, as I said in x86_64, it doesn't work.
/* NOT WORKING */
struct node_vtable {
void (*add_node) (linked_list *, node *);
node * (*create_node) (linked_list *, float, int, int );
void (*print) (linked_list *llist);
};
/* WORKING */
struct node_vtable {
void (*print) (linked_list *llist);
void (*add_node) (linked_list *, node *);
node * (*create_node) (linked_list *, float, int, int );
};
Now, I fixed this moving the pointer node * (*create_node) (linked_list *, float, int, int ); to the end of the struct, as that one has a size of 24 bytes, which is the largest in that struct. However, I really think that there is for sure a more elegant solution, and also I am looking for a clear explanation. Hence, if someone can give a hint or some explanation, that would be great ;) ....as my brain now is really stuck :)
The whole code:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
int var;
float f_var;
struct node *next;
};
typedef struct node node;
typedef struct linked_list linked_list;
/* Structs */
struct node_vtable {
void (*add_node) (linked_list *, node *);
node * (*create_node) (linked_list *, float, int, int );
void (*print) (linked_list *llist);
};
struct linked_list {
/************************/
node *head;
node *tail;
/************************/
node *data;
/* VTable to Methods*/
struct node_vtable *method;
};
/*Prototypes*/
linked_list *constructor_linked_list();
void print(linked_list *llist);
void add_node(linked_list *this, node *node);
node *create_node(linked_list *this, float f_var, int var, int _id);
/***************/
linked_list *constructor_linked_list() {
printf("calling constructor_linked_list...\n");
linked_list *this = (linked_list *)malloc(sizeof(linked_list));
this->head = NULL;
this->tail = NULL;
this->method = NULL;
this->method = (struct node_vtable *)malloc(sizeof(struct node_vtable *));
this->method->print = &print;
this->method->add_node = &add_node;
this->method->create_node = &create_node;
return this;
}
void print(linked_list *llist) {
printf("calling print ...\n");
node *iter = llist->head;
while (iter){
printf("\tnode %d\n", iter->id);
iter = iter->next;
}
}
void add_node(linked_list *this, node *node) {
printf("calling add_node_...\n");
if (this->head == NULL) {
node->next = NULL;
this->head = node;
this->tail = node;
} else {
node->next = NULL;
this->tail->next = node;
this->tail = node;
}
}
node *create_node(linked_list *this, float f_var, int var, int _id) {
printf("calling create_node ...%d\n",(int)sizeof(struct node_vtable));
node *ret_node = (node *)malloc(sizeof(struct node));
ret_node->var = var;
ret_node->id = _id;
ret_node->f_var = f_var;
ret_node->next = NULL;
return ret_node;
}
int main(int argc, char *argv[]) {
linked_list *obj = constructor_linked_list();
int i;
for (i = 0; i < 10; i++) {
obj->method->add_node(obj, create_node(obj, 5.0, 3, i));
}
obj->method->print(obj);
return EXIT_SUCCESS;
}
Cheers
Alignment shouldn't matter at all, so it definitely has one or more bugs.
This line:
this->method = (struct node_vtable *)malloc(sizeof(struct node_vtable *));
should be:
this->method = (struct node_vtable *)malloc(sizeof(struct node_vtable));
Unfortuntaly I cannot check whether it fixes the problem (plain cygwin x86 here), if not then definitely check it with valgrind.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With