5

In c lets say we have 2 files

1.h

#include<2.h>

blah blah

and we have 2.h

#include<1.h>

code

How is this resolved??

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
Laz
  • 6,036
  • 10
  • 41
  • 54
  • 6
    Basically, it isn't resolved. The compiler tries to compile a .cpp file, and every time it encounters an `#include`, it inserts the included file, and starts parsing that. If you do have a circular include (and no include guards), you get an infinitely large sequence of code (or rather, the compiler will give up sooner or later and report an error) – jalf Jun 27 '10 at 11:30
  • You can model it in real life: Take bag 1 and bag 2. Store bag 2 in bag 1. Then store bag 1 in bag 2. Once you have made sense of that, consider how to implement it in source code. Or if you _can't_ make sense of it, then maybe _don't_ implement something similarly senseless in source code. Yes I'm sure someone can scratch their head a lot and come up with a scenario where mutual inclusion might sound reasonable in theory. But that still doesn't mean that we have to design the program accordingly. Most often we'd rather use a third higher layer item that handles communication between the two. – Lundin Oct 11 '22 at 12:46
  • I tried it and got `error: #include nested too deeply` under two different compilers (after about 200 levels of nesting). – Steve Summit Oct 11 '22 at 13:08

4 Answers4

17

Typically you protect your include file with an ifndef/define that corresponds to the file name. This doesn't prevent the file from being included again, but it does prevent the contents (inside the ifndef) from being used and triggering the recursive includes again.

 #ifndef HEADER_1_h
 #define HEADER_1_h

 #include "2.h"

 /// rest of 1.h

 #endif

 #ifndef HEADER_2_h
 #define HEADER_2_h

 #include "1.h"

 //  rest of 2.h

 #endif
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • so basically each one gets included only once and not infinite number of times! Thanks so much! So if it is defined the way I have the compiler will give an error? – Laz Jun 27 '10 at 11:19
  • 1
    @Ram - I would imagine you'd get lots of errors as things get redefined. – tvanfosson Jun 27 '10 at 11:28
  • 3
    Although you shouldn't begin the include guard names with `__`. Names like that are reserved. – Mike Seymour Jun 27 '10 at 11:56
  • @Mike - I don't think that they are actually reserved. I think it's more of a convention, but it is a good idea to avoid them in case you have a header file name that happens to conflict with a library/system header file. I'll update. – tvanfosson Jun 27 '10 at 12:04
  • 1
    @tvanfosson: They are reserved. That is the precise word used in the standard. It says that these names are "reserved for the implementation". So while you could argue that "it's ok to use them as long as it doesn't cause a conflict", the problem is that any implementation could, at any time, decide to use the name, and then the conflict is *your* fault and your problem. :) Anything *containing* a double underscore, anything beginning with underscore followed by upper-case character, and anything beginning with underscore at namespace scope, is reserved for use by the implementation. – jalf Jun 27 '10 at 12:10
  • 1
    @tvanfosson No, they're actually reserved, at least in C++. Std. 17.4.3.1.2: "Certain sets of names and function signatures are always reserved to the implementation: — Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use." – Tyler McHenry Jun 27 '10 at 12:12
  • 1
    They're reserved in C too; C99, 7.1.3: "All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use." – Mike Seymour Jun 27 '10 at 12:14
  • I stand corrected, though, to be fair, when I was programming in C (late '80s/early '90s) that wasn't the case. – tvanfosson Jun 27 '10 at 12:43
  • also gcc at least will recognize this pattern and not even bother to read the file a second time. – Spudd86 Jun 27 '10 at 17:30
9

Okay, for the sake of completeness I'll begin by quoting tvanfosson's answer:

You should use include guards:

// header1.hpp
#ifndef MYPROJECT_HEADER1_HPP_INCLUDED
#define MYPROJECT_HEADER1_HPP_INCLUDED

/// Put your stuff here

#endif // MYPROJECT_HEADER1_HPP_INCLUDED

However include guards are not meant to solve circular dependencies issues, they are meant to prevent multiple inclusions, which is quite different.

          base.h
        /        \
    header1.h  header2.h
        \        /
         class.cpp

In this case (quite common), you only want base.h to be included once, and that's what include guards give you.

So this will effectively prevents the double inclusion... but you won't be able to compile!!

The problem can be illustrated by trying to reason as the compiler does:

  • Include "header1.hpp" > this defines the include guard
  • Include "header2.hpp
  • Try to include "header1.hpp" but doesn't because the include guard is already defined
  • Cannot correctly parse "header2.hpp" because the types coming from "header1.hpp" have not been defined yet (since it was skipped)
  • Back to "header1.hpp", and the types from "header2.hpp" are still missing since they could not be compiled, and thus it fails here too

In the end, you'll left with a big pile of error messages, but at least the compiler does not crash.

The solution is to somehow remove the need for this circular dependency.

  • Use forward declarations if possible
  • Split "header1.h" into 2 parts: the part independent from header2 and the other, you should only need to include the former in header2

And THIS will solve the circular dependency (manually) there is no magic going on in the compiler that will do it for you.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • You are wrong. When header1.hpp is included for the first time, it is *not* skipped since the guard was not yet defined. Thus, the types coming from header1.hpp **have been defined** and there is no problem to parse header2.hpp. (But, of course, circular includes should be avoided.) – PauliL Jun 27 '10 at 14:50
  • @PauliL: no, you're wrong really :) "2.h" is included BEFORE the types are defined in "1.h", so after both headers are parsed, the types of "1.h" that do no depend on "2.h" will probably be defined, but that's all. – Matthieu M. Jun 28 '10 at 06:24
  • OK, I think I understand what you mean now. It is not the circular *include* that causes problems but the *definitions* that depend on each other. If 1.h requires that 2.h is included first, and 2.h requires that 1.h is included first, that can not work, since both can not be the first. The compiler will then give "not defined" error, so the programmer knows to fix it. – PauliL Jun 28 '10 at 11:14
  • Yes. Except that the message from the compiler is likely to be cryptic (depends on the compiler) and it's not immediately obvious that the problem comes from a circular dependency. Fortunately there are external tools to spot this kind of situations :) – Matthieu M. Jun 28 '10 at 11:20
  • I am tying to create this compile error. But I can't get the compile to break. What am I not doing wrong here: I have "base.h" defining class "Point". I have "random.h" defining class "RandomPoint" that extends Point. I have "color.h" defining "ColorPoint" that extends Point. Both of these headers include "Point.h". All headers have include guards. My "main.cpp" includes "RandomPoint.h" and "ColorPoint.h". It compiles correctly. How can I make it break as suggested here after "but you won't be able to compile"? – ChrisCantrell Jan 09 '18 at 19:11
  • 1
    @ChrisCantrell: include `RandomPoint.h` and declare a `RandomPoint toRandomPoint(ColorPoint)` function in `ColorPoint.h`. It should still work. Then include `ColorPoint.h` and declare a `ColorPoint toColorPoint(RandomPoint)` in `RandomPoint.h`. BOOM. You need a circular dependency, ie a header A depending on a header B which depends on A to trigger the issue (and by depend, I mean include *and use stuff from*). – Matthieu M. Jan 09 '18 at 19:42
0

Since you posted your question under the c++ tag as well as c, then I am assuming you are using c++. In c++, you can also use the #pragma once compiler directive:

1.h:

#pragma once
#include "2.h"
/// rest of 1.h 

2.h:

#pragma once
#include "1.h"
/// rest of 2.h 

The result is the same. But there are some notes:

  1. pragma once will usually compile a little faster since it is a higher level mechanism and doesn't happen at preprocessing like include guards

  2. Some compilers have known bugs "dealing" with #pragma once. Though most if not all modern compilers will handle it correctly. For a detailed list see Wikipedia

Edit: I think the directive is also supported in c compilers but have never tried it, and besides, in most c programs I've seen, include guards are the standard (maybe due to compiler limitations handling the pragma once directive?)

eladidan
  • 2,634
  • 2
  • 26
  • 39
  • 1
    `#pragma once` isn't restricted to C++, neither standard says something about the preprocessor. So it's not about "it is supported in some C compilers", it really doesn't matter which language it is :). – Pieter Jun 27 '10 at 12:11
  • 6
    No, in C++ there is no such thing as `#pragma once`. That is an extension some vendors choose to implement. It is not part of C++. (And the compilers that do support it typically also support it in C). By the way, the speed thing is a myth. Today, compilers implement the same optimizations with conventional include guards. – jalf Jun 27 '10 at 12:12
  • jalf that last remark can't be true. Consider the needed elements and verifications on both systems and it becomes obvious that #pragma once is simpler and faster. – Panic Jun 27 '10 at 12:19
  • @Panic: No, the pragma is faster **if the compiler does not optimize the include guards". Which compilers typically do. Basically, if the compiler opens a file, sees that it contains an include guard, it treats it afterwards in the compilation *as if* it'd been included with a #pragma once. The end result is that it is just as fast. – jalf Jun 27 '10 at 12:22
  • okay, I should have noted its not c/c++ standard, but it is widely supported and well received. And yes, many compilers do offer optimizations for include guards which render the difference dismissibal (though not none existent). Main point is, it's a valid solution and I don't think it deserves a -1, but the points you make are valid – eladidan Jun 27 '10 at 12:25
  • ... but it is worth noting that compilers with include guard optimizations can have trouble preprocessing headers. Sutter, in C++ Coding Standards, suggests keeping all comments inside of include guards (not outside) and points out some of the limitations with vendors. That book is a little dated, however, and may not be as applicable today, but I do wish that #pragma once became a bit more widely accepted as it would be simpler. – stinky472 Jun 27 '10 at 12:37
  • 3
    I myself wish we could get away without using either include guards or `#pragma once` like modern languages support. – Matthieu M. Jun 27 '10 at 12:42
  • @Mat: I agree, C++ desperately needs a module system. – fredoverflow Jun 27 '10 at 12:56
  • @stinky: true, if you want to be sure that optimization takes place, the include guard should encompass the entire file. Nothing before the `#ifndef` and nothing after the `#endif`. And @Matthieu: YES! A module system has been proposed which would potentially eliminate all this #include mess. It didn't make the cut for C++0x, but afaik, the committee didn't reject it. They just postponed it for a later revision. Apparently, it's something they want too. So there's hope still :) – jalf Jun 27 '10 at 13:20
  • @eladidan: your post is full of incorrect information: It says that `#pramga once` is valid C++, it says that it speeds up compiles, and that it's is more likely to be supported in C++ than C compilers (if a compiler supports it, it'll support it in both languages. The extension works equally well in both languages, and it's equally proprietary and nonstandard in both languages). I'd say "the answer is incorrect" is a pretty good justification for a -1. ;) – jalf Jun 27 '10 at 13:22
  • @jalf: No, my answer says that #pragma once will USUALLY speed up compiles. And vs. an unoptimized compiler (there are many!) it will. I also confess that I am unsure of whether it will compile in C compilers and so I add an exlaimer that I haven't tried it on C compilers, thus not giving complete information but also not giving false information. And finally, no where in the answer do I claim for it to be part of c++ standard as I'm well aware its not. It is however, a common solution employed by many programmers, which suffers from no serious flaws (except in some specific compilers) – eladidan Jun 27 '10 at 14:50
  • ... which is another note that I don't forget to mention in my answer. – eladidan Jun 27 '10 at 14:52
  • @eladidan: GCC and Visual Studio are by far the most popular. They both implement this optimization. So I can't say I agree with your "usually" statement. Anyway, my point is very simple. As it is now, your answer is misleading, and its score should reflect that. I didn't downvote it to punish you, but simply because I don't want some newbie coming into this thread, seeing that your answer has gotten multiple upvotes, and assuming it must be true. – jalf Jun 27 '10 at 16:00
  • SO isn't about some kind of rep contest, it is about providing the best possible answers. And part of that process is to ensure that a correct answer gets more upvotes than an incorrect one. And I'm not sure how to interpret your comment. You never claimed that this pragma was part of C++? And yet the first paragraph of your answer says "In c++, you can also use the #pragma once compiler directive:" There's no need to get defensive about it. I've gotten my fair share of downvotes when I wrote something that was unclear, misleading or incorrect. – jalf Jun 27 '10 at 16:02
  • oh nm... I'm not trying to win a popularity contest, I just think that the #pragma once solution is valid for this problem. I don't mind that I get downvoted, I mind it when an answer I deem note-worthy is marked 0. And I don't see how I cannot get defensive... I'm defending what I think to be a valid solution to the original question. Maybe I should have phrased it better, but it is my experience that the #pragma once is more accepted in c++ than in c, and that's why I affirmed it's validness with c++. Anyway, no need to quible. I humbly accept your critism – eladidan Jun 27 '10 at 16:16
  • Isn't `#pragma once` a VC++ only think, I don't think gcc supports it, and gcc DOES optimize the #define guard case, and since it WILL turn correct code into incorrect code on compilers that don't do `#pragma once` it's a good idea to always have the `#ifdef` version (and if you care that much doing BOTH is always an option since compilers are required to ignore `#pragma`s they don't recognize) – Spudd86 Jun 27 '10 at 17:34
0

Circular inclusions must be eliminated, not "resolved" with include guards (as the accepted answer suggests). Consider this:

1.h:

#ifndef HEADER_1_h
#define HEADER_1_h
#include "2.h"

#define A 1
#define B 2

#endif // HEADER_1_h

2.h:

#ifndef HEADER_2_h
#define HEADER_2_h
#include "1.h"

#if (A == B)
#error Impossible
#endif

#endif // HEADER_2_h

main.c:

#include "1.h"

This will throw the "Impossible" error at compile time, because "2.h" fails to include "1.h" due to include guards, and both A and B become 0. In practice, this leads to hard to track errors which appear and disappear depending on the order in which header files are included.

The right solution here would be to move A and B to "common.h" which then could be included in both "1.h" and "2.h".

Dmitry Grigoryev
  • 3,156
  • 1
  • 25
  • 53