[LCP]Rounding questions
Josh Helmer
jhelmer4 at cox.net
Sun Sep 8 04:36:05 UTC 2002
On Saturday 07 September 2002 04:08 am, Greg Black wrote:
> | OK... If you have an array of structures and you want to sort the
> | array. The easiest way to go about it is to write a compare function and
> | call qsort(). qsort() will just pass void pointers in to your compare
> | function. You will have to use a cast to do any sort of meaningful
> | comparison.
>
> This is one of those cases I was talking about. It counts as
> rare because qsort() is not used much in real code. And the
> reason behind the actual requirement for the cast in this case
> is quite subtle and utterly mysterious to most programmers, who
> end up "learning" from this that casts might be needed in all
> sorts of inexplicable situations.
>
> One odd thing is that this is one case where you did not need a
> cast in traditional C (which needed many more casts than C89),
> but where the 1989 standard added the requirement for a cast.
OK, now you have peaked my curiosity. How is that possible?
>
> | I have also found that if I want to write (somewhat) generic container
> | classes
>
> Sorry, this sounds like C++ -- a total waste of time and mental
> energy and not the subject of this list or of any comments of
> mine. One of the many weird differences between C++ and C is
> the requirement for all sorts of casts in C++.
I admit that the term "container classes" makes this sound like C++, but I am
actually refering to plain C. My second example comes from an attempt to
write object oriented (or at least object based) C code. I have written a
handful of these containers that I use frequently in my C code. The idea was
to create a generic interface so that I don't have to write all new code
every time I need a linked list, or a vector, or a binary tree...
The actual design stems more from my use of Java.. All of the container
classes that Java provides store things of type Object. What I did in my C
was to plan out a similar interface using the void* instead of Object. What
I ended up with are interfaces like:
LinkedList list_alloc();
list_free(LInkedList);
list_add_tail(LinkedList, void*);
list_add_head(LinkedList, void*);
void* list_find(LInkedList, void*, (int)(*compare)(const void*, const void*));
void* list_get_head(LinkedList);
void* list_get_tail(LinkedList);
void* list_get_next(LinkedList);
void* list_get_prev(LinkedList);
etc...
I end up using function pointers to handle a lot of the messy type specific
details (like searching the list), but in general I have found that doing
this allows me to concentrate less on how to store the data and more on the
actual problem that I am dealing with. I will admit that this solution is a
bit more bloated than writing new linked list code to suit my needs at the
moment, but it has been very rare for me to find an instance where the
additional overhead was enough to get too concerned with... Especially in
light of the development time that I am able to save by using fully tested,
re-usable code.
Unfortunately, this code requires heavy use of the cast since everything in
the list is stored as a void pointer.
Maybe this is cheating anyhow... Both qsort() and my "container class" are
really examples of the same basic idea. No type information is maintained
with a void pointer so casts are often necessary if you need to retrieve any
useful information from it... The upside of the void pointer is that it
allows you to write more generic code, but the downside is that you give up
the sanity checks the compiler normally handles and you place the
responsibility for keeping track of what type of data the pointer actually
references on the programmer.
Josh
More information about the linuxCprogramming
mailing list