1999-01-14 19:38:42

by Martin Cracauer

[permalink] [raw]
Subject: void* taking functions type-safe in C (Re: C++ in kernel)

In <[email protected]>, Marc Espie wrote:
> C++ template expansions can do the exact same things C macros do, with
> strict type-checking

Here is the C scheme I use to make void* - taking Functions type-safe,
without bloating or (even duplicating) the code.

You'd better try the code in the attachment now and read on
afterwards. Trust code, not words :-)

Note that in main() the proper warning is emitted for the safe call,
but that the assembly and object code of the safe and unsafe variants
of the function are *excatly* of the same size. [Don't be mislead by
the file size, the function name is longer. Use size(1) for the object
files and diff for the assembly files.]


.
.
.


OK, for those without mime...

/* This function actually expects a pointer to int */
int libfunc(void *bla1, void *bla2);

static inline int libfunc_int(int *i1, int *i2)
{
return libfunc(i1, i2);
}

The inline function is *complelety* removed even with gcc-2.7.2
-O. Still, it makes the function type-safe, a warning is emitted if
anything else than an int* pointer is being passed. This is exactly
what we need.

If you don't want to write multiple type-wrappers for you void* -
taking functions, you can accompany each of them with a
function-generating macro like this:

#define wrapper(mp1, mp2) \
static inline int mp1 ## _ ## mp2(int *i1, int *i2) \
{ \
return libfunc(i1, i2); \
}
and then use or include this before using the function:
wrapper(libfunc, int);

to get the libfunc_int definition. A matter of taste whether to use
such a macro or not. I usually wouldn't, but used it in the example.

For compilers that don't have inline declaration you can make a macro
(losing type-safeness) or a real function out of the wrapper. Even
#ifdef-conditionally (safe during development and macro when shipping).

Summary:

That is *no* need to duplicate your
collections/sorting/generic-read-write functions to make them
type-safe for multiple different client types. Given a descent C
compiler, it is even overhead-free. Possibly slowdown may result when
the inline function prevents further optimization of the surrounding
code. But you could easily compile type-safe once and then #ifdef
these inline functions to straight macros without loosing anything.



For the record, I as well often think "hey, *this* project would
finally gain from C++". I start in C++ until the goal of the program
becomes clear. Then I realize that I needed C++ additional
expressional power (which is surely there) just to approach the
solution further. But once I understood the problem and the solution
approach I think in nothing else than machine terms and C++ goes in
my way. Then I rewrite it in C or ocassionally in Objective-C.

Martin
--
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Martin Cracauer <[email protected]> http://www.cons.org/cracauer/
BSD User Group Hamburg, Germany http://www.bsdhh.org/


Attachments:
cast-overhead.tar.gz (1.06 kB)