Type Punning

K

kid joe

Hi all,

Im writing a small library implementing a few standard data-structures.
For generality Im giving each node struct a "void* data" member so that
the user of the library can make a tree or list or whatever of any
data-type s/he wants.

One common thing to store is numeric types. Its very longwinded to
have to do

int *i = malloc(sizeof(*i));
*i = 42;
insert_node(X, i);

especially when there are lots of numbers to insert. On my system, its
possible to convert pointers to integers, so I can simplify this code by
just doing

insert_node(X, (void*) 42);

and then I can retrieve the data later by casting to intptr_t.

Also for unsigned integers, I can convert back to uintptr_t.

Fine so far...

What I was wondering was about floating-point types. I'd like to know
which of them (float/double/long double) has the same size as a pointer so
that I can get the conversion right... but unfortunately theres no
fltptr_t! Also using conditional compilation doesnt work because the
preprocessor doesnt seem to know about sizeof()!

Does anyone have any ideas for a good way to do this? I dont mind if the
answers only work on common desktop platforms.

Cheers,
Joe
 
A

Antoninus Twink

What I was wondering was about floating-point types. I'd like to know
which of them (float/double/long double) has the same size as a pointer so
that I can get the conversion right... but unfortunately theres no
fltptr_t! Also using conditional compilation doesnt work because the
preprocessor doesnt seem to know about sizeof()!

If you want to know this at preprocessing time, you'll need to do the
work when your library gets configured. If you're using autoconf, check
out the AC_CHECK_SIZEOF macro.
 
B

Ben Bacarisse

blargg said:
kid said:
Im writing a small library implementing a few standard data-structures.
For generality Im giving each node struct a "void* data" member so that
the user of the library can make a tree or list or whatever of any
data-type s/he wants. [...]
especially when there are lots of numbers to insert. On my system, its
possible to convert pointers to integers, so I can simplify this code by
just doing

insert_node(X, (void*) 42); [...]
What I was wondering was about floating-point types. I'd like to know
which of them (float/double/long double) has the same size as a pointer so
that I can get the conversion right... but unfortunately theres no
fltptr_t! Also using conditional compilation doesnt work because the
preprocessor doesnt seem to know about sizeof()!

Does anyone have any ideas for a good way to do this? I dont mind if the
answers only work on common desktop platforms.

Works on all platforms:

union data_t
{
void* p;
int i;
double d;
void (*f)( void );
};

struct list_node_t
{
union data_t data;
struct list_node_t* next;
};

And perhaps write some helper functions to create a data_t given one of
its member types.

C99's compound literals and designated initialisers are a win here:
(data_t){.d = 42.0} is not too clumsy to write. Since the OP said
"common desktop platforms" rather than "common desktop compilers" this
may be protable enough.
 
G

Gene

Hi all,

Im writing a small library implementing a few standard data-structures.
For generality Im giving each node struct a "void* data" member so that
the user of the library can make a tree or list or whatever of any
data-type s/he wants.

One common thing to store is numeric types. Its very longwinded to
have to do

int *i = malloc(sizeof(*i));
*i = 42;
insert_node(X, i);

especially when there are lots of numbers to insert. On my system, its
possible to convert pointers to integers, so I can simplify this code by
just doing

insert_node(X, (void*) 42);

and then I can retrieve the data later by casting to intptr_t.

Also for unsigned integers, I can convert back to uintptr_t.

Fine so far...

What I was wondering was about floating-point types. I'd like to know
which of them (float/double/long double) has the same size as a pointer so
that I can get the conversion right... but unfortunately theres no
fltptr_t! Also using conditional compilation doesnt work because the
preprocessor doesnt seem to know about sizeof()!

Does anyone have any ideas for a good way to do this? I dont mind if the
answers only work on common desktop platforms.

I've used a number of C libraries that do this. In the school of hard
knocks, I've learned--as a library user--always to either do access
through macros or to wrap the attached value in a struct (even if it
is just an integer) so that adding a new data field does not involve
changing many casts. If it were me, I'd just advise the user in your
documentation to adopt one or both ideas and leave the decision out of
the API. I wouldn't even provide the insert_node() call. C APIs are
best when they're lean.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top