Recursive #includes

Daniel F. Fisher dff at Morgan.COM
Thu Mar 2 12:14:12 AEST 1989


In article <3701 at xyzzy.UUCP> throopw at agarn.dg.com (Wayne A. Throop)
writes:
> [clarification between two antithetical positions followed by
> a reasonable proposal involving "phantom objects" to define
> a ready to be read attribute for header files followed by this:]
>
>( This scheme still doesn't deal with cyclic includes broken with
>  #ifdef... but despite there being ways to deal with that as well,
>  my personal feeling is "don't DO that" is a good remedy.  )

Since the world is not as well layered as one would sometimes like
to believe, it is likely one will at usually need to cope with cyclic
includes.  That is unless one does away with modularity by putting
everything in the same include file.  

Suppose one assumes a system in which there is no cyclic dependencies
between modules, then the dependency relationship is a complete
partial ordering of the set of modules.  So one could represent is
as a sufficiently deep layer cake.  But if the system cannot be
layered, say due to a reflexive relationship between two modules
(I point to your objects and you point to mine), this implies that
there must be cyclic dependencies.

In a modular style, one usually specifies the interface to a module
inside a header file.  This header file is included in any source
file that references objects defined in the module.  In particular,
a header file for one module should include another header file for
another if that first modules interface depends on declarations found
in the second's interface.  In this way, a module that depends on
another, but not directly on things that that module's interface
depends, only needs to include the header file of modules on which
it directly depends.  [Aside: This is the source of my recommendation
to myself any anyone who will listen that header files, by themselves,
should compile/lint cleanly.  Of course, its bad form to define
data objects or functions in a header, so if its compiled, a header
should yield an object file with zero length data and text segments.]

As an example, consider a module called tran.c, that handles a data
structure defining transactions in a system and trproc.c, that handles
a data structure defining transaction processors in the same system.
In this system, transactions are received by a front-end processor,
routed to the appropriate back-end processor which processes the
transaction and returns the response to the front-end for forwarding
to the originator of the transaction.  One of the requirements is
that it be possible to close a processor and dispose of all its
transactions in a reasonable manner (return a negative response to
the originator, and free the resources allocated for the transaction).
In this system, struct tran includes pointers to the front-end and
back-end processors that are handling the transaction.  The processors
also contain lists of transactions that they are currently processing.
Closing a transaction processor requires it to abort processing of
its transactions on their other processor.  So tran.c refers to
trproc.c and trproc.c refers to tran.c and tran.h refers to trproc.h
and trproc.h refers to tran.h.  So we have a situation in which cyclic
dependencies are quite natural and I claim necessary.

tran.h:
-------------------------------------
#ifndef included_tran_h
#define included_tran_h

#include "trproc.h"

struct tran
{
	struct trproc *frontend_proc;
	struct trproc *backend_proc;
...
};
...
#endif
-------------------------------------

tran.c:
-------------------------------------
#include "trproc.h"
#include "tran.h"
...
-------------------------------------

trproc.h:
-------------------------------------
#ifndef included_trproc_h
#define included_trproc_h

#include "tran.h"

struct trproc
{
	struct tran **trans;
...
};
...
#endif
-------------------------------------

trproc.c:
-------------------------------------
#include "tran.h"
#include "trproc.h"
...
-------------------------------------

-- 
Daniel F. Fisher
dff at morgan.com



More information about the Comp.lang.c mailing list