Questions regarding cyclic header dependency

F

fc2004

Hi,

Is there any tools that could report where cyclic header dependency
happens? this would be useful when working with a large project where
tens or hundreds of headers files may form complex inclusion
relationships.

Another question I have is how to solve this dependency when "typedef"
is used. usually we can use forward declaration like "struc A; " to
solve references like "struct A* p". But in many places we have
"typedef struct A A_t;"in one header file, then how to solve references
like "A_t* p" in another header without including the first header?

Any hint in appreciated!

Jeremy
 
M

Michael Mair

Hi,

Is there any tools that could report where cyclic header dependency
happens?

If you use header guards, then your compiler will refuse to compile
"cyclic" include dependencies that do not work. This helps you to
avoid such include dependencies early.
Tools such as PCLint might be able to help you but essentially it
is "do not get bitten in the first place".
If you are unlucky and inherited code that does not follow this
simple guideline, then start by inserting header guards header
by header and make sure the whole thing still does compile.
If you encounter cyclic dependencies, then resolve them by isolating
the common parts necessary for all headers in one separate header.
This can be done iteratively, if necessary.
this would be useful when working with a large project where
tens or hundreds of headers files may form complex inclusion
relationships.

If these relationships are not messed up in the first place:
No, I don't think so.
Only include what you need. As long as your compiler does not
run into numerical limits, everything is fine.

Another question I have is how to solve this dependency when "typedef"
is used. usually we can use forward declaration like "struc A; " to
solve references like "struct A* p". But in many places we have
"typedef struct A A_t;"in one header file, then how to solve references
like "A_t* p" in another header without including the first header?

Not at all.
If you want A_t, then include the first header -- it is the provider
of the typedef and should be the only provider.
Even if your compiler allows multiple identical typedefs, they are
still not standard C and can lead to trouble later on. As you talk
about large projects, you probably will have to port or migrate them
sooner or later -- this necessitates the usage of standard C wherever
possible.
If you want to communicate that A_t is in truth struct A and every
part of your program can alternatively use struct A, then A_t is
unnecessary.
With the exception of function pointer types, typedefs should not
be used to make typing a typename shorter but in order to express
a role the typedef fills.
A good article about typedefs from Chris Torek:
<[email protected]>


Cheers
Michael
 
J

Jeremy

Michael said:
If you use header guards, then your compiler will refuse to compile
"cyclic" include dependencies that do not work. This helps you to
avoid such include dependencies early.
Tools such as PCLint might be able to help you but essentially it
is "do not get bitten in the first place".
If you are unlucky and inherited code that does not follow this
simple guideline, then start by inserting header guards header
by header and make sure the whole thing still does compile.
If you encounter cyclic dependencies, then resolve them by isolating
the common parts necessary for all headers in one separate header.
This can be done iteratively, if necessary.
header guards are always used. and compiler gives the error but still
this is very hard to figure out where it happens, since the C file may
contain a bunch of header files and each of them could have several
layers of inclusion themselves. I used another lint tool but and the
error message is not very helpful.
If these relationships are not messed up in the first place:
No, I don't think so.
Only include what you need. As long as your compiler does not
run into numerical limits, everything is fine.
when inheriting code from other people in a large project, people may
not just include what's really necessary. Later comers can run into my
situation even if they include what is necessary. when you have 5-6
levels of inclusion, you have no idea where the real problem is.
Not at all.
If you want A_t, then include the first header -- it is the provider
of the typedef and should be the only provider.

I can't agree.
One rule I got from people was that whenever you are only referencing a
type name insead of its size, use forward declaration, not the header
file where the type is defined. This can effectively reduce possible
header coupling. But this seems not possible when typedef is widely
used.
Even if your compiler allows multiple identical typedefs, they are
still not standard C and can lead to trouble later on. As you talk
about large projects, you probably will have to port or migrate them
sooner or later -- this necessitates the usage of standard C wherever
possible.
If you want to communicate that A_t is in truth struct A and every
part of your program can alternatively use struct A, then A_t is
unnecessary.
With the exception of function pointer types, typedefs should not
be used to make typing a typename shorter but in order to express
a role the typedef fills.

My impression is that this kind of typedefs are widely used in
commercial production code.
A good article about typedefs from Chris Torek:
<[email protected]>

Thanks for the info. I will try to find it.

Jeremy
 
M

Michael Mair

Jeremy said:
header guards are always used. and compiler gives the error but still
this is very hard to figure out where it happens, since the C file may
contain a bunch of header files and each of them could have several
layers of inclusion themselves. I used another lint tool but and the
error message is not very helpful.

Most compilers offer you output of the preprocessed code,
sometimes complete with #line and #file directives; some even
offer to not descend into standard headers or headers included
using <>.
With this, you can often easier find the point where the error
occurs.

If you use version control of any kind, then you should be able
to pinpoint the change which made the whole thing uncompilable
and work from there.

when inheriting code from other people in a large project, people may
not just include what's really necessary. Later comers can run into my
situation even if they include what is necessary. when you have 5-6
levels of inclusion, you have no idea where the real problem is.

If _much_ more is included than strictly necessary:
Use tools to throw out unnecessary includes from headers.
This makes it much easier to find errors.
I once inherited a 0.5 MLoc project with all the experts no
longer directly available. Cleaning up the headers in this
way helped a lot.

I can't agree.
One rule I got from people was that whenever you are only referencing a
type name insead of its size, use forward declaration, not the header
file where the type is defined. This can effectively reduce possible
header coupling. But this seems not possible when typedef is widely
used.

I think you misunderstand:
,- someofmytypedefs.h --
#ifndef H_SOMEOFMYTYPEDEFS_H
#define H_SOMEOFMYTYPEDEFS_H

struct A;
.....

typedef struct A A_t;
.....
#endif
`---
,- a_stuff.h --
#ifndef H_A_STUFF_H
#define H_A_STUFF_H

#include "someofmytypedefs.h"

struct A {
....

};
#endif
`---
My impression is that this kind of typedefs are widely used in
commercial production code.

Yes. I thought you were talking about handwritten code.
For generated code, other rules apply; among other things, you
implicitly trust that constructs frowned on for handwritten code
are correct (by data flow and control flow analysis) and that
some uglies cannot be avoided without increasing the code
generation time and memory consumption.

FWIW, even production code generators can be convinced to not
emit typedefs of this kind; at least the good ones.

Thanks for the info. I will try to find it.

google groups still has it.


Cheers
Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top