I know that #inclusion is often described as a text copy-pasting preprocessor directive. Now if a header is #include guarded, or #pragma onced, then how'd we describe what is actually happening past the first translation unit to #include said header?
-
1When starting working with a new translation using, it drops the old guards and starts the process clean. – Ted Lyngmo Dec 13 '21 at 14:06
-
Consider: I compile one "unit" on my machine, you compile one "unit" on your machine, and we link them together on a third machine. How could any of our compilations affect the outcome on the other? – molbdnilo Dec 13 '21 at 14:27
-
The same description works as well for multiple translation units as for a single one. What is the issue that you see? – JaMiT Dec 13 '21 at 14:30
-
@JaMiT If the header is copied multiple times, then we will have multiple copies of every identifier declared or defined in the header. Doesn't that make a bloated binary? Isn't there name matching somewhere so that a function fully defined in a header won't end up having multiple copies with multiple addresses in the code area of the RAM while execution? – Physician Dec 13 '21 at 14:46
-
You may have the declaration of a certain identifier in all the TU:s that needs it, but the actual definition should only be in one TU. – Ted Lyngmo Dec 13 '21 at 15:03
-
@Physician *"Doesn't that make a bloated binary?"* -- well, yes, it can. That is fully consistent with "often described as a text copy-pasting preprocessor directive", and it is one of the reasons that one potential form of link-time optimization (well after preprocessing) is checking for multiple copies of the same function and eliminating the copies that are allowed to be eliminated. This just reinforces the common description of "text copy-pasting". You still have not provided a reason to think that this description is inaccurate. – JaMiT Dec 13 '21 at 15:03
-
@JaMiT Yeah thanks for your help, I just thought that repeating declarations and definitions is not allowed at all inside the executable program. That's why I thought #prama once won't allow that to happen. – Physician Dec 13 '21 at 15:17
-
@TedLyngmo yeah I know that well. Thanks for you comment. – Physician Dec 13 '21 at 15:18
1 Answers
There is no "first" translation unit. All translation units are conceptually translated in parallel (of course, in practice you might end up compiling them one at a time, but it doesn't matter).
Each translation unit begins with a blank slate. Technically that isn't quite true because you can add #define
s at the command line and there are some predefined macros as well, but anyway, no translation unit will have a "memory" of #define
s that were executed in any other translation unit. Thus, a header may be #include
d multiple times despite the guards. It is just that it won't be #include
d multiple times into a single translation unit.
This means that you must still take care to avoid multiple definitions: for example, if your header contains a global variable then you must ensure it is const
(so it will have internal linkage) or explicitly declare it inline
(to collapse all definitions into one) or extern
(to suppress definition in the header so you can place the definition into a single translation unit).
Despite the fact that include guards don't prevent multiple definitions across multiple translation units, they do prevent multiple definitions within a single translation unit, and this is important because even though some entities may be defined multiple times in a program, it's still not allowed for multiple definitions to appear in the same translation unit. For example, if you have an inline
global variable in a header, then multiple translation units can include that header and the definitions will all be collapsed into a single definition at link time, but you will get a compilation error if any one translation unit defines that variable multiple times. Therefore, such a header must have an include guard.

- 111,498
- 10
- 176
- 312