(bad practice ?) Pointers for having better variable names

Started by
10 comments, last by SeanMiddleditch 7 years, 6 months ago

In my C game engine, i have an array of structs representing all the active game objects. Those structs contains classic data (type of object, x/y pos...), a pointer to the function handling the object's behavior and a bunch of 'generic' variables (ints, floats...) to be used by this function if needed.

Depending on the object, those variables have different uses so they are named generically varA, varB, varC....

What do you think about creating pointers for them at the beginning of the object's function, just for the sake of having good readable names ?


void function(myobject *o){

int* iaState = &o->varA;
int* otherSuperVariable = &o->varB;

// do stuff with them

}

Since the pointer will never change after its creation, do you think the compiler automatically optimize it or it'll add useless processing each time i use it ?

Advertisement

In release mode, it's highly likely that there will be no extra variable created and no runtime overhead at all.

However, I doubt that this set of 'generic' variables can't be replaced with something better. At the very minimum, can't you use a union? Or just have the top level object contain different structs for different object types?

I practice C since a quite long time, and to be honest, i didn't know about the union existence ! Thank you for this tip, it seems a great way to avoid wasting space because of inappropriately-typed variables.

I think your 2nd solution, with different structs for each object type, is the total opposite and would waste so much space it would be dangerous. Or i didnt understand what you mean?

I could also have only a void pointer per object, a bunch of typedef structs defining the variables needed for every object type, and do a malloc on the object creation. I don't know what is better

The idea would be that the shared data is in a 'base' struct, and that struct would be contained in one of many 'child' structs, one for each type of object. It would be similar to C++ classes but you would cast the pointer based on which type of object it is. There would be no wasted space as each object would contain only the exact fields it needs (compared to your current system which wastes space if a certain type of object doesn't need some of the generic variables.) This would only work if you were allocating each one separately; you couldn't store them all in an array, that way.

Kylotan's suggestion of using unions is the way to go. You can see an example of how to use them for the sort of thing you are wanting to do by looking at SDL's event handling - specifically SDL_events.h. Look at the SDL_Event union typedef at line 525.

Thanks, i'll use union to save memory

For the variable names, should i declare them all in the unions (so I have to decide here which can overlap, all the variables names for all objects will be declared into unions... ) like this:


union{
int playerLifes;
int platformSpeed;
float something;
float otherthing;
};

union{
int levelId;
float gravity;
};

union{
 ...

, or should i keep the union generic like :


union {
int i;
float f;
} data[10]; // each object can have a maximum of 10 variables of mixed types

and go with the pointers to get more readable names?

I guess the whole purpose of the thing is to use the 1st method, but I feel weird putting the mixed stuff of all objects here.

I'd make one struct for each type of game object, then create a union of those structs inside the game object itself.

Thanks, i'll use union to save memory

For the variable names, should i declare them all in the unions (so I have to decide here which can overlap, all the variables names for all objects will be declared into unions... )

You should have a union of structures not a union of unions. The latter will put all the variables in the sample space.

This thread honestly irritates me. Most of the people responding here should know better.

Yes, your proposed use of pointers is bad practice. Using unions here is even worse practice.

Do not use unions. They are dangerous. They seem like magic but are filled with peril. They have very strict and almost universally poorly-understood rules that your compiler _will not_ warn you about when you misuse them (and you _will_ misuse them).

Your actual problem is that you're trying to stuff unrelated objects into a single array. This is bad code - for any language, C or otherwise - and the actual fix is to stop doing what you're trying to do. Making one big array with all game objects represented by a single struct is bad design. Don't do it.

Even if you make your code "easy" with the use of unions, your array is still going to be poorly laid in memory. Each game object being as large as the largest object. In other words, if a bullet needs at most 20 bytes and a player object requires 500 bytes, every bullet is still going to take up 500 bytes. Iterating through your bullets (of which you'll have many) will make poor use of the cache because they are not tightly packed.

Using a single base struct for your game objects also mean your game logic is going to be slow. Having only a single array means that during iteration, you must branch for each object depending upon its type in order to execute the appropriate logic. Doing this defeats the branch predictor in the CPU, which is possibly the single most important piece of modern hardware optimization you have available aside from the cache itself.

The efficiency problems are secondary. The _incorrect_ code you're almost guaranteed to write combined with the _sloppy architecture_ you'd be buying into are the real problems.

Use separate arrays. Preferably, break your objects up into components, and put each of those into their own arrays. Do not use unions. Fix your bad architecture rather than trying to paper over it.

Sean Middleditch – Game Systems Engineer – Join my team!

I decided to use this way of storing the objects after analyzing the disassembly of Sonic on Genesis, which is quite an achievement for its era. All objects take 64 bytes in ram, they have common attributes and a free area that every object can use to store its specific data.

I'm doing a similar thing : most of the attributes in Object struct are somewhat generic (mostly graphical related) and could be needed by everything : alive, type, subtype, x/y speed, angle, animationId, framecount, currentframe... + those additional "free usage" values to be used the way the object wants. The player releated variables are handled outside the object struct since it's very specific.

If i use separate arrays for every object type, i may end with heavily duplicated code. Should i really have 40 structs if i have 40 objects types, each having 80% of common attributes?

This topic is closed to new replies.

Advertisement