Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!decwrl!sun!pitstop!sundc!seismo!uunet!mstan!dff From: dff@Morgan.COM (Daniel F. Fisher) Newsgroups: comp.lang.c Subject: Re: Recursive #includes Keywords: recursive includes, modularity Message-ID: <237@mstan.Morgan.COM> Date: 2 Mar 89 02:14:12 GMT References: <570@marob.MASA.COM> <9727@smoke.BRL.MIL> <964@philmds.UUCP> <9736@smoke.BRL.MIL> <3701@xyzzy.UUCP> Reply-To: dff@Morgan.COM (Daniel F. Fisher) Organization: Morgan Stanley and Co., NY, NY Lines: 106 In article <3701@xyzzy.UUCP> throopw@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@morgan.com