If ANOTHER_MACRO(y) is indeed evaluated for C correctness even when
SOME_MACRO(x) expands to 1, then clearly the sequence #if - #elif -
#endif is not simply a shorthand for #if - #else - #if - #endif -
#endif. I would think that is something which would puzzle most C++
programmers, as it puzzled me when this sort of situation came up in
real code.
Could you cite a section in the C standard which justifies your
interpretation ?
You've got it backwards. Look for where it says anything is _not_
evaluated. It says when groups _between_ #if/#elif/#else directives
are skipped. It forgets to mention skipping the #elif expression.
--
Hallvard
About as clear as it's intended that the #elif expression should be
skipped, I suppose:)
--
Hallvard
To be a bit less flippant in the morning, there's the difference that
if you implement the standard's words literally, you are sure to notice
this one when you test your compiler.
--
Hallvard
I personally think that it's far clearer than that issue. #if and #elif
are directly described as checking "whether the controlling constant
expression evaluates to nonzero" (6.10.1p3). #ifdef IDENTIFIER is
specified as being equivalent to #if defined(IDENTIFIER), and #ifndef
IDENTIFIER is specified as being equivalent to #if !defined(IDENTIFIER)
(6.10.1p5). 6.10.1p6 refers only to a "directive's condition", without
specifying which directive it's referring to; it therefore can
reasonably be inferred that it applies to all directives which are
described as having a controlling constant expression that needs to be
checked.
...
>> talking about 6.10.1p6:
>>
>>> Each directive’s condition is checked in order. If it evaluates to false (zero), the group
>>> that it controls is skipped: directives are processed only through the name that determines
>>> the directive in order to keep track of the level of nested conditionals; the rest of the
>>> directives’ preprocessing tokens are ignored, as are the other preprocessing tokens in the
>>> group. Only the first group whose control condition evaluates to true (nonzero) is
>>> processed. If none of the conditions evaluates to true, and there is a #else directive, the
>>> group controlled by the #else is processed; lacking a #else directive, all the groups
>>> until the #endif are skipped.147)
>
> I still do not understand what the correct ruling is. If an #if
> evaluates to true, is a corresponding #elif condition checked for C
> validity at all and, if so, exactly what is being checked ?
The description for the case where conditional directives condition is
false makes it pretty clear what should happen to nested directives
inside the group that it controls: only the directive name is parsed, so
as to correctly identify where the end of the group is - the rest of the
directive is ignored. I strongly suspect that it was intended to be the
case the same handling should apply to corresponding #else or #elif
directives when the condition is true. I believe that Larry Jone's comment:
> Oops. It appears that I let that slip through the cracks.
refers to the failure of the above text to actually specify such
handling for #else and #elif.
--
James Kuyper
The standard currently says that the #elif condition is evaulated (even
though the resulting value is irrelevant), which means that it must be
syntactically and semantically valid. It is not part of a group that is
skipped, so the special rule about only processing skipped directives
through the name does not apply.
I don't think that matches the committee's intent, but that's what it
says.
--
Larry Jones
Fortunately, that was our plan from the start. -- Calvin
This isn't a question about whether the #elif condition can be
evaluated, it's a question about whether it has the correct syntax. The
following example demonstrates the issue, without being plausible enough
to motivate significant worry about it. I gather that Edward's question
was motivated by an actual failure of real code to work as intended,
though he's never provided the details.
#ifndef OPERATION
// Something
#else
#if 5 OPERATION 3
// Something else
#endif
#endif
If OPERATION is #defined as something like "+" or "*" or ">", then "5
OPERATION 3" can be a valid integer constant expression. However, if it
is not defined, OPERATION gets replaced with 0 (6.10.1p4), so "5
OPERATION 3" becomes "5 0 3", which does not have the correct syntax to
be an constant expression, as required by the syntax for #elif
directives. This is not a problem, because the #elif is within the group
governed by the #else directive. If the #ifndef condition is true,
preprocessing directives within the group controlled by the #else
directive are parsed no farther than their directive name, solely for
the purpose of correctly identifying the end of that group (6.10.1p6).
Preprocessing tokens on the same line as skipped directives are parsed
solely to determine where the end of the directive is; they need not
have correct syntax. Therefore, the fact that "5 OPERATION 3" is not
valid integer constant expression doesn't matter.
However, if the above is re-written as follows:
#ifndef OPERATION
// Something
#elif 5 OPERATION 3
// Something else
#endif
Then there's a problem if OPERATION is not #defined. The group
controlled by the #elif is clearly discarded, but that group consists of
the // Something else" comment; it does not include the #elif directive
itself. It not covered by that rule, so "5 OPERATION 3" must be
detected as a syntax error.
Larry Jones, who is the editor for the C standard, was informed about
this problem a long time ago, acknowledged that it was a defect, and was
recently reminded of it by this very thread. That's probably sufficient
to ensure that it will eventually be dealt with, but it wouldn't hurt to
file a defect report. As I understand it, defect reports for the C
standard can only be filed by members of the committee. The best way to
do this is by joining the committee - but that is expensive and involves
a lot of work. The next-best option is to find someone who's already a
committee member and convince them to file a defect report.
--
James Kuyper
It's a non-terminal in the grammar; what more description do you need?
--
Larry Jones
Mr. Subtlety drives home another point. -- Calvin
I am not a committee member. But I would like to see a defect report
filed and this issue resolved so that the #elif expression is not
evaluated if its corresponding #if is true. If you or someone else is a
committee member, and can point me to some form for writing up a defect
report, I would be glad tyo write one up, and pass it on to the
appropriate person so that it reaches the attention of the C standard
committee. I can be reached at my reply-to address.
Edward Diener