You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
8.6 KiB
HTML
188 lines
8.6 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<!-- Created by GNU Texinfo 6.4, http://www.gnu.org/software/texinfo/ -->
|
|
<head>
|
|
<title>Guard Macros (The GNU C Preprocessor Internals)</title>
|
|
|
|
<meta name="description" content="Guard Macros (The GNU C Preprocessor Internals)">
|
|
<meta name="keywords" content="Guard Macros (The GNU C Preprocessor Internals)">
|
|
<meta name="resource-type" content="document">
|
|
<meta name="distribution" content="global">
|
|
<meta name="Generator" content="makeinfo">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<link href="index.html#Top" rel="start" title="Top">
|
|
<link href="Concept-Index.html#Concept-Index" rel="index" title="Concept Index">
|
|
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
|
|
<link href="index.html#Top" rel="up" title="Top">
|
|
<link href="Files.html#Files" rel="next" title="Files">
|
|
<link href="Line-Numbering.html#Line-Numbering" rel="prev" title="Line Numbering">
|
|
<style type="text/css">
|
|
<!--
|
|
a.summary-letter {text-decoration: none}
|
|
blockquote.indentedblock {margin-right: 0em}
|
|
blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
|
|
blockquote.smallquotation {font-size: smaller}
|
|
div.display {margin-left: 3.2em}
|
|
div.example {margin-left: 3.2em}
|
|
div.lisp {margin-left: 3.2em}
|
|
div.smalldisplay {margin-left: 3.2em}
|
|
div.smallexample {margin-left: 3.2em}
|
|
div.smalllisp {margin-left: 3.2em}
|
|
kbd {font-style: oblique}
|
|
pre.display {font-family: inherit}
|
|
pre.format {font-family: inherit}
|
|
pre.menu-comment {font-family: serif}
|
|
pre.menu-preformatted {font-family: serif}
|
|
pre.smalldisplay {font-family: inherit; font-size: smaller}
|
|
pre.smallexample {font-size: smaller}
|
|
pre.smallformat {font-family: inherit; font-size: smaller}
|
|
pre.smalllisp {font-size: smaller}
|
|
span.nolinebreak {white-space: nowrap}
|
|
span.roman {font-family: initial; font-weight: normal}
|
|
span.sansserif {font-family: sans-serif; font-weight: normal}
|
|
ul.no-bullet {list-style: none}
|
|
-->
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
<body lang="en">
|
|
<a name="Guard-Macros"></a>
|
|
<div class="header">
|
|
<p>
|
|
Next: <a href="Files.html#Files" accesskey="n" rel="next">Files</a>, Previous: <a href="Line-Numbering.html#Line-Numbering" accesskey="p" rel="prev">Line Numbering</a>, Up: <a href="index.html#Top" accesskey="u" rel="up">Top</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html#Concept-Index" title="Index" rel="index">Index</a>]</p>
|
|
</div>
|
|
<hr>
|
|
<a name="The-Multiple_002dInclude-Optimization"></a>
|
|
<h2 class="unnumbered">The Multiple-Include Optimization</h2>
|
|
<a name="index-guard-macros"></a>
|
|
<a name="index-controlling-macros"></a>
|
|
<a name="index-multiple_002dinclude-optimization"></a>
|
|
|
|
<p>Header files are often of the form
|
|
</p>
|
|
<div class="smallexample">
|
|
<pre class="smallexample">#ifndef FOO
|
|
#define FOO
|
|
…
|
|
#endif
|
|
</pre></div>
|
|
|
|
<p>to prevent the compiler from processing them more than once. The
|
|
preprocessor notices such header files, so that if the header file
|
|
appears in a subsequent <code>#include</code> directive and <code>FOO</code> is
|
|
defined, then it is ignored and it doesn’t preprocess or even re-open
|
|
the file a second time. This is referred to as the <em>multiple
|
|
include optimization</em>.
|
|
</p>
|
|
<p>Under what circumstances is such an optimization valid? If the file
|
|
were included a second time, it can only be optimized away if that
|
|
inclusion would result in no tokens to return, and no relevant
|
|
directives to process. Therefore the current implementation imposes
|
|
requirements and makes some allowances as follows:
|
|
</p>
|
|
<ol>
|
|
<li> There must be no tokens outside the controlling <code>#if</code>-<code>#endif</code>
|
|
pair, but whitespace and comments are permitted.
|
|
|
|
</li><li> There must be no directives outside the controlling directive pair, but
|
|
the <em>null directive</em> (a line containing nothing other than a single
|
|
‘<samp>#</samp>’ and possibly whitespace) is permitted.
|
|
|
|
</li><li> The opening directive must be of the form
|
|
|
|
<div class="smallexample">
|
|
<pre class="smallexample">#ifndef FOO
|
|
</pre></div>
|
|
|
|
<p>or
|
|
</p>
|
|
<div class="smallexample">
|
|
<pre class="smallexample">#if !defined FOO [equivalently, #if !defined(FOO)]
|
|
</pre></div>
|
|
|
|
</li><li> In the second form above, the tokens forming the <code>#if</code> expression
|
|
must have come directly from the source file—no macro expansion must
|
|
have been involved. This is because macro definitions can change, and
|
|
tracking whether or not a relevant change has been made is not worth the
|
|
implementation cost.
|
|
|
|
</li><li> There can be no <code>#else</code> or <code>#elif</code> directives at the outer
|
|
conditional block level, because they would probably contain something
|
|
of interest to a subsequent pass.
|
|
</li></ol>
|
|
|
|
<p>First, when pushing a new file on the buffer stack,
|
|
<code>_stack_include_file</code> sets the controlling macro <code>mi_cmacro</code> to
|
|
<code>NULL</code>, and sets <code>mi_valid</code> to <code>true</code>. This indicates
|
|
that the preprocessor has not yet encountered anything that would
|
|
invalidate the multiple-include optimization. As described in the next
|
|
few paragraphs, these two variables having these values effectively
|
|
indicates top-of-file.
|
|
</p>
|
|
<p>When about to return a token that is not part of a directive,
|
|
<code>_cpp_lex_token</code> sets <code>mi_valid</code> to <code>false</code>. This
|
|
enforces the constraint that tokens outside the controlling conditional
|
|
block invalidate the optimization.
|
|
</p>
|
|
<p>The <code>do_if</code>, when appropriate, and <code>do_ifndef</code> directive
|
|
handlers pass the controlling macro to the function
|
|
<code>push_conditional</code>. cpplib maintains a stack of nested conditional
|
|
blocks, and after processing every opening conditional this function
|
|
pushes an <code>if_stack</code> structure onto the stack. In this structure
|
|
it records the controlling macro for the block, provided there is one
|
|
and we’re at top-of-file (as described above). If an <code>#elif</code> or
|
|
<code>#else</code> directive is encountered, the controlling macro for that
|
|
block is cleared to <code>NULL</code>. Otherwise, it survives until the
|
|
<code>#endif</code> closing the block, upon which <code>do_endif</code> sets
|
|
<code>mi_valid</code> to true and stores the controlling macro in
|
|
<code>mi_cmacro</code>.
|
|
</p>
|
|
<p><code>_cpp_handle_directive</code> clears <code>mi_valid</code> when processing any
|
|
directive other than an opening conditional and the null directive.
|
|
With this, and requiring top-of-file to record a controlling macro, and
|
|
no <code>#else</code> or <code>#elif</code> for it to survive and be copied to
|
|
<code>mi_cmacro</code> by <code>do_endif</code>, we have enforced the absence of
|
|
directives outside the main conditional block for the optimization to be
|
|
on.
|
|
</p>
|
|
<p>Note that whilst we are inside the conditional block, <code>mi_valid</code> is
|
|
likely to be reset to <code>false</code>, but this does not matter since
|
|
the closing <code>#endif</code> restores it to <code>true</code> if appropriate.
|
|
</p>
|
|
<p>Finally, since <code>_cpp_lex_direct</code> pops the file off the buffer stack
|
|
at <code>EOF</code> without returning a token, if the <code>#endif</code> directive
|
|
was not followed by any tokens, <code>mi_valid</code> is <code>true</code> and
|
|
<code>_cpp_pop_file_buffer</code> remembers the controlling macro associated
|
|
with the file. Subsequent calls to <code>stack_include_file</code> result in
|
|
no buffer being pushed if the controlling macro is defined, effecting
|
|
the optimization.
|
|
</p>
|
|
<p>A quick word on how we handle the
|
|
</p>
|
|
<div class="smallexample">
|
|
<pre class="smallexample">#if !defined FOO
|
|
</pre></div>
|
|
|
|
<p>case. <code>_cpp_parse_expr</code> and <code>parse_defined</code> take steps to see
|
|
whether the three stages ‘<samp>!</samp>’, ‘<samp>defined-expression</samp>’ and
|
|
‘<samp>end-of-directive</samp>’ occur in order in a <code>#if</code> expression. If
|
|
so, they return the guard macro to <code>do_if</code> in the variable
|
|
<code>mi_ind_cmacro</code>, and otherwise set it to <code>NULL</code>.
|
|
<code>enter_macro_context</code> sets <code>mi_valid</code> to false, so if a macro
|
|
was expanded whilst parsing any part of the expression, then the
|
|
top-of-file test in <code>push_conditional</code> fails and the optimization
|
|
is turned off.
|
|
</p>
|
|
<hr>
|
|
<div class="header">
|
|
<p>
|
|
Next: <a href="Files.html#Files" accesskey="n" rel="next">Files</a>, Previous: <a href="Line-Numbering.html#Line-Numbering" accesskey="p" rel="prev">Line Numbering</a>, Up: <a href="index.html#Top" accesskey="u" rel="up">Top</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html#Concept-Index" title="Index" rel="index">Index</a>]</p>
|
|
</div>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|