2

Should header files have #includes?

I'm generally of the opinion that this kind of hierarchical include is bad. Say you have this:

foo.h:

#include <stdio.h> // we use something from this library here
struct foo { ... } foo;

main.c

#include "foo.h"
/* use foo for something */
printf(...)

The day main.c's implementation changes, and you no longer use foo.h, the compilation will break and you must add <stdio.h> by hand.

Versus having this:

foo.h

// Warning! we depend on stdio.h
struct foo {...

main.c

#include <stdio.h> //required for foo.h, also for other stuff
#include "foo.h"

And when you stop using foo, removing it breaks nothing, but removing stdio.h will break foo.h.

Should #includes be banned from .h files?

Tordek
  • 10,628
  • 3
  • 36
  • 67
  • possible duplicate of [Is there a standard #include convention for C++?](http://stackoverflow.com/questions/691079/is-there-a-standard-include-convention-for-c). This is C++, not C, but the principle is identical. There's lots of good advice there. http://stackoverflow.com/questions/181921/your-preferred-c-c-header-policy-for-big-projects is another. – Oliver Charlesworth Jul 05 '11 at 21:32

6 Answers6

4

You've outlined the two main philosophies on this subject.

My own opinion (and I think that's all that one can really have on this) is that headers should as self-contained as possible. I don't want to have to know all the dependencies of foo.h just to be able to use that header. I also despise having to include headers in a particular order.

However, the developer of foo.h should also take responsibility for making it as dependency-free as possible. For example, the foo.h header should be written to be free of a dependency on stdio.h if that's at all possible (using forward declarations can help with that).

Note that the C standard forbids a standard header from including another standard header, but the C++ standard doesn't. So you can see the problem you describe when moving from one C++ compiler version to another. For example, in MSVC, including <vector> used to bring in <iterator>, but that no longer occurs in MSVC 2010, so code that compiled before might not any more becuase you may need to specifically include <iterator>.

However, even though the C standard might seem to advocate the second philosophy, note that it also mandates that no header depend on another and that you can include headers in any order. So you get the best of both worlds, but at a cost of complexity to the implementers of the C library. They have to jump through some hoops to do this (particularly to support definitions that can be brought in through any of several headers, like NULL or size_t). I guess that the people who drafted the C++ standard decided adding that complexity to impersonators was no longer reasonable (I don't know to what degree C++ library implementors take advantage of the 'loophole' - it looks like MS might be tightening this up, even if it's not technically required).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • If `` declares methods that operate with iterators, why shouldn't it pull in ``? Why should the user be expected to do this? What if the user pulls in `` *after* ``? – Mike DeSimone Jul 05 '11 at 22:24
  • I probably shouldn't have said "tighten this up" - I didn't mean to imply that this was necessarily a good thing for users (it would probably have been best if `` didn't pull in `` from the start). There's never problem with pulling in `` after (or before) `` - if it has already been included, whatever include guard is used in `` will prevent it from causing problems the second time around. – Michael Burr Jul 05 '11 at 22:41
  • 1
    But that's the thing that bothers me: Why require users to pull in ``, and do it before ``, instead of just saying "`#include ` will just work"? It's like intentionally increasing complexity and introducing bugs in the name of some kind of "purity". – Mike DeSimone Jul 06 '11 at 00:39
3

My general recommendations are:

  • A file should #include what it needs.
  • It should not expect something else to #include something it needs.
  • It should not #include something it doesn't need because something else might want it.

The real test is this: you should be able to compile a source file consisting of any single #include and get no errors or warnings beyond "There is no main()". If you pass this test, then you can expect anything else to be able to #include your file with no problems. I've written a short script called "hcheck" which I use to test this:

#!/usr/bin/env bash
# hcheck: Check header file syntax (works on source files, too...)
if [ $# -eq 0 ]; then
    echo "Usage: $0 <filename>"
    exit 1
fi

for f in "$@" ; do
    case $f in
        *.c | *.cpp | *.cc | *.h | *.hh | *.hpp )
            echo "#include \"$f\"" > hcheck.cc
            printf "\n\033[4mChecking $f\033[0m\n"
            make -s $hcheck.o
            rm -f hcheck.o hcheck.cc
            ;;
    esac
done

I'm sure there are several things that this script could do better, but it should be a good starting point.

If this is too much, and if your header files almost always have corresponding source files, then another technique is to require that the associated header be the first #include in the source file. For example:

Foo.h:

#ifndef Foo_h
#define Foo_h

/* #includes that Foo.h needs go here. */

/* Other header declarations here */

#endif

Foo.c:

#include "Foo.h"
/* other #includes that Foo.c needs go here. */

/* source code here */

This also shows the "include guards" in Foo.h that others mentioned.

By putting #include "Foo.h" first, Foo.h must #include its dependencies, otherwise you'll get a compile error.

Tordek
  • 10,628
  • 3
  • 36
  • 67
Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
2

Well, main shouldn't rely on "foo.h" in the first place for stdio. There's no harm in including something twice.
Also, perhaps foo.h doesn't really need stdio. What's more likely is that foo.c (the implementation) needs stdio.

Long story short, I think everyone should just include whatever they need and rely on include guards.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • `stdio` was an arbitrary choice, but struct {foo} may use a type defined in `stdio`; it makes it necessary to include stdio.h and foo.h in both main.c and foo.c. – Tordek Jul 05 '11 at 22:52
  • A common example is headers that require the type `size_t`. – caf Jul 06 '11 at 03:41
1

Once you get into projects with hundreds or thousands of header files, this gets untenable. Say I have a header file called "MyCoolFunction.h" that contains the prototype for MyCoolFunction(), and that function takes pointers to structs as parameters. I should be able to assume that including MyCoolFunction.h will include everything that's necessary and allow me to use that function without looking in the .h file to see what else I need to include.

Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
0

If the header file needs a specific header, add it to the header file

#ifndef HEADER_GUARD_YOUR_STYLE
#define HEADER_GUARD_YOUR_STYLE

#include <stdio.h> /* FILE */
int foo(FILE *);

#endif /* HEADER GUARD */

if the code file doesn't need a header, don't add it

/* #include <stdio.h> */ /* removed because unneeded */
#include <stddef.h> /* NULL */
#include "header.h"
int main(void) {
  foo(NULL);
  return 0;
}
pmg
  • 106,608
  • 13
  • 126
  • 198
0

Why don't you #include stuff in the *.c file corresponding to the header?

HRÓÐÓLFR
  • 5,842
  • 5
  • 32
  • 35