[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