On Tue, 8 Jul 2003, Derk Gwen wrote:[color=blue]
>[/color]
[stupid octothorpe quoting fixed]
[color=blue]
>
jcblanchard@netcourrier.com (JCB) wrote:[color=green]
> >
> > I have two C file which are referencing in a circular way.
> >
> > I have car.c, structure car and functions prototypes of car.c are in a
> > file car.h
> > I have also engine.c, a structure engine and functions prototypes of
> > engin.c are in a file engine.h.[/color]
>
> If car and engine are so incestuous that they need to know each other's
> structures, you should move them into one file. They are tightly coupled
> and the program organisation should reflect that.[/color]
IMHO, not if the concept of "engine" is distinct from the concept of "car"
(which in this trivial example it is). A car "has-a" engine, but so do
other things, and maybe someday you'll want to change your "engine" class
to work with "lawnmowers", without having to weed out all the intermixed
declarations and definitions of "car"-related methods.
Of course, any beginner's textbook would tell you to use inheritance from
an "Engine-Powered Vehicle" class in the first place. But I don't listen
to that kind of textbook. ;-)
My advice: Keep the separate files. Just put them in the same directory.
IMHO.
[color=blue]
> You can couple them more loosely by using pointers to incomplete
> structures and functions.
> car.h
> #ifndef car_h
> #define car_h
> #include "engine.h"
> typedef struct car car;
> t functionname(engine *...);
> t functionname(...);
> ...
> #endif[/color]
Ahh. *This* is where the problem I mentioned earlier bites people.
Look at what happens when this file is preprocessed:
[color=blue]
> #ifndef car_h
> #define car_h
> #include "engine.h"[/color]
"car_h" is not defined, so "car_h" gets defined.
Then we #include "engine.h" as follows:[color=blue]
> #ifndef engine_h
> #define engine_h
> #include "car.h"[/color]
"engine_h" is not defined, so "engine_h" gets defined.
Then we #include "car.h" as follows:[color=blue]
> #ifndef car_h[/color]
"car_h" is defined, so we skip to the corresponding[color=blue]
> #endif[/color]
....and return to processing "engine.h".
[color=blue]
> typedef struct engine engine;[/color]
Now we have a typedef for "engine". Good.
[color=blue]
> t functionname(car *...);[/color]
Now we have a function taking a "car *". Bad.
The identifier "car" has not been declared to mean
anything anywhere. The compiler chokes.
The solution to this problem is left as an exercise
for Derk. (I explained it, albeit less lucidly, earlier
in the thread.)
-Arthur