📄 cpp.texinfo
字号:
@example#define x (4 + y)#define y (2 * x)@end example@noindent@samp{x} would expand into @samp{(4 + (2 * x))}. Clear?But suppose @samp{y} is used elsewhere, not from the definition of @samp{x}.Then the use of @samp{x} in the expansion of @samp{y} is not a self-referencebecause @samp{x} is not ``in progress''. So it does expand. However,the expansion of @samp{x} contains a reference to @samp{y}, and thatis an indirect self-reference now because @samp{y} is ``in progress''.The result is that @samp{y} expands to @samp{(2 * (4 + y))}.It is not clear that this behavior would ever be useful, but it is specifiedby the ANSI C standard, so you need to understand it.@node Argument Prescan, Cascaded Macros, Self-Reference, Macro Pitfalls@subsubsection Separate Expansion of Macro ArgumentsWe have explained that the expansion of a macro, including the substitutedactual arguments, is scanned over again for macro calls to be expanded.What really happens is more subtle: first each actual argument text is scannedseparately for macro calls. Then the results of this are substituted intothe macro body to produce the macro expansion, and the macro expansionis scanned again for macros to expand.The result is that the actual arguments are scanned @emph{twice} to expandmacro calls in them.Most of the time, this has no effect. If the actual argument containedany macro calls, they are expanded during the first scan. The resulttherefore contains no macro calls, so the second scan does not change it.If the actual argument were substituted as given, with no prescan,the single remaining scan would find the same macro calls and producethe same results.You might expect the double scan to change the results when aself-referential macro is used in an actual argument of another macro(@pxref{Self-Reference}): the self-referential macro would be expanded oncein the first scan, and a second time in the second scan. But this is notwhat happens. The self-references that do not expand in the first scan aremarked so that they will not expand in the second scan either.The prescan is not done when an argument is stringified or concatenated.Thus,@example#define str(s) #s#define foo 4str (foo)@end example@noindentexpands to @samp{"foo"}. Once more, prescan has been prevented fromhaving any noticeable effect.More precisely, stringification and concatenation use the argument aswritten, in un-prescanned form. The same actual argument would be used inprescanned form if it is substituted elsewhere without stringification orconcatenation.@example#define str(s) #s lose(s)#define foo 4str (foo)@end exampleexpands to @samp{"foo" lose(4)}.You might now ask, ``Why mention the prescan, if it makes no difference?And why not skip it and make the preprocessor faster?'' The answer isthat the prescan does make a difference in three special cases:@itemize @bullet@itemNested calls to a macro.@itemMacros that call other macros that stringify or concatenate.@itemMacros whose expansions contain unshielded commas.@end itemizeWe say that @dfn{nested} calls to a macro occur when a macro's actualargument contains a call to that very macro. For example, if @samp{f}is a macro that expects one argument, @samp{f (f (1))} is a nestedpair of calls to @samp{f}. The desired expansion is made byexpanding @samp{f (1)} and substituting that into the definition of@samp{f}. The prescan causes the expected result to happen.Without the prescan, @samp{f (1)} itself would be substituted asan actual argument, and the inner use of @samp{f} would appearduring the main scan as an indirect self-reference and would notbe expanded. Here, the prescan cancels an undesirable side effect(in the medical, not computational, sense of the term) of the specialrule for self-referential macros.But prescan causes trouble in certain other cases of nested macro calls.Here is an example:@example#define foo a,b#define bar(x) lose(x)#define lose(x) (1 + (x))bar(foo)@end example@noindentWe would like @samp{bar(foo)} to turn into @samp{(1 + (foo))}, whichwould then turn into @samp{(1 + (a,b))}. But instead, @samp{bar(foo)}expands into @samp{lose(a,b)}, and you get an error because @code{lose}requires a single argument. In this case, the problem is easily solvedby the same parentheses that ought to be used to prevent misnesting ofarithmetic operations:@example#define foo (a,b)#define bar(x) lose((x))@end exampleThe problem is more serious when the operands of the macro are notexpressions; for example, when they are statements. Then parenthesesare unacceptable because they would make for invalid C code:@example#define foo @{ int a, b; @dots{} @}@end example@noindentIn GNU C you can shield the commas using the @samp{(@{@dots{}@})}construct which turns a compound statement into an expression:@example#define foo (@{ int a, b; @dots{} @})@end exampleOr you can rewrite the macro definition to avoid such commas:@example#define foo @{ int a; int b; @dots{} @}@end exampleThere is also one case where prescan is useful. It is possibleto use prescan to expand an argument and then stringify it---if you usetwo levels of macros. Let's add a new macro @samp{xstr} to theexample shown above:@example#define xstr(s) str(s)#define str(s) #s#define foo 4xstr (foo)@end exampleThis expands into @samp{"4"}, not @samp{"foo"}. The reason for thedifference is that the argument of @samp{xstr} is expanded at prescan(because @samp{xstr} does not specify stringification or concatenation ofthe argument). The result of prescan then forms the actual argument for@samp{str}. @samp{str} uses its argument without prescan because itperforms stringification; but it cannot prevent or undo the prescanningalready done by @samp{xstr}.@node Cascaded Macros,, Argument Prescan, Macro Pitfalls@subsubsection Cascaded Use of Macros@cindex cascaded macros@cindex macro body uses macroA @dfn{cascade} of macros is when one macro's body contains a referenceto another macro. This is very common practice. For example,@example#define BUFSIZE 1020#define TABLESIZE BUFSIZE@end exampleThis is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}.The @samp{#define} for @samp{TABLESIZE} uses exactly the body youspecify---in this case, @samp{BUFSIZE}---and does not check to see whetherit too is the name of a macro.It's only when you @emph{use} @samp{TABLESIZE} that the result of its expansionis checked for more macro names.This makes a difference if you change the definition of @samp{BUFSIZE}at some point in the source file. @samp{TABLESIZE}, defined as shown,will always expand using the definition of @samp{BUFSIZE} that iscurrently in effect:@example#define BUFSIZE 1020#define TABLESIZE BUFSIZE#undef BUFSIZE#define BUFSIZE 37@end example@noindentNow @samp{TABLESIZE} expands (in two stages) to @samp{37}.@node Conditionals, Combining Sources, Macros, Top@section Conditionals@cindex conditionalsIn a macro processor, a @dfn{conditional} is a command that allows a partof the program to be ignored during compilation, on some conditions.In the C preprocessor, a conditional can test either an arithmetic expressionor whether a name is defined as a macro.A conditional in the C preprocessor resembles in some ways an @samp{if}statement in C, but it is important to understand the difference betweenthem. The condition in an @samp{if} statement is tested during the executionof your program. Its purpose is to allow your program to behave differentlyfrom run to run, depending on the data it is operating on. The conditionin a preprocessor conditional command is tested when your program is compiled.Its purpose is to allow different code to be included in the program dependingon the situation at the time of compilation.@menu* Uses: Conditional Uses. What conditionals are for.* Syntax: Conditional Syntax. How conditionals are written.* Deletion: Deleted Code. Making code into a comment.* Macros: Conditionals-Macros. Why conditionals are used with macros.* Errors: #error Command. Detecting inconsistent compilation parameters.@end menu@node Conditional Uses, Conditional Syntax, Conditionals, Conditionals@subsection Why Conditionals are UsedGenerally there are three kinds of reason to use a conditional.@itemize @bullet@itemA program may need to use different code depending on the machine oroperating system it is to run on. In some cases the code for oneoperating system may be erroneous on another operating system; forexample, it might refer to library routines that do not exist on theother system. When this happens, it is not enough to avoid executingthe invalid code: merely having it in the program makes it impossibleto link the program and run it. With a preprocessor conditional, theoffending code can be effectively excised from the program when it isnot valid.@itemYou may want to be able to compile the same source file into twodifferent programs. Sometimes the difference between the programs isthat one makes frequent time-consuming consistency checks on itsintermediate data while the other does not.@itemA conditional whose condition is always false is a good way to excludecode from the program but keep it as a sort of comment for futurereference.@end itemizeMost simple programs that are intended to run on only one machine willnot need to use preprocessor conditionals.@node Conditional Syntax, Deleted Code, Conditional Uses, Conditionals@subsection Syntax of Conditionals@findex #ifA conditional in the C preprocessor begins with a @dfn{conditionalcommand}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}.@xref{Conditionals-Macros}, for info on @samp{#ifdef} and@samp{#ifndef}; only @samp{#if} is explained here.@menu* If: #if Command. Basic conditionals using @samp{#if} and @samp{#endif}.* Else: #else Command. Including some text if the condition fails.* Elif: #elif Command. Testing several alternative possibilities.@end menu@node #if Command, #else Command, Conditional Syntax, Conditional Syntax@subsubsection The @samp{#if} CommandThe @samp{#if} command in its simplest form consists of@example#if @var{expression}@var{controlled text}#endif /* @var{expression} */@end exampleThe comment following the @samp{#endif} is not required, but it is a goodpractice because it helps people match the @samp{#endif} to thecorresponding @samp{#if}. Such comments should always be used, except inshort conditionals that are not nested. In fact, you can put anything atall after the @samp{#endif} and it will be ignored by the GNU C preprocessor,but only comments are acceptable in ANSI Standard C.@var{expression} is a C expression of integer type, subject to stringentrestrictions. It may contain@itemize @bullet@itemInteger constants, which are all regarded as @code{long} or@code{unsigned long}.@itemCharacter constants, which are interpreted according to the characterset and conventions of the machine and operating system on which thepreprocessor is running. The GNU C preprocessor uses the C data type@samp{char} for these character constants; therefore, whether somecharacter codes are negative is determined by the C compiler used tocompile the preprocessor. If it treats @samp{char} as signed, thencharacter codes large enough to set the sign bit will be considerednegative; otherwise, no character code is considered negative.@itemArithmetic operators for addition, subtraction, multiplication,division, bitwise operations, shifts, comparisons, and @samp{&&} and@samp{||}.@itemIdentifiers that are not macros, which are all treated as zero(!).@itemMacro calls. All macro calls in the expression are expanded beforeactual computation of the expression's value begins.@end itemizeNote that @samp{sizeof} operators and @code{enum}-type values are not allowed.@code{enum}-type values, like all other identifiers that are not takenas macro calls and expanded, are treated as zero.The text inside of a conditional can include preprocessor commands. Thenthe commands inside the conditional are obeyed only if that branch of theconditional succeeds. The text can also contain other conditional groups.However, the @samp{#if}'s and @samp{#endif}'s must balance.@node #else Command, #elif Command, #if Command, Conditional Syntax@subsubsection The @samp{#else} Command@findex #elseThe @samp{#else} command can be added to a conditional to provide alternativetext to be used if the condition is false. This looks like@example#if @var{expression}@var{text-if-true}#else /* Not @var{expression} */@var{text-if-false}#endif /* Not @var{expression} */@end exampleIf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -