The best way to solve this would be to use unions.
Another way would be to memcpy() the list item to an actual struct (i.e., not a pointer) of the appropriate type. This would have the advantage of making each List item as small as possible.
A third way would be to just cast the pointer types as in type punning. C allows this as long as the object is dereferenced with its either its correct type or char.
Either way, you will need to put a code in each structure that identifies the type of object. There is no way the compiler can figure out what a pointer points to for you. And even if you could use typeof
, you shouldn't. It's not C99.
Technically, if you don't use a union, you will have a problem making a legal C99 access to the type code, because you will need to make a temporary assumption about the type and this will violate the rule that objects must be dereferenced as their actual type, via a union, or via a char *. However, since the type code must by necessity be in the same position in every type (in order to be useful) this common technical violation of the standard will not actually cause an aliasing optimization error in practice.
Actually, if you make the type code a char
, make it the first thing in the struct, and access it via a char *
, I think you will end up with code that is a bit confusing to read but is perfectly conforming C99.
Here is an example, this passes gcc -Wall -Wextra
#include <stdio.h>
#include <stdlib.h>
struct A {
char typeCode;
int something;
};
struct B {
char typeCode;
double somethingElse;
};
void *getMysteryList();
int main()
{
void **list = getMysteryList();
int i;
for (i = 0; i < 2; ++i)
switch (*(char *) list[i]) {
case 'A':
printf("%d\n", ((struct A *) list[i])->something);
break;
case 'B':
printf("%7.3f\n", ((struct B *) list[i])->somethingElse);
break;
}
return 0;
}
void *getMysteryList()
{
void **v = malloc(sizeof(void *) * 2);
struct A *a = malloc(sizeof(struct A));
struct B *b = malloc(sizeof(struct B));
a->typeCode = 'A';
a->something = 789;
b->typeCode = 'B';
b->somethingElse = 123.456;
v[0] = a;
v[1] = b;
return v;
}