Sign in to follow this  
BlackDuck

struct and function pointers

Recommended Posts

BlackDuck    151
Hi Again, I have a project that can only be done in C. So I am told I can create struct with functions inside and call it similiar to biPlane->IncreaseSpeed(2); My understanding is each file in a project represent something that is similar like player, enemy, input, display etc. So I will have a file call plane.h In there do I create a struct
struct plane
{
    Vector3D loc;
    float speed;
}

I wish to understand, do I need a implementation file and a header file for plane. Where do I put the IncreaseSpeed function How do I create the plane object like
plane biPlane = new plane();

And then increase the speed like
biPlane->IncreaseSpeed(2);

And probably before all this, initialise the speed to zero

Share this post


Link to post
Share on other sites
fastcall22    10838
Quote:

I wish to understand, do I need a implementation file and a header file for plane


Sure, if you wish.

HINT:
biPlane.IncreaseSpeed(2);

Is synthetic sugar for:
Plane::IncreaseSpeed( &biPlane, 2 );

Share this post


Link to post
Share on other sites
BlackDuck    151
Please review code. Please correct me, but I believe I have create a struct that contains a member and three methods..kind of...class speaking ;) maybe?


#include <stdio.h>

struct plane
{
float m_speed;

void IncreaseSpeed (void)
{
m_speed++;
}

void SetSpeed (float speed)
{
m_speed = speed;
}

void Initialise(void)
{
m_speed = 0;
}
};

int main (void)
{
plane biPlane;

biPlane.Initialise();
biPlane.IncreaseSpeed();

printf("m_speed: %f\n", biPlane.m_speed);

biPlane.SetSpeed(5.0);

printf("m_speed: %f\n", biPlane.m_speed);

return 0;
}



Now any advice how to change this so I can do this below using function pointers. Do I have it all wrong?


biPlane->Initialise();
biPlane->IncreaseSpeed();
biPlane->SetSpeed(5.0);

Share this post


Link to post
Share on other sites
Aardvajk    13207
Function pointers in structs in C are used more for hacking polymorphic behaviour. Unless that is required here, member functions are far simpler to implement. Code below is deliberately a bit cryptic because this sounds a bit like homework.


struct type
{
int value;
};

void t_constructor(struct type *t,int value)
{
t->value=value;
}

void t_method(struct type *t,int add)
{
t->value+=add;
}

void f()
{
type t;
t_constructor(&t,10);

t_method(&t,23);
}








would be a simple example of how to implement non-polymorphic member functions in C.

Polymorphic behaviour with function pointers in structs would look more like this:


struct type
{
int value;

void (*method)(struct type*,int);
};

void t_method_one(struct type *t,int add)
{
t->value+=add;
}

void t_method_two(struct type *t,int sub)
{
t->value-=sub;
}

void t_add_constructor(struct type *t,int value)
{
t->value=value;
t->method=t_method_one;
}

void t_sub_constructor(struct type *t,int value)
{
t->value=value;
t->method=t_method_two;
}

void poly(struct type *t)
{
(*t->method)(t,23); // think this is correct syntax, can't remember
}

void f()
{
struct type a,b;

t_add_constructor(&a,10);
t_sub_constructor(&b,20);

poly(&a);
poly(&b);
}








As _fastcall points out above, this is all really just sort of manually doing what a C++ compiler is most likely doing under the hood.

Share this post


Link to post
Share on other sites
haegarr    7372
Quote:
Original post by BlackDuck
I have a project that can only be done in C. ...
Quote:
Original post by BlackDuck
Please review code. Please correct me, but I believe I have create a struct that contains a member and three methods..kind of...class speaking ;) maybe? ...

Maybe I've overlooked something, but it seems me that C and C++ is confused here. The OP seems me to ask for a C solution to mimik some sort of C++ functionality. BlackDuck, please clarify whether just pure C or also C++ is an option for your project.

Share this post


Link to post
Share on other sites
BlackDuck    151
Pure C..

My tutor mention that I could setup a struct with function pointers to make it behaviour similiar to OO but there is no real need but to make it readable and cleaner.

The project is to make a 3D program to simulate a force (gravity), 3D animation, interaction, some other stuff so struct / function pointers as such is not access but it would make my code more readable so that is why I am asking. i don't mind if the responses are cryptic, as long as it makes sense and it is the direction I wish to implement. At the end the tutor did say that he may have confused things, it has been a while he said. But he mention that I am to put all relate functions and attributes of my plane in a file for itself (maybe a header) inside a struct since I can have functions there too.

Now I only seem to be able to call the function like foo.bar rather than foo->bar

Is there a way?

At the end the goal is to make the code readable and to keep things inside a struct to make it neater.

Share this post


Link to post
Share on other sites
Tac-Tics    197
It's not clear what you're really looking for. There is no way to simulate the C++-style OOP syntax you want in C.

If you want readable code, don't use C (or C++). C is a 40 year old programming language (C++, 30 year old) that was designed during a time when assembly code was seen to be the only legitimate way to program a computer. Don't expect it to be elegant or "clean".

That being said, why can't you simply do it the way a C programmer would do it. Leave your C++ habits with C++ and adopt a C mentality:


struct plane
{
Vector3D loc;
float speed;
}

void planeNew(plane* p)
{
// do your initialization here
p->speed = 0;
p->loc.x = 0;
p->loc.y = 0;
p->loc.z = 0;
}

void planeIncreaseSpeed(plane* p, float amount)
{
p->speed += amount;
}

...

plane players[NUM_PLAYERS];

...

void setup()
{
for (i = 0; i < NUM_PLAYERS; i++)
{
planeNew(&players[i]);
}
}

...

void onSpeedUp(int playerId)
{
planeIncreaseSpeed(&players[playerId], 2);
}

Share this post


Link to post
Share on other sites
szecs    2990
I have to disagree about C++ habits in C stuff.

It is in fact useful to have function pointer members in a struct: think about a GUI structure. Drawing/function/whatever are just pointers, so the GUI will be flexible, and not the immediate mode stuff

Share this post


Link to post
Share on other sites
Tac-Tics    197
Quote:
Original post by szecs
It is in fact useful to have function pointer members in a struct: think about a GUI structure. Drawing/function/whatever are just pointers, so the GUI will be flexible, and not the immediate mode stuff


There's nothing wrong with using function pointers in your structs. If you need polymorphic behavior, function pointers are the correct way to do it.

But the OP isn't looking for polymorphism. He's looking to group state and behavior in his code and a way to pretty up the syntax. This isn't possible in C. (And if it is, it requires unnecessary abuse of the preprocessor).

Share this post


Link to post
Share on other sites
haegarr    7372
Quote:
Original post by BlackDuck
Now I only seem to be able to call the function like foo.bar rather than foo->bar

Is there a way?
I think it isn't really a question whether to use a dot or an arrow. Even in C++ you have both ways, dependend on whether you have a reference or else a pointer to the class instance. Instead, the exercise is just to declare a struct where function pointers are members, to set such pointers to an actual function, and to invoke it.

(A rule in GDnet is not to solve home work. So I suggest to use your search engine of choice and look for "c function pointer". That gives you a plenty of hits. Then put that into a struct. If it didn't compile or execute, then we like to help on source code / error messages / whatever you show us.)

Share this post


Link to post
Share on other sites
Ferneu    100
Quote:
Original post by haegarr
Quote:
Original post by BlackDuck
Now I only seem to be able to call the function like foo.bar rather than foo->bar

Is there a way?
I think it isn't really a question whether to use a dot or an arrow. Even in C++ you have both ways, dependend on whether you have a reference or else a pointer to the class instance.


I don't know, but from what I read so far it seems that all
he really wanna do is to use the arrow. And maybe he is just
talking about function pointers because what he wants to do
involves functions (methods) and pointers. And if it is so,
all he have to do is do declare a pointer instead of a plain
stack object.

so, you can eighter do it like this:
Foo foo;
foo.bar

or like this, using a pointer:
Foo* foo;
foo->bar;


Share this post


Link to post
Share on other sites
haegarr    7372
Quote:
Original post by Ferneu
I don't know, but from what I read so far it seems that all
he really wanna do is to use the arrow. And maybe he is just
talking about function pointers because what he wants to do
involves functions (methods) and pointers. And if it is so,
all he have to do is do declare a pointer instead of a plain
stack object.

Well, in the OP there is a passus
Quote:
Original post by BlackDuck
... create struct with functions inside and call it similiar to biPlane->IncreaseSpeed(2); ...

that seems me a clear statement of what he wants. For sure, whether it is what he needs is another question (as Aardvajk has already written). However, if functions inside a struct using pure C are really requested, then function pointers is the way to go.

Share this post


Link to post
Share on other sites
Zahlman    1682
Simulating how C++ does polymorphism in C is not very easy.

Let's make a real C++ example so that we can see a basic case where polymorphism is actually used.


// I will not bother with making anything 'private', and just use structs with
// everything public, because in C there will be no equivalent to 'private' anyway.

struct Base {
int x;
virtual void doSomething() {
cout << "Base doing something with" << x;
}
virtual void doSomethingElse() {
cout << "Base doing something else with" << x;
}
Base(): x(42) {}
virtual ~Base() {}
};

struct Derived: Base {
int y;
virtual void doSomething() {
cout << "Derived doing something with" << x << " and " << y;
}
virtual void doSomethingElse() {
cout << "Derived doing something else with" << x << " and " << y;
}
Derived(): Base(), y(23) {}
};

// later
Base* b = new Derived();
b->doSomething();
b->doSomethingElse();
delete b;



In C, it will look more like this:


typedef struct Base_struct { struct BaseVtable* vtable_ptr; int x; } Base;
typedef struct Derived_struct { Base b; int y; } Derived;

void baseDoSomething(Base* b) {
printf("Base doing something with %d", b->x);
}
void baseDoSomethingElse(Base* b) {
printf("Base doing something else with %d", b->x);
}

// Notice that the 'b' member of a Derived will be at the beginning of the
// memory allocated for a Derived, so a Base pointer with that address will
// access the members of the contained Base. To get the Derived-specific
// members, we need a cast. Note that with multiple inheritance this would not
// work so easily; we would need to offset the pointers to find the right base.
void derivedDoSomething(Base* b) {
printf("Derived doing something with %d and %d", b->x, ((Derived*)b)->y);
}
void derivedDoSomethingElse(Base* b) {
printf("Derived doing something else with %d and %d", b->x, ((Derived*)b)->y);
}

// Replaces 'delete', as well as any other work done by the destructor.
// (In our example, there is no such work.)
void baseDealloc(Base* b) { free(b); }
void derivedDealloc(Base* b) { free((Derived*)b); }

// Of course you will need to handle each type of function pointer separately.
// I also didn't handle the case where Derived adds more virtual functions,
// or multiple inheritance, or any of the other interesting stuff. ;)
typedef void(*Base_void_to_void)(Base*);

struct BaseVtable {
Base_void_to_void doSomething, doSomethingElse, dealloc;
} base_table = {
baseDoSomething, baseDoSomethingElse, baseDealloc
}, derived_table = {
derivedDoSomething, derivedDoSomethingElse, derivedDealloc
};

// Replaces the constructor
void init_base(Base* b) { b->x = 42; }

// Implements 'new' for the type
Base* create_base() {
Base* result = malloc(sizeof(Base));
init_base(result);
result->vtable_ptr = &base_table;
return result;
}

void init_derived(Derived* d) {
init_base(&(d->b)); // Alternatively, init_base((Base*)d), for single inheritance
d->y = 23;
}

Base* create_derived() {
Derived* result = malloc(sizeof(Derived));
init_derived(result);
result->vtable_ptr = &derived_table;
return (Base*)result;
}

// Implement the virtual functions.
void doSomething(Base* b) { (b->vtable_ptr->doSomething)(b); }
void doSomethingElse(Base* b) { (b->vtable_ptr->doSomethingElse)(b); }
void dealloc(Base* b) { (b->vtable_ptr->dealloc)(b); }

// Later, used like:
Base* b = create_derived();
doSomething(b);
doSomethingElse(b);
dealloc(b);



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this