files.c and ubiqx

Christopher R. Hertel crh at NTS.Umn.EDU
Mon Aug 17 14:47:49 GMT 1998


Andrew,

The interface isn't the problem.  The issue is the object-oriented nature
of the code, as implemented in standard C.  The macros perform type casts
in order to make a structure work like a descendant type.

There are some simple solutions, though.  Here are some examples:

typdef struct
  {
  ubi_dlNode      node;
  struct whatever data;
  } descendant_type;

descendant_type *MyNode;

You can skip the macros and pass a pointer to the node directly to the API
functions.  Above, you would pass &(MyNode->node) to ubi_dlInsert() or
ubi_dlRemove(), and never use the macros.

It would probably make sense to write short functions that would do the 
work for you.  Eg:

static descendant_type *insert_descendant_type( mylist_type     *mylist,
                                                descendant_type *mynode,
                                                descendant_type *afternode )
  {
  (void)ubi_dlInsert( &(mylist->list),
                      &(mynode->node),
                      (afternode) ? &(afternode->node) : NULL
                    );
  return( mynode );
  } /* insert_descendant_type */

This specifically adds code that checks *both* the type of the descendant
list & node *and* the type of the ubi_dlList and ubi_dlNode.  That might
be overkill.  You can achieve your goal more simply with something like
this: 

static descendant_type *AddHead_descendant_type( mylist_type     *mylist,
                                                 descendant_type *mynode )
  {
  return( (descendant_type *)ubi_dlAddHead( mylist, mynode ) );
  } /* AddHead_descendant_type */

static descendant_type *AddNext_descendant_type( mylist_type     *mylist,
                                                 descendant_type *mynode,
                                                 descendant_type *afternode )
  {
  return( (descendant_type *)ubi_dlAddNext( mylist, mynode, afternode ) );
  } /* AddNext_descendant_type */

You get the general idea.  The only thing that this does is add
compiler-time type checking on the input parameters (and possibly a very
small amount of overhead).  Adding the type checking is what you wanted, 
however.

You would have to do this kind of thing for every descendant type, but the
overhead should be much less than re-implementing a linked list each time. 

Chris -)-----

> Chris,
> 
> I thought I'd explain why I didn't use the ubiqx calls in the doubly
> linked list code in files.c. I thought you might be wondering ...
> 
> The reason is the casts in the ubiqx macros. When you write linked
> list code explicitly the compiler tells you about getting the pointers
> of the wrong type and similar mistakes. If you do it via ubiqx then
> you go via macros which hide the types. The casts ensure that the
> compiler doesn't complain, but that also means that if you have a
> mistake then the compiler won't point it out. You could pass a int
> instead of a linked list to ubi_dlAddNext() and the compiler would
> dutifully do the wrong thing.
> 
> I don't really have a solution for making ubiqx retain all the
> typececking while retaining its interface, but I thought I should at
> least let you know why I don't tend to use it. I'm a big believer in
> letting the build system find bugs whenever possible :)
> 
> 	Cheers, Tridge
> 


-- 
Christopher R. Hertel -)-----                   University of Minnesota
crh at nts.umn.edu              Networking and Telecommunications Services


More information about the samba-technical mailing list