[gnu.gcc] #pragma once

rms@AI.MIT.EDU (10/30/89)

If you want to make sure a file won't be reincluded, you should use
`#pragma once' together with suitable conditionals that would prevent
multiple processing of the header file's contents.  You can't rely on
`#pragma once'--it is just a time-saving hint.

If reinclusion would not cause any problem except for increased
compilation time, then you can use `#pragma once' by itself.

dld@F.GP.CS.CMU.EDU (David Detlefs) (10/31/89)

(This may be better placed in bug-gcc, but I don't normally read that.)

#pragma once has bothered me for a while.  I recently corresponded
with Ron Guillemette (sp? sorry) on the issue, and the discussion
caused me to clarify the reasons for my uneasiness.

1) Reading Harbison and Steele's description of Draft Proposed ANSI C,
p. 254, we see that "... implementations should ignore [pragma]
information they do not understand."  Thus, an ANSI C compiler may
validly include a .h file containing #pragma once multiple times.

2) rms recently posted that

>If you want to make sure a file won't be reincluded, you should use
>`#pragma once' together with suitable conditionals that would prevent
>multiple processing of the header file's contents.  You can't rely on
>`#pragma once'--it is just a time-saving hint.

What happens if a file contains a #pragma once but does not contain
conditionals suitable to prevent it's contents from being processed
multiple times?  It certainly seems to me that if the file is not
processed on inclusions after the first, then the (Draft Proposed)
ANSI standard has been violated.  A C implementation that uses the
"#pragma" once in this way produces semantically different results
than one that ignores it; in effect, this interpretation makes it not
a "pragma," in the sense that this term is usually used (non-semantics
affecting.)

3) There is no way that I can see to make "#pragma once" safe; that
is, a pragma in the sense defined in the ANSI C proposal.  The only
way to do so is to have cpp do enough analysis to determine whether
the #pragma once file contains "suitable conditionals" (to use rms's
term) to prevent subsequent reinclusion.  Even then, an including file
might #undef the variable whose definedness prevents processing.  If
this is not recognized, semantics are not preserved.  The best idea I
have ever heard along these lines was recently reiterated by John
Nagle on comp.lang.c++ (I don't know if it's original with him):

have cpp recognize files of the common form

<foo.h>:
<comments/whitespace>
#ifndef <foo_defined>
<body>
#endif
<comments/whitespace>

maintain a table associating filenames <foo.h> with variables
<foo_defined>.

whenever we encounter 

#include "<foo.h>"

check to see if <foo.h> is in the table, and if so, if the
corresponding <foo_defined> is currently defined.  If so, we may
safely pass over the #include.

Note that this gets all the performance savings of #pragma once,
while maintaining ANSI semantics.  If you read rms's post again,
you'll note that you are supposed to use *both* #pragma once and the
#ifndef style.  This proposal obviates the need for the #pragma once.

This is not my idea, but I really think it's a good one.  Hope I've
convinced somebody.

--
Dave Detlefs			Any correlation between my employer's opinion
Carnegie-Mellon CS		and my own is statistical rather than causal,
dld@cs.cmu.edu			except in those cases where I have helped to
				form my employer's opinion.  (Null disclaimer.)

gjditchfield@watmsg.waterloo.edu (Glen Ditchfield) (10/31/89)

In article <DLD.89Oct30145205@F.GP.CS.CMU.EDU> dld@F.GP.CS.CMU.EDU (David Detlefs) writes:

> ... The best idea I have ever heard along these lines was recently
>reiterated by John Nagle on comp.lang.c++ (I don't know if it's original
>with him):
>
>have cpp recognize files of the common form
>
><foo.h>:
><comments/whitespace>
>#ifndef <foo_defined>
><body>
>#endif
><comments/whitespace>
>
> ... Note that this gets all the performance savings of #pragma once,
>while maintaining ANSI semantics.  If you read rms's post again,
>you'll note that you are supposed to use *both* #pragma once and the
>#ifndef style.  This proposal obviates the need for the #pragma once.

Some other, weaker points:
- For better or worse, the "Nagle" system would allow programmers to force
  reinclusion by undefining <foo_defined>.  I don't how to override
  "#pragma once"; I'll bet there is a way, and I'll bet that it would vary
  among compilers that implement "#pragma once".
- I often pass my C++ code through g++ and through AT&T's system.  The
  obsolescent cpp used here with cfront complains that it doesn't know what
  to do with "#pragma", so I've gotten out of the habit of using "#pragma
  once".  (I agree that the proper thing to do is to change preprocessors,
  but ...)
- Other systems have already taken other approaches.  If I remember
  correctly, one C compiler had "#pragma idempotent", while Objective C's
  preprocessor tackled the problem from the other end with "#import".
  "#ifndef/#endif" works for all of them.  I think it's easier to provide
  an optimization for this idiom than to get all implementors to agree to a
  single extension.

mark@jhereg.Minnetech.MN.ORG (Mark H. Colburn) (11/08/89)

In article <522@loft386.UUCP> dpi@loft386.UUCP (Doug Ingraham) writes:
>#ifdef __GNUC__
>#pragma once
>#endif
>#ifndef __STRING_H
>#define __STRING_H
>
>< The required string.h information here >
>
>#endif	/* __STRING_H */

Ok, I'll finally admit it, I am a little confused as to why there is such a
construct as the #pragma once.

If you want to avoid including the file twice, why not use the "standard"
method of enclosing the entire thing in "#ifdefs" as shown above:

	#ifndef __MYHEADER_H
	#define __MYHEADER_H

		<header stuff>

	#endif /* __MYHEADER_H */

This works on any machine with a preprocessor, is portable across any
compiler, does not use a #pragma, and is in widespread use today.  Also,
from the discussion which has ensued here about #pragma once, I assume that
it does not always work correctly.

Can someone enlighten me here?

-- 
Mark H. Colburn                       mark@Minnetech.MN.ORG
Open Systems Architects, Inc.

pardo@cs.washington.edu (David Keppel) (11/10/89)

mark@jhereg.UUCP (Mark H. Colburn) writes:
>[Why `#pragma once'?  What's wrong with
>	#ifndef TOKEN
>	#define TOKEN
>	    ...
>	#endif TOKEN
>]

It's slow, particularly if you have nested includes.  The problem is
that with `#ifndef TOKEN ... #endif' the entire file must be scanned
each place that the #include directive appears, even if the #include
is redundent.  With `#pragma once', the compiler can avoid redundent
rescans.

An portable alternative convention avoids the overhead of rescanning
but requires more programmer work and allows more typos:

	#ifndef TOKEN
	#   include TOKEN
	#endif

I ususually combine the latter with lines in the .h that look like

	#ifdef TOKEN
	{ TOKEN multiply defined! }
	#else
	#define TOKEN
	    ...
	#endif

Alternatively, you can just do `#ifndef TOKEN ... #endif' and let
the compile go slow if you (somebody) does some repeated includes.

To summarize: `#pragma once' provides a facility that is available by
other mechanisms.  The advantage of `#pragma once' is that information
about the use of the .h is not spread through both the .h and the .c.
Using `#pragma once' does not compromise portability if the `#prgama
once' is ifdeffed.

#ifdef __STDC__
    #pragma once
#endif

Note that the octothorpe ('#') should be indented to keep older
compilers from gagging.

	;-D on  ( #pragma once upon a time )  Pardo
-- 
		    pardo@cs.washington.edu
    {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo

ccplumb@rose.waterloo.edu (Colin Plumb) (11/10/89)

In article <305@jhereg.Minnetech.MN.ORG> mark@jhereg.UUCP (Mark H. Colburn) writes:
> Ok, I'll finally admit it, I am a little confused as to why there is such a
> construct as the #pragma once.
>
> If you want to avoid including the file twice, why not use the "standard"
> method of enclosing the entire thing in "#ifdefs" as shown above:
>
> This works on any machine with a preprocessor, is portable across any
> compiler, does not use a #pragma, and is in widespread use today.  Also,
> from the discussion which has ensued here about #pragma once, I assume that
> it does not always work correctly.

No, it works fine, it's just inefficient.  The preprocessor has to open the
file, parse it, including such pathological situations as

printf("\
#endif /* \
*/");

and all to include a few carriage returns in the source file.  #pragma once
lets the prorpocessor just skip over future #includes of the same file, not
even opening the file for examination.  With ANSI type-checking, header files
are bigger than ever, and reducing time spent parsing them becomes more
important.
-- 
	-Colin