|
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <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">
- <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>
|