On 27 Feb 2004 23:40:26 +0000, Anton Altaparmakov <ai...@ca...> =
wrote:
>> >volume.h includes inode.h
>> >inode.h includes runlist.h
>> >runlist.h includes volume.h
>>=20
>> runlist.h includes attrib.h
>> attrib.h includes runlist.h
>>=20
>> attrib.h includes volume.h
>> volume.h includes ... <see the first circle>
>>=20
>> is this intentional? should i stop looking for circles?
>
>It is intentional. You will notice that each file references bits from =
the=20
>other file.
sometimes, and almost :O)
e.g. if you remove #include "runlist.h" from attrib.h make will still =
succeed
>There is no way to fix this (feel free to prove me wrong!) short of =
using=20
>only one massive header file...
i think it's easy to prove that it's never needed:
a.h includes b.h
b.h includes a.h
1. assuming no header guards (#ifdef A_H) it's an infite loop
at compile-time, and it doesn't compile
2. with include guards, when a.h is included in a program, it
starts by including b.h which does not again include a.h as=20
the header guard is already declared, but in fact nothing=20
from a.h has been compiled yet, so if the compile succeeds,
b.h necessarily hasn't used anything from a.h (so for every=20
such circle there must be at least one point where it can be=20
broken up)
the reason you felt you need the circles is that sometimes
a.h needs an incomplete type from b.h and at the same time
b.h really depends on a.h=20
this is why runlist.h forward declares runlist_element and=20
runlist before including attrib.h: attrib.h needs incomplete
types from runlist.h, and runlist.h depends on attrib.h; but=20
you still had to handcode that into runlist.h because circular=20
includes don't really solve this problem (1 & 2 means they=20
don't do anything at all when they compile)
volume.h similarly forward declares ntfs_volume before including=20
other headers; i haven't got further yet :O)
using handcoded forward declarations is one option, but afaik
the canonical (pretty) solution is to provide separate forward=20
declaration headers, like
runlist_fwd.h:
typedef struct _runlist_element runlist_element;
typedef runlist_element runlist;
attrib.h:
#include "runlist_fwd.h" <-- instead of "runlist.h"
...
handcoding the forward declarations into the header
is perfectly o.k. (although the right place is attrib.h,
not runlist.h), but having a forwarding header means
- slightly less maintenance (only one file has to be
edited when e.g. you add a new type to runlist.h)
- slightly faster compilation (user code that only
needs the incomplete type can also include the _fwd.h
instead of the real one)
- imho a bit more clarity
br,
andras
|