Messages in this thread | | | Date | Thu, 14 Jan 1999 20:08:29 +0100 | From | Martin Cracauer <> | Subject | void* taking functions type-safe in C (Re: C++ in kernel) |
| |
In <19990112104939.20004@liafa1.liafa.jussieu.fr>, 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 <cracauer@cons.org> http://www.cons.org/cracauer/ BSD User Group Hamburg, Germany http://www.bsdhh.org/ [unhandled content-type:application/x-tar-gz] | |