Questions regarding cyclic header dependency

Discussion in 'C Programming' started by fc2004@gmail.com, Apr 21, 2006.

  1. Guest

    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
     
    , Apr 21, 2006
    #1
    1. Advertising

  2. Michael Mair Guest

    schrieb:
    > 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:
    <>


    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Apr 21, 2006
    #2
    1. Advertising

  3. Jeremy Guest

    Michael Mair wrote:
    > schrieb:
    > > 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.
    >

    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.

    > > 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.
    >

    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.

    >
    > > 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.


    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:
    > <>
    >
    >


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

    Jeremy

    > Cheers
    > Michael
    > --
    > E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Jeremy, Apr 22, 2006
    #3
  4. Michael Mair Guest

    Jeremy schrieb:
    > Michael Mair wrote:
    >> schrieb:
    >>
    >>>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.

    >
    > 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.


    >>>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.

    >
    > 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.


    >>>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.

    >
    > 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
    `---

    >>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.


    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.


    >>A good article about typedefs from Chris Torek:
    >> <>

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


    google groups still has it.


    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Apr 22, 2006
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dennis Lerche

    Cyclic Dependency problem

    Dennis Lerche, May 11, 2004, in forum: C++
    Replies:
    6
    Views:
    11,235
    Khaled.Jouda
    Jul 5, 2010
  2. pallav

    Cyclic header dependency

    pallav, Apr 12, 2007, in forum: C++
    Replies:
    1
    Views:
    514
  3. pallav

    Cyclic header dependency

    pallav, Apr 12, 2007, in forum: C++
    Replies:
    3
    Views:
    397
    Michael
    Apr 13, 2007
  4. pallav

    Cyclic header dependency

    pallav, Apr 12, 2007, in forum: C++
    Replies:
    0
    Views:
    379
    pallav
    Apr 12, 2007
  5. pallav

    Cyclic header dependency

    pallav, Apr 12, 2007, in forum: C++
    Replies:
    1
    Views:
    594
Loading...

Share This Page