Re: Best Practices: #include

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Joseph M. Newcomer (newcomer_at_flounder.com)
Date: 05/19/04


Date: Wed, 19 May 2004 18:44:28 -0400

I don't follow the logic here.

#pragma once

says that the file will be included only once in each compilation unit.

It does not require that the header file be included in every file; in fact, that so
rarely makes sense that the sentence is completely disconnected from any discussion I can
see going on.

If the header file has been included once, in a given compilation, any subsequent
inclusion would be redundant, so it doesn't need to be included. There is no way to make
the file not be included by #pragma once until it has been included one time, so the
phrase "any additional calls to the header will fail - even if it's unknown in the file"
is completely content-free. The correct description is "any additional #include of the
header in this compilation will be ignored, because the header has already been
processed", that is, the same effect as the include-guards, without the file-open and
parsing overhead!

The statement "On the other hand, the #ifdef/#define/#endif wrapper for header files
allows the header to be read where it's contents are unknown" is also content-free. Note
that the #pragma once creates an entry in the compiler so that a #include is not even
processed! So there is no issue about whether the contents are known or not; it is
completely irrelevant.

There would be no reason to include the header in every file; each compilation is
completely independent so whatever is included in one compilation has absolutely no effect
on what is included in another compilation. The phrase "translation unit" (§5.1.1.1) is
important here.

>From the standard:

"A source file together with all the headers and source files included via the
preprocessing directing #include, less any source lines skipped by any of the conditional
inclusion preprocessing directives, is called a translation unit"

So #pragma once can have a scope of at most a single translation unit.

The two methods, the #pragma once and the include guards, are completely identical, in
that the contents of the file are not processed. In the case of #pragma once, the file is
not opened, and is not scanned, because the compiler knows this has happened already. Did
you think it meant that the file was opened, and the #pragma once had to be read again?
Wrong. The second and subsequent #include statements have the same semantic value as
comments!

So I think you really misunderstand what this does and how it works.

The #pragma was introduced in version 11.00 of the compiler. Older compilers (I'm not sure
which one) would have issued a warning about an unknown #pragma.
                                        joe

On Wed, 19 May 2004 14:52:43 GMT, Balboos <balboos@masonicbrother.com.No.Spam> wrote:

>According to my MSDN help file:
>#pragma once
>
>Specifies that the file, in which the pragma resides, will be included
>(opened) only once by the compiler in a build. A common use for this
>pragma is the following:
>
>This, then, presupposes that some one header will be #include'd in every
>file. VC++ may do this for you, but it's not a guaranteed situation.
>So, using once, if the above description is correct, means that any
>additional calls to the header will fail - even if it's unknown in the
>file. On the other hand, the #ifdef/#define/#endif wrapper for header
>files allows the header to be read where it's contents are unknown.
>
>BUT, put that aside:
>
>When VS6 creates a header, it uses both methods, but the pragma is
>wrapped as follows:
> #if _MSC_VER > 1000
> #pragma once
> #endif // _MSC_VER > 1000
>
>This gives an implication that the pragma isn't (or wasn't) always
>handled the same way. As an 'old timer' with MFC, perhaps you can
>enlighten on this (the pragma interpretation changed?)
>
>Balboos
>
>
>
>
>
>
>Joseph M. Newcomer wrote:
>> In the case of the library file, then you should include the library files in your header.
>> If they have already been included in stdafx.h, no harm is done; if they weren't, your
>> code compiles anyway.
>>
>> Not sure why you think #ifdef/#define/#endif is better than #pragma once--that solution
>> requires that the compiler open and scan the file, only to have nothing happen the second
>> time. #pragma once creates an entry in the compiler tables such that each #incude is
>> checked against this internal table, and if the name is found, the file is not even
>> opened. While generally the time doesn't matter, it will impact you for large header files
>> which are included multiple times. Better still, use both. That way you get both optimum
>> performance and maximum portability. I have no idea what the phrase "allows visibility
>> wherever not yet visible" could possibly mean in the context of #pragma once. Or, for that
>> matter, any other context.
>> joe
>> On Mon, 17 May 2004 17:26:00 GMT, Balboos <balboos@masonicbrother.com.No.Spam> wrote:
>>
>>
>>>I've made some .lib files - in these, it is important that the headers
>>>be in (another) header file - much as you suggest.
>>>
>>>But,
>>>
>>>I'm not sure "at the highest possible compile location" is a good idea -
>>>if one wants to be able to easily reuse the code. Putting the <vector>
>>>header in stdafx, for example, means that in addition to including the
>>>header for your (class/library/etc), you need to explicitly add its
>>>dependencies (again to stdafx?). Including it in the lower level header
>>>will automatically insert it wherever it's needed (when the add-in's
>>>header is called). Moreover - if it's a lib type file, it probably
>>>doesn't share the stdafx.h of you app - or may not even have one at all.
>>>
>>>I avoid the multiple inclusions with the #ifdef / #define /#endif
>>>method, rather than #pragma once. This allows visibility wherever not
>>>yet visible.
>>>
>>>Balboos
>>>
>>>James Ryan wrote:
>>>
>>>
>>>>If I am writing a dll and providing a header I include all .h dependencies
>>>>in that header. Otherwise it may not compile for my user unless they have
>>>>included these files elsewhere. This should not be a problem if all
>>>>headers are protected from multiple inclusions (ie #pragma once)
>>>>
>>>>If I am writing an executable I usually include headers at the highest
>>>>possible compile location. Most system headers like <vector> and <string> I
>>>>always include in stdafx.h. If a header file requires another header file
>>>>to compile successfully I still try to include this file in the required
>>>>header. Header files are included in .cpp files only when there is a
>>>>explicit dependancy in that file. Of course if you start creating circular
>>>>dependancies then all bets are off.
>>>>
>>>>Otherwise, write in C# and all these issues go away ;)
>>>>
>>>>James
>>
>>
>> Joseph M. Newcomer [MVP]
>> email: newcomer@flounder.com
>> Web: http://www.flounder.com
>> MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm



Relevant Pages

  • Re: sendmail compile errors on TNS/E - NS2000
    ... #pragma RUNNABLE, WIDE, XMEM, SYMBOLS, INSPECT, ENV COMMON, ... SAVEABEND ... only supported on the command line ... warnings were issued during compilation. ...
    (comp.sys.tandem)
  • Proposal: pragma Assumption
    ... But if an 'assert' is valid during the whole ... So the proposal whould be adding to the next Ada revision two new ... it is a compilation error to find any pragma Assumption in the sources ... anyway it is a documentation pragma ...
    (comp.lang.ada)
  • sendmail compile errors on TNS/E - NS2000
    ... #pragma RUNNABLE, WIDE, XMEM, SYMBOLS, INSPECT, ENV COMMON, ... SAVEABEND ... only supported on the command line ... warnings were issued during compilation. ...
    (comp.sys.tandem)
  • Re: Best Practices: #include
    ... >>Specifies that the file, in which the pragma resides, will be included ... > says that the file will be included only once in each compilation unit. ... > It does not require that the header file be included in every file; ...
    (microsoft.public.vc.mfc)
  • Re: Porting from VC6, Class Wizard Comments
    ... Either way #ifdef sequence, or #pragma once, it should be implied, the ... beyond (I never installed VS5 anywhere because it had so many other ... THe only place you currently need include guards is if you have a header ... I have always needed the #ifdef my header files! ...
    (microsoft.public.vc.mfc)