Thread: Confusion with inclusions

  1. #1
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92

    Confusion with inclusions

    Coming from Ada and Pascal I have been very confused about the include operator which - as I study different C code - seems to have certain issues associated with it.

    One is the idea of multiple inclusions - I have tried to find articles using Google that talked about the details of multiple inclusions (their impact on performance, how to minimize them, etc) but have been unsuccessful.

    I would like to maintain logical separations of headers and include ONLY the necessary dependency for each file in my project - but, again, from the examples I've seen things seem to get slammed into one "shared" or "common" file to avoid apparent conflict.

    What are some details about the specifics of include, and, if you know of any, what are some good reference articles?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Well a clean (or messy) arrangement of include files flows naturally from the initial design of the program.

    If clear internal interfaces have been designed, then keeping the inclusions tidy is easy.

    But a poor/no design, where things are used at random all over the place, then it's all to easy to end up with
    #include "everything.h"
    just to save worrying about picking out which headers are actually needed today.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    But what are multiple inclusions and other issues associated with include?

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by 127.0.0.1 View Post
    One is the idea of multiple inclusions - I have tried to find articles using Google that talked about the details of multiple inclusions (their impact on performance, how to minimize them, etc) but have been unsuccessful.
    If you include something multiple times and don't get errors, there will be no impact on performance, etc, or at least not with a decent compiler.

    If you get errors, there is no performance.

    Errors are usually due to "redefinition". There are a few ways to eliminate that. The first is to only include files in the places you actually need them. This seems obvious, but consider: you have a .c file with main() in it, and it #includes "lib.h", which is a header for a separate .c file that will be compiled and linked to main(). lib.c uses some functions from <string.h>, but lib.h is just function prototypes, typedefs, etc. Since "string" is not a datatype in C, those prototypes cannot possibly require <string.h>; it's the function definitions that require it. In that case, #include <string.h> in lib.c, not in lib.h.

    This is kind of an irrelevant example since you can include string.h as much as you want, it will not result in redefinition errors or wasted resources, but it's the principle that counts: put your includes in your .c files first, and only move them to the header if the compiler throws an error on the header because (eg) it refers to a datatype that requires a .h.

    When you do get unavoidable redefinition errors, because you have a type defined in fileA.h that's used in the prototypes in fileB.h, and a type defined in fileB.h is used in fileA.h, use #define and #ifndef:

    Code:
    /* fileA.h */
    #define FILEA_INC 1
    
    #ifndef FILEB_INC
    #include "fileB.h"
    #endif
    
    /* fileB.h */
    #define FILEB_INC 1
    
    #ifndef FILEA_INC
    #include "fileA.h"
    #endif
    Now, when fileA.h is included from whereever, it will not #include itself again via fileB.h.
    Last edited by MK27; 05-03-2011 at 08:42 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by 127.0.0.1 View Post
    But what are multiple inclusions and other issues associated with include?
    Multiple inclusions can happen when one header file includes another (and yes, sometimes it's necessary).

    The way to deal with this is by a simple policy ouf using "include guards"...

    myinclude.h...
    Code:
    #ifndef MYINCLUDE_H
    #define MYINCLUDE_H
    
    // definitions and prototypes go here
    
    
    #endif     //MYINCLUDE_H
    This will prevent the compiler from reading the include file more than once for each source page that includes it.

    Alternatively, if your compiler supports it you can use #pragma once

    You should be aware however this is a "once per souce page" not "once per program" thing, since C compilers work on single pages.

    If you take a look at the headers in your C includes library you will likely discover they use this scheme or one very close to it.

    As for the performance hit... 0, none... these pages are reference information for the compiler, they do not form part of the final executable code.
    Last edited by CommonTater; 05-03-2011 at 08:46 AM.

  6. #6
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    file includes another (and yes, sometimes it's necessary).
    Is there a common scenario you can describe where such a case is true?

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    It would be difficult for me to find examples where it's NOT true...

    Look at the C and Windows headers in your compiler's include folder... almost every header in there will include at least one other header.
    (headers are plain text and can be opened in Notepad for examination... just don't be editing them!)

    This is also true for personal projects... I recently did a project that incorporated a number of "global" helper functions and typedefs which I defined in Global.C and prototyped in Global.H Every other include file in the entire project needed to include Global.H to work. This because the prototypes in each of the headers relied on typedefs in the Global header. Moreover, some of the headers for one part of the project had to include headers from other parts, for example Message.H had to include Network.H because it relied upon some of the network definitions. And, I assure you, this is not uncommon practice in C coding.

  8. #8
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    When I did work on Ada projects, if I included say "Ada.Strings.Fixed" to a my own string manipulation package and then included the string library into another package I would have to again include "Ada.Strings.Fixed" since Ada could only work with one level of inclusion. I would like to carry on the practice with my C projects (even if unnecessary) and from what I understand from the explanations this is possible if my code is designed properly

  9. #9
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by 127.0.0.1 View Post
    When I did work on Ada projects, if I included say "Ada.Strings.Fixed" to a my own string manipulation package and then included the string library into another package I would have to again include "Ada.Strings.Fixed" since Ada could only work with one level of inclusion. I would like to carry on the practice with my C projects (even if unnecessary) and from what I understand from the explanations this is possible if my code is designed properly
    Possible yes... practical, not likely.

    You are learning a new programming language; it is a mistake to try to make it into something you already know...
    As they say... "This ain't That!"

  10. #10
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Possible yes... practical, not likely.
    I consider this to add readability to code -- even if the unnecessary includes were commented out -- because it lists all of the specific dependencies of each file. Does anyone else not see benefit in this?

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by 127.0.0.1 View Post
    I consider this to add readability to code -- even if the unnecessary includes were commented out -- because it lists all of the specific dependencies of each file. Does anyone else not see benefit in this?
    If you want to do that, add comments or some other form of documentation. Readable code -- clear formatting, meaningful variable names, etc -- is great, but code that is included for no reason other than to "inform the reader about something" is not code, and it certainly would count as a very poor practice in my book. It is barely different from intentional obfuscation, meaning you are just as likely to confuse the reader as inform them because they will be trying to discern why this unnecessary code is there (and perhaps concluding they don't trust this tish).

    Simply commenting them out is no solution, because only you will understand why that is, and you already understand. It's also extremely lazy -- just use a real comment if you want, like "/* requires libX 3.2+ */". Readable code includes real comments, not hack ones.

    Build/make/configure systems can also be used to check for dependencies if you are distributing packages. For your own use, concern about dependencies is oxymoronic; you could not have written the code without them in the first place, and if you are using your stuff on a new machine the missing software will be obvious to you as soon as you try to compile.
    Last edited by MK27; 05-03-2011 at 11:09 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    Quote Originally Posted by 127.0.0.1 View Post
    I consider this to add readability to code -- even if the unnecessary includes were commented out -- because it lists all of the specific dependencies of each file. Does anyone else not see benefit in this?
    Nope. In fact, it works against encapsulation. If an implementation of a data structure uses another one, your approach would require you to include the header files for the extra data structure in every .C file using it. Later on, if you change which data structure is used to implement your library, you have to edit every single source file which included those headers instead of just editing one header which in turn included the other data structure's .h file.

    Not to mention that your approach becomes unworkable after a few layers of nested uses of headers. How is application programmer A supposed to know that the header for library B used by library C used by library D used by his code needs to be included? He shouldn't care - he just wants to know that to use libD, you #include "libd.h" and it works.

    Do you know what include files stdio.h needs to include to work? Are you sure you can pick the correct one when there's several different versions of float.h in different subdirectories under /usr/include? Sounds like a lot of work - luckily the people who wrote the C library didn't make you worry about it. Learn from what they did.

    Most compilers and IDEs will automatically track dependencies for you. Use that feature if you're worried about files getting out of date.

  13. #13
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by KCfromNC View Post
    Nope. In fact, it works against encapsulation. If an implementation of a data structure uses another one, your approach would require you to include the header files for the extra data structure in every .C file using it. Later on, if you change which data structure is used to implement your library, you have to edit every single source file which included those headers instead of just editing one header which in turn included the other data structure's .h file.
    Yep. Happened to me when working on the project I was talking about earlier... If I didn't have my typedefs for the project in Global.H, I would have had a huge job on my hands when I had to change a struct element from unit8_t to unit16_t .... With the headers arranged as they were, all I had to do was change that one line and recompile...

  14. #14
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Do you know what include files stdio.h needs to include to work? Are you sure you can pick the correct one when there's several different versions of float.h in different subdirectories under /usr/include?
    Sorry I guess I didn't explain myself well, I did not mean anything like this. I meant if say "liba.h" used a data structure from "libb.h" internally (not part of the function calls i.e passed in parameter or returned) and a data structure from "libc.h" externally (there were functions that returned this data structure or took it as a parameter).
    In a file that included "liba.h" i would only have included "liba.h" and "libc.h" not "libb.h".

    But I think the best option is to move on and do the common / best practices with the language I am using, so I think I am going to have to let this habit go.

    Thanks again for the helpful advice.
    Last edited by 127.0.0.1; 05-03-2011 at 05:12 PM.

  15. #15
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    No worries... every programmer has his or her own way of doing things.
    Only two issues really matter..
    1) Does it work?
    2) Is it maintainable?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ confusion
    By Eirik in forum Windows Programming
    Replies: 14
    Last Post: 04-29-2009, 01:54 PM
  2. Problems with inclusions.
    By Gatt9 in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2005, 02:46 AM
  3. Header file (multiple inclusions)
    By cjschw in forum C++ Programming
    Replies: 1
    Last Post: 08-10-2004, 10:28 AM
  4. Understanding Headers and Inclusions
    By jdm in forum C++ Programming
    Replies: 11
    Last Post: 04-21-2004, 10:11 PM
  5. Slim down inclusions!
    By kimberleyp in forum C++ Programming
    Replies: 0
    Last Post: 10-06-2001, 02:18 AM