# Thread: Unions and void pointers

1. ## Unions and void pointers

There are at least two questions in this post. I thought it might be somewhat hard to find them amongst all of the text, so I made them green.

----

I recently wrote some code that used a union of pointers to implement a sort of inheritance:
Code:
```struct cat_t {
int mice_caught;
};

struct dog_t {
int squirrels_chased;
int bones_hidden;
};

enum type_t {
ANIMAL_CAT,
ANIMAL_DOG
};

/* The union method */
struct animal_t {
const char *name;
enum type_t type;

union {
struct cat_t *cat;
struct dog_t *dog;
} p;
};```
(This code is, of course, entirely fictional. But the real code was much the same.)

Anyway, I thought of doing this.
Code:
```/* The union-with-void-pointer method */
struct animal_t {
const char *name;
enum type_t type;

union {
struct cat_t *cat;
struct dog_t *dog;
void *all;
} p;
};```
That way, I could use
Code:
`free(animal.p->all);`
and perhaps even
Code:
```animal.p->all = malloc(sizeof_animal(type));

size_t sizeof_animal(enum type_t type) {
switch(type) {
case ANIMAL_CAT:
return sizeof(struct cat_t);
/* ... */
}
}```
But I don't know if that would be a good idea. It relys on the fact that sizeof(struct cat_t *) == sizeof(struct dog_t *) == sizeof(void *), which is probably not a good idea.

It's not really that important; I can just free() and malloc() using the right pointer. But I was wondering if this is standard and portable. Can one to rely on the sizeof() a void pointer being the same as the sizeof() a pointer to a structure?

----

As for the union of void pointers, another way of implementing it would be:
Code:
```/* The void pointer method */
struct animal_t {
const char *name;
enum type_t type;

void *p;
};```
But then a cast would be required.
Code:
```animal.p.cat->mice_caught;  /* union method */
((struct cat_t *)animal.p)->mice_caught;  /* void pointer method */```
I thought the first method was a little cleaner. But, of course, the second would allow free()ing and malloc()ing the data without worrying about sizeof(void *).

Does anyone else have some other ideas of how to implement this quasi-inheritance? (No, I don't really want to use C++. )

2. what usage do you want for the code that uses the structs? are you adverse to init and cleanup functions?

3. Originally Posted by dwks
Can one to rely on the sizeof() a void pointer being the same as the sizeof() a pointer to a structure?
In C, yes! all pointers, regardless of what they point to are the same size. This is essentially, because they all hold an address to a piece of memory. The pointer itself is not concerned with what you're storing there, it could be an int, the first element of a char array or a cat (struct).

QuantumPete

4. Originally Posted by QuantumPete
In C, yes! all pointers, regardless of what they point to are the same size. This is essentially, because they all hold an address to a piece of memory. The pointer itself is not concerned with what you're storing there, it could be an int, the first element of a char array or a cat (struct).

QuantumPete
According to Salem, apparently not http://cboard.cprogramming.com/showp...87&postcount=5

5. Originally Posted by dwks
Does anyone else have some other ideas of how to implement this quasi-inheritance? (No, I don't really want to use C++. )
Well, how serious do you want to go with this?

A very serious solution woulc be something along the lines of using shared libaries (ie. .dlls on Windows) where each one represents a new type. This way you can add new types as you go along. Each library could contain the implementation of new data types that you void pointer would point to, as well as known functions that return the size of the data type that you are using and other such things.

If you want a less serious solution, then I guess you're on the right track. C++ would probably be better for a true OOP, but since you're against it, I'd just stick with the unions that have known types and a void * if you know you'll have unknown types.

6. Originally Posted by zacs7
I think he meant across different machines. I.e. you can't rely on your *nix system to have the same size pointers as a BBC compact or a Vista machine.
On the same machine however, all pointers are the same size (you can after all cast any pointer to any other pointer!)
This is like the fact that on most machines an int is 32 bits, but it doesn't *have* to be. Same for a pointer, they are normally 32 bits (i.e. a WORD, i.e. the size of your address bus) but this can vary from machine to machine.

http://www.c-faq.com/null/machexamp.html

8. :-S I'm not convinced. I don't think anyone here is programming on Cray mainframes, old HP3000, or Honeywell-Bull machines.
Given your good old SUN or IBM machines, I think you can safely assume that all pointers are the same size (how else would GTK work otherwise, which does nothing but cast pointers?!)

QuantumPete

9. Agreed, but what if someone had a <insert arch here> PC, and they wanted a pet database program, oh noes!

10. I give up :-P

11. > size_t sizeof_animal(enum type_t type)
In the same vein, you should implement the malloc_animal and free_animal functions.

Eg.
Code:
```animal_t *malloc_animal(enum type_t type) {
animal_t *a = malloc ( sizeof *a );
a->type = type;
a->name = NULL;
switch ( type ) {
case ANIMAL_CAT:
a->p.cat = malloc ( sizeof *a->p.cat );
break;
default:
// diagnostic for unknown animal
}
return a;
}```
Likewise, free_animal() also has a switch/case.

No casting magic, no assumptions on the representation of different pointer types, and the ability to add some additional diagnostic if you need to.

12. Originally Posted by zacs7
Well, how serious do you want to go with this?

A very serious solution woulc be something along the lines of using shared libaries (ie. .dlls on Windows) where each one represents a new type. This way you can add new types as you go along. Each library could contain the implementation of new data types that you void pointer would point to, as well as known functions that return the size of the data type that you are using and other such things.

If you want a less serious solution, then I guess you're on the right track. C++ would probably be better for a true OOP, but since you're against it, I'd just stick with the unions that have known types and a void * if you know you'll have unknown types.
I don't think that it's "serious" enough to warrant separate shared libraries and all that, though it's a good idea and one I'll certainly keep it in mind.

I don't have any unknown types, so there's no reason to use a void* pointer on that count. It was just there to facilitate allocation and freeing.

Given your good old SUN or IBM machines, I think you can safely assume that all pointers are the same size (how else would GTK work otherwise, which does nothing but cast pointers?!)

QuantumPete
I think it would probably use (I've never used it myself) this sort of code:
Code:
```animal.p.cat->mice_caught;  /* union method */
((struct cat_t *)animal.p)->mice_caught;  /* void pointer method */```
Like you said, this is casting. There's nothing wrong with it, even if void pointers and struct cat_t pointers are different sizes, because the compiler will know how to convert between the types. It's what I was doing, treating a void pointer and a struct cat_t pointer as exactly the same size and edianness and everything, that is suspect.

Originally Posted by robwhit
are you adverse to init and cleanup functions?
> size_t sizeof_animal(enum type_t type)
In the same vein, you should implement the malloc_animal and free_animal functions.
I think that's what I'll do. It's what I had, actually, until I hit upon this brilliant idea to use a void pointer . . .