gcc 4.4.1 c89
I have 2 different structures called origin_t and session_t.
I would to pass the instance of one of these structure to my function. However, before I can perform an operation on these I need to cast it to the correct type. My problem is that I don't know how to check for the correct type. Is there any standard c function that can check for the correct instance of this structure.
Many thanks for any advice,
const char* get_value(void *obj)
{
/* Cast to the correct structure type */
if(obj == origin) {
/* Is a origin structure */
origin_t *origin = (origin_t*)obj;
}
else if(obj == session) {
/* Is a session structure */
session_t *session = (session_t*)obj;
}
}
Is there any way to modify the types? Seems like the easiest way it to put a small member that indicates the type if there's no other way to tell.
C doesn't have any built-in runtime type information capabilities, so you'd have to create your own - for example, by putting at the beginning of both origin_t and session_t some integer or pointer to some data structure that would allow you to distinguish between them.
The best way would be to combine the types (if possible!) under a common type such as:
typedef enum {
t_origin,
t_session
} type_t;
struct base_t {
type_t type;
union {
origin_t origin;
session_t session;
};
}
and then:
const char* get_value(base_t *obj)
{
/* Cast to the correct structure type */
if(obj->type == t_origin) {
/* Is a origin structure */
origin_t *origin = &obj->origin;
}
else if(obj->type == t_session) {
/* Is a session structure */
session_t *session = &obj->session;
}
}
There are no ways of determining types from a pointer in C. You have to add your own type mechanism. This is one way to do it without being intrusive in the subtypes (origin_t and session_t). You also don't have to do weird casts, and compromise the already weak type system in the C language.
Related
In JavaScript I can have a function with an untyped argument, and then customize the behavior depending on the type:
function customize(a) {
if (a instanceof Uint8Array) {
doArray()
} else if (typeof a == 'function') {
doFunction()
} else {
doOther()
}
}
How can I do this same thing in C, either with or without macros (preferrably without macros).
void
customize(void *a) {
// ???
}
Here it says:
Your void pointer looses all its type information, so by that alone, you cannot check if it can be cast safely. It's up to the programmer to know if a void* can be cast safely to a type.
Can I somehow do a comparison against the key functions or structs in my application to see if it is a match?
void
customize(void *a) {
if (a == fn_a) return do_function();
if (a == fn_b) return do_function();
// somehow iterate dynamically through the functions.
}
void
fn_a() {
}
As it was stated in the thread you've found, it is not possible through void *.
You can do something similar with unions, but it's not very flexible and I'm not sure it is a good solution (might be better to have separate functions for every type):
typedef enum {
TYPE_1 = 0,
TYPE_2,
TYPE_3
} type_e;
typedef union {
int t1;
char t2[5];
double t3;
} types_u;
typedef struct {
type_e type;
types_u types;
} my_types_t;
void func(my_types_t *some_variable)
{
switch (some_variable->type)
{
case TYPE_1:
// do something
break;
case TYPE_2:
// do something else
break;
}
}
There is an old saying that you can write FORTRAN in any language. I'm not sure if it is true or not, but I'm sure that you can't write Javascript in any language and especially not in C.
C is statically typed and all type information is lost at runtime. You'll have to rethink your design, perhaps avoiding completely the need of carrying the information, perhaps passing an additional parameter with that information, perhaps bundling it with the void* in a struct, perhaps assuming that the void* point to something you have more information about and you can reextract the type information. There are several techniques possible, all with various trade-off and caveats, but expanding on them seems like writing a book and I don't have time for that.
Some of the techniques were made language features in C++; that would avoid you to have to reinvent them and reimplement them, but you'd need to learn another language.
Given that there are multiple struct typedefs (all different) but with the same first element 'out' as in:
typedef struct myStructOneOfMany
{
uint8_t out;
//somestuff that is different
void* inPntr[33];
struct myStructOneOfMany *prev;
struct myStructOneOfMany *next;
}myStructOneOfMany;
how could one use a generic struct:
typedef struct OUT
{
uint8_t out;
}OUT;
with only the 1st element to access just the 1st element of all the different types?
assume:
myStructOneOfMany *currMyStructOneOfMany = //pointer to 1st in the linked list
I have tried:
uint8_t value = (struct OUT*)(currMyStructOneOfMany->inPntr[4])->out;
... along with other variations and I get nowhere.
Thanks!
EDIT:
As written in Jonathan Leffler's great comment - C11 §6.7.2.1 ¶15 says:
A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.
Which is why we either use a struct in the first element (matching padding and all), or a single variable / enum. I prefer using structs because they are easier to extend later on, if you want to add something.
Structs are interesting and complex animals, their field include compiler specific paddings and alignments.
Although very often the code will work fine by a simple matching of the top element, it isn't always the case when you're trying to use a common header with a number of fields (that would be undefined behavior due to padding concerns)... single elements are fine.
A classic way (that is also a compiler correct way) to implement "inheritance" in C would look something like this:
struct parent_s {
/* common attributes */
int object_type; /* for example */
};
struct child_s {
/* must be first element if you want pointers to be interchangeable. */
struct parent_s parent;
/*more stuff */
int my_unique_data;
}
Similar code is used in network address structures.
P.S.
This was a very quick and simplified answer, enough to get you started but not very accurate.
As you explore this you will discover techniques that allow you to place the common structures all over the place and have multiple inheritance when you need it.
I used to miss inheritance in C, but these days I love C better than many OO languages because it gives me more control over the memory structure and I can manage most inheritance features without the need to resort to virtual function tables (which I very rarely do).
EDIT:
Following #AjayBrahmakshatriya 's comment, I thought a quick casting example might be nice... So here's something I'm working on that uses the exact type of inheritance you're asking about (I just started this part of the code today, so it might be glitchy, I also didn't sleep for two days...):
/** Used to identify te type of the RESP object. */
enum resp_type_enum {
/** A String object (`resp_string_s`) that indicates an error. */
RESP_ERR = 0,
/** A simple flag object object (`resp_object_s`) for NULL. */
RESP_NULL,
/** A simple flag object object (`resp_object_s`) for OK. */
RESP_OK,
/** A Number object object (`resp_number_s`). */
RESP_NUMBER,
/** A String object (`resp_string_s`). */
RESP_STRING,
/** An Array object object (`resp_array_s`). */
RESP_ARRAY,
/** A specific Array object object (`resp_array_s`) for Pub/Sub semantics. */
RESP_PUBSUB,
};
/* This is the parent "class" / object */
typedef struct { enum resp_type_enum type; } resp_object_s;
/* an Array child class */
typedef struct {
enum resp_type_enum type;
size_t len;
size_t pos; /** allows simple iteration. */
resp_object_s *array[];
} resp_array_s;
/* a String child class */
typedef struct {
enum resp_type_enum type;
size_t len;
uint8_t string[];
} resp_string_s;
/* a Number child class */
typedef struct {
enum resp_type_enum type;
int64_t number;
} resp_number_s;
I wrote macros that allow me to easily cast from one type to another. They include error checks (by returning NULL if the types don't match:
#define resp_obj2arr(obj) \
((resp_array_s *)((obj)->type == RESP_ARRAY || (obj)->type == RESP_PUBSUB \
? (obj) \
: NULL))
#define resp_obj2str(obj) \
((resp_string_s *)((obj)->type == RESP_STRING || (obj)->type == RESP_ERR \
? (obj) \
: NULL))
#define resp_obj2num(obj) \
((resp_number_s *)((obj)->type == RESP_NUMBER ? (obj) : NULL))
This allows me to do use the macros to easily switch between the different "types".
switch (obj->type) {
case RESP_ERR:
safe_write1('-');
safe_write2((resp_obj2str(obj)->string), (resp_obj2str(obj)->len));
safe_write_eol();
break;
case RESP_NULL:
safe_write2("$-1\r\n", (resp_obj2str(obj)->len));
break;
case RESP_OK:
safe_write2("+OK\r\n", 5);
case RESP_ARRAY:
case RESP_PUBSUB:
safe_write1('*');
safe_write_i(resp_obj2arr(obj)->len);
safe_write_eol();
{
resp_array_s *a = resp_obj2arr(obj);
a->pos = a->len;
obj = NULL;
while (a->pos) {
a->pos--;
push_obj(a->array[a->pos], obj);
obj = a->array[a->pos];
}
}
// ...
}
Well it seems I over thought things.
The last comment above compiles and works !
uint8_t value = *(uint8_t *)(…some expression denoting a pointer to a structure with a uint8_t first member…);
I thought I had to make a generic struct similar to my several typedefs.
As Jonathan said ... no need to get fancy.
The pointer to the struct is also a pointer to the first element as long as you cast the pointer to point to the same type as the first element.
Thanks to Jonathan Leffler for pointing this out !!
PS: one thing that threw me was the additional * at the beginning.
I assumed the cast to (uint8_t*) was enough but I guess this just says "treat the right side after the cast as a pointer to type uint8_t.
Without the * before the cast ... 'value' would get the pointer value ... not the value that the pointer points to.
I am still between beginner and intermediate on C but making progress
Thanks to you all !!
Up to now, I've been using void * as a way to encapsulate private data in C. The idea is : the user should not bother with the internal, and just request exposed functions.
Hence for example :
typedef void* myPrivateType;
myPrivateType createMPt(int someArg);
int doSomething(myPrivateType mpt, int someOtherArg);
void freeMpt(myPrivateType mpt);
This works well at hiding the internal of myPrivateType. However, there is one last minor catch : void* is so permissive, that the compiler will silently accept any kind of pointer, and not trigger any warning in case of incorrect type.
This looks like a small issue, but it just increases the likelyhood that a user improperly uses the interface and lose a lot of time trying to debug what's wrong.
As a consequence, I'm now leaning on using incomplete types instead of void*, as a stricter way to control type during compilation.
Hence the previous example becomes as follows :
typedef struct foo* myPrivateType;
myPrivateType createMPt(int someArg);
int doSomething(myPrivateType mpt, int someOtherArg);
void freeMpt(myPrivateType mpt);
As you can see, almost nothing has changed, only the typedef. It works better than previous example as now, if the user provides another pointer than `myPrivateType', the compiler will complain, and the error will be immediately caught.
This is a fairly good alternative. Except that, in the "private section" of the code (the .c file), I will have to define what struct foo is. In some cases, it's quite straightforward, when such content is clearly and statically defined.
But sometimes, the content of myPrivateType depends on some variable provided at runtime, and therefore its size may vary. This is no good for a C struct, which is supposed to have a defined size at compilation time.
As a workaround, I could for example typedef myPrivateType this way :
typedef size_t* myPrivateType;
or
typedef size_t myPrivateType[]; // equivalent
This let the possibility to decide the size later on, as a multiple of size_t. But now, myPrivateType is more permissive, as any size_t* pointer will also fit the bill.
I'm wondering if there is a way to combine both properties, with myPrivateType being very strict, hence impossible to confuse with any other type of pointer, but the underlying private data keeping the ability to select its size at runtime.
How about:
struct myPrivateType { void * private; };
Use in essentially exactly the same way that you used to use the raw void pointer. You can expose the whole struct in the header, since there's nothing much the application can do with the void pointer it contains anyway.
This solves the problem of implicit conversions with void * without introducing any irritations beyond the mpt->private dereference within your library functions.
edit: with the typedef struct myPrivateType myPrivateType; construct if you prefer.
I'm wondering if there is a way to combine both properties, with myPrivateType being very strict, hence impossible to confuse with any other type of pointer, but the underlying private data keeping the ability to select its size at runtime.
Yes, you can do that quite easily by using:
struct foo
{
int dataType;
void* fooData;
};
struct FooData1
{
// ...
};
struct FooData2
{
// ...
};
myPrivateType createMPt(int someArg)
{
myPrivateType ret = malloc(sizeof(*ret));
if ( someArg == 10 )
{
ret->dataType = 1;
ret->fooData = malloc(sizeof(FooData1));
}
else if ( someArg == 20 )
{
ret->dataType = 2;
ret->fooData = malloc(sizeof(FooData2));
}
else
{
// ...
}
}
Update
If a public function, one that is declared in a .h file, is called many times in a tight loop, and the implementation of that function has to call different functions based of the dataType of struct foo, you can store a function pointer in struct foo instead. This is analogous to the use of virtual tables in C++ classes.
struct foo
{
int dataType;
void* fooData;
void (*functionInTightLoop)(void);
};
struct FooData1
{
// ...
};
void FooData1Function()
{
}
struct FooData2
{
// ...
};
void FooData2Function()
{
}
myPrivateType createMPt(int someArg)
{
myPrivateType ret = malloc(sizeof(*ret));
if ( someArg == 10 )
{
ret->dataType = 1;
ret->fooData = malloc(sizeof(FooData1));
ret->functionInTightLoop = FooData1Function;
}
else if ( someArg == 20 )
{
ret->dataType = 2;
ret->fooData = malloc(sizeof(FooData2));
ret->functionInTightLoop = FooData2Function;
}
else
{
// ...
}
}
void tightFunction(myPrivateType foo)
{
foo->functionInTightLoop();
}
Can structures contain functions?
No, but they can contain function pointers.
If your intent is to do some form of polymorphism in C then yes, it can be done:
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
// And data goes here.
} tCommClass;
The typedef above was for a structure I created for a general purpose communications library. In order to initialise the variable, you would:
tCommClass *makeCommTcp (void) {
tCommClass *comm = malloc (sizeof (tCommClass));
if (comm != NULL) {
comm->open = &tcpOpen;
comm->close = &tcpOpen;
comm->read = &tcpOpen;
comm->write = &tcpWrite;
}
return comm;
}
tCommClass *makeCommSna (void) {
tCommClass *comm = malloc (sizeof (tCommClass));
if (comm != NULL) {
comm->open = &snaOpen;
comm->close = &snaOpen;
comm->read = &snaOpen;
comm->write = &snaWrite;
}
return comm;
}
tCommClass *commTcp = makeCommTcp();
tCommClass *commSna = makeCommSna();
Then, to call the functions, something like:
// Pass commTcp as first params so we have a self/this variable
// for accessing other functions and data area of object.
int stat = (commTcp->open)(commTcp, "bigiron.box.com:5000");
In this way, a single type could be used for TCP, SNA, RS232 or even carrier pidgeons, with exactly the same interface.
edit Cleared up ambiguity with the use of 'data types'
Not in C. struct types can only contain data.
From Section 6.7.2.1 of the ISO C99 Standard.
A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
No, you cannot. A structure cannot contain a declaration of a function but they can contain a definition of a function. A structure can only contain data types, pointers, pointers to different function. You can make a pointer to a function and then access from the structure.
#include<iostream>
#include<cstring>
using namespace std;
struct full_name
{
char *fname;
char *lname;
void (*show)(char *,char*);
};
void show(char *a1,char * a2)
{
cout<<a1<<"-"<<a2<<endl;
}
int main()
{
struct full_name loki;
loki.fname="Mohit";
loki.lname="Dabas";
loki.show=show;
loki.show(loki.fname,loki.lname);
return 0;
}
In C, structures are allowed to contain on data values and not the function pointers. Not allowed in C. but the following works literally fine when checked with gcc.
enter code here
#include <stdio.h>
struct st_func_ptr{
int data;
int (*callback) ();
};
int cb(){
printf(" Inside the call back \n");
return 0;
}
int main() {
struct st_func_ptr sfp = {10, cb};
printf("return value = %d \n",sfp.callback());
printf(" Inside main\n");
return 0;
}
So, am confused ...
It's all right.
In the linux kernel code,you will find many structures contain functions.
such as:
/*
* The type of device, "struct device" is embedded in. A class
* or bus can contain devices of different types
* like "partitions" and "disks", "mouse" and "event".
* This identifies the device type and carries type-specific
* information, equivalent to the kobj_type of a kobject.
* If "name" is specified, the uevent will contain it in
* the DEVTYPE variable.
*/
struct device_type {
const char *name;
struct attribute_group **groups;
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
void (*release)(struct device *dev);
int (*suspend)(struct device * dev, pm_message_t state);
int (*resume)(struct device * dev);
};
Yes its possible to declare a function and the function definition is not allowed and that should be the function pointer.
Its based on C99 tagged structure.
Lokesh V
They can, but there is no inherent advantage in usual C programming.
In C, all functions are in the global space anyway, so you get no information hiding by tucking them in a function. paxdiablo 's example is a way to organize functions into a struct, but you must see has to dereference each one anyway to use it.
The standard organizational structure of C is the File, with
the interfaces in the header and the implementations in the source.
That is how libc is done and that is how almost all C libraries are done.
Moder C compilers allow you to define and implement functions in the same source file, and even implement static functions in header files. This unfortunately leads to some confusion as to what goes where, and you can get unusual solutions like cramming functions into structs, source-only programs with no headers, etc.
You lose the advantage of separating interface from implementation that way.
I can understand how a void** might look in memory, but I'm wondering if I'm using it quite right. Are there any fundamental flaws in what I describe below? For example, although I can say "it works for me", am I creating bad / unportable code in some way?
So I have an Asteroids clone. There are three entities that can fire bullets, the players (SHIP *player_1, SHIP *player_2) and the UFO (UFO *ufo). When a bullet is fired, it's important to know who fired the bullet; if it was a player, when it hits something their score needs to be incremented. So, the bullet will store what kind of entity it belongs to (owner_type) and also a pointer directly to the owner (owner):
enum ShipType
{
SHIP_PLAYER,
SHIP_UFO
};
typedef struct Bullet
{
// ...other properties
enum ShipType owner_type;
void **owner;
} BULLET;
Then, when the player hits the button or the UFO sees a target, one of these functions will be called:
void ship_fire(SHIP **shipp)
{
BULLET *bullet = calloc(1, sizeof(BULLET));
bullet->owner_type = SHIP_PLAYER;
bullet->owner = (void**)shipp;
// do other things
}
void ufo_fire(UFO **ufop)
{
BULLET *bullet = calloc(1, sizeof(BULLET));
bullet->owner_type = SHIP_UFO;
bullet->owner = (void**)ufop;
// do other things
}
... they may be called, for example, like this:
ship_fire(&player_1);
Finally, when the bullet hits a target (such as an asteroid), we dereference the owner. If it's a ship, we can increment the score there and then.
void hit_asteroid(ASTEROID *ast, BULLET *bullet)
{
SHIP *ship_owner;
if (bullet->owner_type == SHIP_PLAYER && *bullet->owner != NULL)
{
ship_owner = (SHIP*)*bullet->owner;
ship_owner->score += 1000;
}
}
Does that seem a reasonable approach? Like I say, it works for me, but I only have a couple of months of C experience.
A final note: why do I not use a void* instead of a void**? Because I want to avoid dangling pointers. In other words, say that player_1 dies and is free'd, but their bullet keeps going and hits an asteroid. If I only have a void*, the hit_asteroid function has no way of knowing that bullet->owner points to de-allocated memory. But with a void**, I can validly check to see if it's NULL; if player_1 is NULL, then *bullet->owner will be NULL too.
EDIT: All respondents so far concur that using a void** probably isn't necessary here because I can avoid the dangling pointers issue (by just statically allocating the base object, for instance). They're correct and I will refactor. But I'm still kinda interested to know if I've used void** in a way that might break something e.g. in terms of memory allocation / casting. But I guess if no-one has thrown their hands in the air and declared it faulty, it at least resembles something that would technically work.
Thanks!
Even if you wanted to continue doing it the way you were, you don't need to use void ** (and shouldn't).
Although void * is a generic pointer type, void ** is not a generic pointer-to-pointer type - it should always point to a genuine void * object. Your code dereferences a SHIP ** or UFO ** pointer through an lvalue of type void ** - that's technically not guaranteed to work. (This happens when you do (SHIP*)*bullet->owner).
However, the good news is that you could continue to use the double-pointer method, using a plain void * to do the job. void * can happily store a pointer-to-a-pointer (because that, after all, is just another kind of pointer). If you change owner to void *, then in ship_fire you would do this:
bullet->owner = shipp;
and in hit_asteroid you would do this:
ship_owner = *(SHIP **)bullet->owner;
In general, the rule for working with pointer casts is: First cast the pointer back to the pointer type that you know it really is, then dereference.
The linux kernel does this in an interesting way. It would be something like
/**
* container_of - cast a member of a structure out to the containing structure
* #ptr: the pointer to the member.
* #type: the type of the container struct this is embedded in.
* #member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
typedef struct Ship {
void (*fire)(struct Ship * shipp);
/* ...other methods...*/
} SHIP;
#define playership_of(shipp) container_of(shipp, PLAYERSHIP, ship)
#define ufoship_of(shipp) container_of(shipp, UFOSHIP, ship)
typedef struct PlayerShip {
/* PlayerShip specific stuff ...*/
SHIP ship;
/*...*/
} PLAYERSHIP;
typedef struct UFOShip {
/*...UFO stuff...*/
SHIP ship;
/*...*/
} UFOSHIP;
void ship_fire(SHIP * shipp)
{
shipp->fire(shipp);
}
void player_fire(SHIP *shipp)
{
PLAYERSHIP * ps = playership_of(shipp);
BULLET *bullet = calloc(1, sizeof(BULLET));
bullet->owner = shipp;
// do other things
}
void ufo_fire(SHIP * shipp)
{
UFOSHIP * ufos = ufoship_of(shipp);
BULLET *bullet = calloc(1, sizeof(BULLET));
bullet->owner = ufop;
// do other things
}
UFOSHIP ufoship = { /*...*/ .ship = { .fire = ufo_fire } /* ... */ };
PLAYERSHIP playership = { /*...*/ .ship = { .fire = player_fire } /*...*/ };
/* ... */
ship_fire(&playership.ship);
Read the linux kernel source code for lots of examples of this tecnique.
Since you only have two possible types, I'd use a union for this sort of thing, like so:
typedef struct Bullet {
enum ShipType owner_type;
union {
SHIP *ship;
UFO *ufo;
} owner;
} BULLET;
/* and then... */
void hit_asteroid(ASTEROID *ast, BULLET *bullet)
{
SHIP *ship_owner;
if (bullet->owner_type == SHIP_PLAYER && bullet->owner.ship != NULL) {
ship_owner = bullet->owner.ship;
ship_owner->score += 1000;
}
}
Note that I didn't use the pointer-to-a-pointer scheme that you used. I'm not really convinced of the necessity of it, and the code I suggested doesn't require such a technique.
First off, check the union construct suggested by mipadi; that's a very readable and efficient way of dealing with polymorphism.
Closer to your snippet/question, at a quick glance, I don't see the need/use for the double indirection introduced by pointer-to-pointers. The whole logic would work the same if the arguments to xxxx_fire() methods were [direct] pointers to xxxx objects (and if the typecast etc. in the rest of the logic were to follow accordingly.
Pointers to pointers are useful when the value of the intermediate pointer may be changed at some point. For example if the underlying object is moved, or if it replace by a different object altogether (say a better-equipped ship part of a new level in game etc...)
Edit: (on the use of double indirection to manage "fleets" of objects which may be deallocated.
Responding to your comment, do not refactor so that the objects are not de-allocated (from memory) when they get killed/detroyed (as part of the game). Instead, look into something like the following, as this is indeed an example where the pointer-to-pointer construct helps a lot. Here's how it could work:
Upon game (or level) initialization, allocate an array of pointers big enough to contain as many pointers as the total number of objects the game may allocate, over time. Initialize all its values to NULL.
Introduce an int value index, which indicates the location of the next available (=unused so far) pointer in this array.
When a new object (UFO, Ship or what have you) gets created, four things happen:
new memory is allocated for the object per se
the address of this new memory is stored in the object pointer array (at the location indicated by the index)
the index gets incremented
the "world" only knows this object by way of the double indirection
when an object gets destroyed two things happen
the memory is freed
the pointer in the array is set to null
when accessing any objects the program does three things
first dereference (once) the pointer-to-pointer
check if this is null (if so this indicate the object doesn't exist anymore, the logic may decide to remove this reference from wherever it stored it, as so to not try again, but this is of course optional).
access the actual object by dereferencing the intermediate pointer (if it isn't NULL)
In insight, a short snippet in C language may have been more explicit; sorry I described this in words...
If your bullet owners are frequently changed (e.g. deallocated), the pointer-to-pointer approach is suitable. The union solution does not address this concern directly; as presented, it does not support deallocating ships without touching the pointer on each of that ship's bullets. Of course, that may actually be a practical solution in some implementations, e.g. if you have a need to find all the bullets of a given player, you could maintain a linked list of them: a “next_bullet” pointer for each bullet and “last_bullet” pointer to the head of the list for each player.
And instead of allocating each bullet separately, I would also follow mjv's suggestion of pre-allocating some number of them and picking the next available one. In the linked list implementation, you could use the same “next_bullet” pointers to maintain one list of pre-allocated bullets not currently in use. The advantage of this approach is that you could easily allocate more if you ran out of them, instead of maintaining an array, i.e. if the list of available bullets is empty just add them to the list on demand. Similarly, put “expired” (exploded?) bullets back into the list of available ones and the amount allocated will automatically adapt to however many is required.
Another thing that comes to mind is that you might not need to know which particular UFO (or other enemy) owns a given bullet; just have a single pointer (e.g. SHIP **) for the owning player and set it to NULL for all non-player bullets. If this is not suitable, you could also consider storing the type of each owner in the beginning of owner struct itself, e.g.:
enum EntityType { TYPE_PLAYER_SHIP, TYPE_UFO_SHIP, TYPE_BULLET, };
struct GameEntity {
enum EntityType type;
// This struct is not actually used, it just defines the beginning
};
struct Ship {
enum EntityType type; // Set to TYPE_PLAYER_SHIP when allocating!
…
};
struct UFO {
enum EntityType type; // Set to TYPE_UFO_SHIP when allocating!
…
};
struct Bullet {
enum EntityType type; // Set to TYPE_BULLET when allocating!
struct GameEntity *owner;
…
};
struct Bullet *ship_fire (struct Ship *ship) {
Bullet *b = get_next_available_bullet();
b->owner = (struct GameEntity *) ship;
return b;
}
void hit_asteroid (struct Asteroid *ast, struct Bullet *bullet) {
if (bullet->owner && bullet->owner->type == TYPE_PLAYER_SHIP) {
…
}
}
Note that this trick relies on pointers to different types of structs being interchangeable, and the single enum being stored at the same offset in each type of struct. In practice these are not unreasonable assumptions, but I'm not certain that this behaviour is strictly guaranteed in standard C (however, e.g. struct sockaddr uses the same trick, and it's used by various POSIX networking functions like bind).
I would do like this:
enum _ShipType
{
SHIPT_PLAYER,
SHIPT_UFO, //trailing , is good if you need to add types later
};
typedef struct _Bullet
{
// ...other properties
struct _Bullet_Owner
{
enum _ShipType type;
void* ship;
}owner;
} Bullet;
void ship_fire(Player* p)
{
Bullet* b = malloc(sizeof(Bullet));
// ...other init
b->owner.type = SHIPT_PLAYER;
b->owner.ship = p;
}
If there's only <constant> players, you would be better off having a dead flag for each and setting when they die. (And having them statically allocated.)
#define PLF_DEAD 0x1
//more stuff
struct _Player
{
long flags;
//other data;
}player_1,player_2;
Or you could have an array, or...
Edit: Nonconstant players, a horrifically overengineered solution:
typedef struct _PShip
{
long nweakrefs;
void** weakrefs;
//etc...
}PShip;
PShip* PShip_new(/* args or void */)
{
PShip t;
t = malloc(sizeof(PShip));
t->nweakrefs = 1;
t->weakrefs = malloc(sizeof(void*)*t->nweakrefs);
//other stuff
}
void PShip_regref(PShip** ref)
{
void** temp;
temp = realloc((*ref)->weakrefs,(*ref)->nweakrefs);
if(!temp){/* handle error somehow */}
(*ref)->weakrefs = temp;
(*ref)->weakrefs[(*ref)->nweakrefs++] = ref;
}
void PShip_free(PShip* ship)
{
long i;
for(i=0;i<ship->nweakrefs;i++)
{
if(ship->weakrefs[i]){*(ship->weakrefs[i]) = 0;}
}
//other stuff
}
Alternatively, a reference count might work well, without the O(n) memory.
typedef struct _PShip
{
long refs;
//etc...
}PShip;
void Bullet_free(Bullet* bullet)
{
//other stuff
if(bullet->owner.type == SHIPT_PLAYER)
{
if(--(((PShip*)(bullet->owner.ship))->refs) <= 0)
{PShip_free(bullet->owner.ship);}
}
}
Also, neither of these is threadsafe.