Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Evaluation of #elif

41 views
Skip to first unread message

Edward Diener

unread,
Sep 12, 2011, 7:47:21 PM9/12/11
to
In code such as:

#if SOME_MACRO(x)
#elif ANOTHER_MACRO(y)
#endif

is ANOTHER_MACRO expanded and evaluated for C correctness even when
the result of SOME_MACRO's expansion is 1.

In other words what does the standard say about whether or not the C
preprocessor considers paths which are not taken in #if - #elif - #endif
and #if - #else - #endif constructs and whether the code in those
untaken paths need to be valid C or not ? By path I also mean the
evaluation of #elif in the first case when the corresponding #if is not 0.

Is this considered to be purely a compiler decision that has nothing to
do with the C standard or is there some C standard rule which says
whether or not an untaken preprocessor path is parsed for valid C code ?

Eric Sosman

unread,
Sep 12, 2011, 8:47:50 PM9/12/11
to
On 9/12/2011 7:47 PM, Edward Diener wrote:
> In code such as:
>
> #if SOME_MACRO(x)
> #elif ANOTHER_MACRO(y)
> #endif
>
> is ANOTHER_MACRO expanded and evaluated for C correctness even when
> the result of SOME_MACRO's expansion is 1.

As I understand it, no. Quoth the Standard (6.10.1p6):

Each directive’s condition is checked in order. [...] Only
the first group whose control condition evaluates to true
(nonzero) is processed.

> In other words what does the standard say about whether or not the C
> preprocessor considers paths which are not taken in #if - #elif - #endif
> and #if - #else - #endif constructs and whether the code in those
> untaken paths need to be valid C or not ? By path I also mean the
> evaluation of #elif in the first case when the corresponding #if is not 0.

The material need not be valid C, but it must be "tokenizable."
For example,

#if 0
/* I am an unterminated comment
#endif

won't work, and similar situations occur with unmatched " or ', or
with characters that would be just plain meaningless in source code.
But you *can* #if or #ifdef out "tokenizable" nonsense:

#if 0
>)<I am a bunch of gibberish](]
#endif

is perfectly all right.

Note that conditionals within a skipped region are still parsed
to the extent of being recognized as conditionals, so proper nesting
is maintained. That is,

#if 0
#if 1
You are in a maze of twisty little passages, all different.
#endif
You are in a twisty little maze of passages, all different.
#endif

is all right, because the skipped "#if 1" is still recognized as a
conditional. Thus, the outer "#if 0" doesn't end prematurely, as
it might if the "#if 1" were ignored altogether.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Paul Mensonides

unread,
Sep 13, 2011, 6:39:03 AM9/13/11
to
On Mon, 12 Sep 2011 20:47:50 -0400, Eric Sosman wrote:

> won't work, and similar situations occur with unmatched " or ', or with
> characters that would be just plain meaningless in source code. But you
> *can* #if or #ifdef out "tokenizable" nonsense:
>
> #if 0
> >)<I am a bunch of gibberish](]
> #endif
>
> is perfectly all right.

What Edward is specifically referring to is something like the following:

#if 1

// ...

#elif >)<I am a bunch of gibberish](] // point 1

#if >)<I am a bunch of gibberish](] // point 2

#endif

#endif

IOW, point 2 is obviously okay. The question is whether point 1 is okay
given that the first #if branch is taken.

-Paul

Eric Sosman

unread,
Sep 13, 2011, 8:01:15 AM9/13/11
to
The first sentence of my response was "As I understand it, no."

Disclaimer: I almost never speak ex cathedra.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Hallvard B Furuseth

unread,
Sep 13, 2011, 8:38:28 AM9/13/11
to
Edward Diener writes:
> #if SOME_MACRO(x)
> #elif ANOTHER_MACRO(y)
> #endif
>
> is ANOTHER_MACRO expanded and evaluated for C correctness even when
> the result of SOME_MACRO's expansion is 1.

Yes. Likely an oversight. Larry Jones said in 2008 he'd bring it up
for C1X, in message <2akdv5...@jones.homeip.net>.

As far as I can tell, N1570 still says the #elif is processed. But
maybe I'm just tired. Looking again, I can't find any text which says
when (or that) the groups after #if and #elif are skipped either, only
when the groups after #ifdef, #ifndef and #else are skipped.

--
Hallvard

lawrenc...@siemens.com

unread,
Sep 13, 2011, 10:08:21 AM9/13/11
to
Edward Diener <eldi...@tropicsoft.invalid> wrote:
> In code such as:
>
> #if SOME_MACRO(x)
> #elif ANOTHER_MACRO(y)
> #endif
>
> is ANOTHER_MACRO expanded and evaluated for C correctness even when
> the result of SOME_MACRO's expansion is 1.

The standard is clear that any nested directives undergo only very
minimal processing but it doesn't say the same about directives at the
top level that follow the first group that isn't skipped. Thus, it
appears to require *all* the conditions to be evaluated, which means
that they must be valid constant expressions.
--
Larry Jones

There's never enough time to do all the nothing you want. -- Calvin

lawrenc...@siemens.com

unread,
Sep 13, 2011, 10:19:44 AM9/13/11
to
Hallvard B Furuseth <h.b.fu...@usit.uio.no> wrote:
>
> Yes. Likely an oversight. Larry Jones said in 2008 he'd bring it up
> for C1X, in message <2akdv5...@jones.homeip.net>.

Oops. It appears that I let that slip through the cracks.

> As far as I can tell, N1570 still says the #elif is processed. But
> maybe I'm just tired. Looking again, I can't find any text which says
> when (or that) the groups after #if and #elif are skipped either, only
> when the groups after #ifdef, #ifndef and #else are skipped.

I think it's reasonably clear that p6 is intended to apply to all of the
conditional directives.
--
Larry Jones

I can do that! It's a free country! I've got my rights! -- Calvin

Edward Diener

unread,
Sep 13, 2011, 9:34:41 PM9/13/11
to
On 9/13/2011 8:01 AM, Eric Sosman wrote:
> On 9/13/2011 6:39 AM, Paul Mensonides wrote:
>> On Mon, 12 Sep 2011 20:47:50 -0400, Eric Sosman wrote:
>>
>>> won't work, and similar situations occur with unmatched " or ', or with
>>> characters that would be just plain meaningless in source code. But you
>>> *can* #if or #ifdef out "tokenizable" nonsense:
>>>
>>> #if 0
>>> >)<I am a bunch of gibberish](]
>>> #endif
>>>
>>> is perfectly all right.
>>
>> What Edward is specifically referring to is something like the following:
>>
>> #if 1
>>
>> // ...
>>
>> #elif>)<I am a bunch of gibberish](] // point 1
>>
>> #if>)<I am a bunch of gibberish](] // point 2
>>
>> #endif
>>
>> #endif
>>
>> IOW, point 2 is obviously okay. The question is whether point 1 is okay
>> given that the first #if branch is taken.
>
> The first sentence of my response was "As I understand it, no."

That was in response to my OP, which means to me that you are saying
"yes" to Paul's question immediately above as I understand it.

Edward Diener

unread,
Sep 13, 2011, 9:45:06 PM9/13/11
to
On 9/13/2011 8:38 AM, Hallvard B Furuseth wrote:
> Edward Diener writes:
>> #if SOME_MACRO(x)
>> #elif ANOTHER_MACRO(y)
>> #endif
>>
>> is ANOTHER_MACRO expanded and evaluated for C correctness even when
>> the result of SOME_MACRO's expansion is 1.
>
> Yes. Likely an oversight. Larry Jones said in 2008 he'd bring it up
> for C1X, in message<2akdv5...@jones.homeip.net>.

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.


Edward Diener

unread,
Sep 13, 2011, 9:47:52 PM9/13/11
to
On 9/13/2011 10:08 AM, lawrenc...@siemens.com wrote:
> Edward Diener<eldi...@tropicsoft.invalid> wrote:
>> In code such as:
>>
>> #if SOME_MACRO(x)
>> #elif ANOTHER_MACRO(y)
>> #endif
>>
>> is ANOTHER_MACRO expanded and evaluated for C correctness even when
>> the result of SOME_MACRO's expansion is 1.
>
> The standard is clear that any nested directives undergo only very
> minimal processing but it doesn't say the same about directives at the
> top level that follow the first group that isn't skipped. Thus, it
> appears to require *all* the conditions to be evaluated, which means
> that they must be valid constant expressions.

Could you cite a section in the C standard which justifies your
interpretation ?


Hallvard B Furuseth

unread,
Sep 14, 2011, 2:10:35 AM9/14/11
to

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

Hallvard B Furuseth

unread,
Sep 14, 2011, 2:12:35 AM9/14/11
to
lawrenc...@siemens.com writes:
> Hallvard B Furuseth <h.b.fu...@usit.uio.no> wrote:
>> (...) Looking again, I can't find any text which says

>> when (or that) the groups after #if and #elif are skipped either, only
>> when the groups after #ifdef, #ifndef and #else are skipped.
>
> I think it's reasonably clear that p6 is intended to apply to all of the
> conditional directives.

About as clear as it's intended that the #elif expression should be
skipped, I suppose:)

--
Hallvard

Hallvard B Furuseth

unread,
Sep 14, 2011, 2:26:12 AM9/14/11
to

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

Edward Diener

unread,
Sep 15, 2011, 10:29:42 PM9/15/11
to
To what does p6 refer ?


James Kuyper

unread,
Sep 16, 2011, 7:57:09 AM9/16/11
to
We're talking about conditional inclusion; section 6.10.1 is the part of
the standard that covers conditional inclusion, so I would presume he's
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)
--
James Kuyper

Hallvard B Furuseth

unread,
Sep 16, 2011, 8:45:03 AM9/16/11
to
lawrenc...@siemens.com writes:
>Hallvard B Furuseth <h.b.fu...@usit.uio.no> wrote:
>> (...) Looking again, I can't find any text which says
>> when (or that) the groups after #if and #elif are skipped either, only
>> when the groups after #ifdef, #ifndef and #else are skipped.
>
> I think it's reasonably clear that p6 is intended to apply to all of the
> conditional directives.

Yes indeed. It helps so much so not somehow see the top line at that
page as a header. Sorry about the noise.

--
Hallvard

Edward Diener

unread,
Sep 16, 2011, 11:05:58 PM9/16/11
to
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 ?

James Kuyper

unread,
Sep 17, 2011, 8:51:50 AM9/17/11
to
On 09/16/2011 11:05 PM, Edward Diener wrote:
> On 9/16/2011 7:57 AM, James Kuyper wrote:
>> On 09/15/2011 10:29 PM, Edward Diener wrote:
>>> On 9/14/2011 2:12 AM, Hallvard B Furuseth wrote:
>>>> lawrenc...@siemens.com writes:
>>>>> Hallvard B Furuseth<h.b.fu...@usit.uio.no> wrote:
>>>>>> (...) Looking again, I can't find any text which says
>>>>>> when (or that) the groups after #if and #elif are skipped either, only
>>>>>> when the groups after #ifdef, #ifndef and #else are skipped.
>>>>>
>>>>> I think it's reasonably clear that p6 is intended to apply to all of the
>>>>> conditional directives.
>>>>
>>>> About as clear as it's intended that the #elif expression should be
>>>> skipped, I suppose:)

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

Hallvard B Furuseth

unread,
Sep 17, 2011, 9:09:32 AM9/17/11
to
James Kuyper writes:
>>>> On 9/14/2011 2:12 AM, Hallvard B Furuseth wrote:
>>>>> lawrenc...@siemens.com writes:
>>>>>> I think it's reasonably clear that p6 is intended to apply to all of the
>>>>>> conditional directives.
>>>>>
>>>>> About as clear as it's intended that the #elif expression should be
>>>>> skipped, I suppose:)
>
> I personally think that it's far clearer than that issue.

Yes. I was just too tired to see straight.

--
Hallvard

Edward Diener

unread,
Sep 17, 2011, 9:40:09 AM9/17/11
to
So then is the answer is that the C standard, in 6.10.1p6, does not
specify whether or not the #elif expression is checked when its
corresponding #if directive is true ?

This seems a defect in the C standard, or is it the intention of the
standard then to imply that since the C standard does not specify this,
it is therefore implementation defined what is done ?

I also asked about this in comp.std.c++, only to be told that the C++
standard directly follows the C standard and I should ask here. Which
would make both the C and C++ standards seemingly defective in not
specifying whether the #elif expression is checked for valid C ( or C++
) syntax when its corresponding #if expression is true.

Also I would still like to know what it would mean to "check" the #elif
expression for valid C ( or C++ ) syntax when its corresponding #if
expression is true. Does this just mean that the #elif expression
consisted of valid preprocessing tokens, or does it mean that the #elif
expression was a valid C ( or C++ ) constant expression ?

James Kuyper

unread,
Sep 17, 2011, 2:57:25 PM9/17/11
to
On 09/17/2011 09:40 AM, Edward Diener wrote:
> On 9/17/2011 8:51 AM, James Kuyper wrote:
>> On 09/16/2011 11:05 PM, Edward Diener wrote:
...
>> 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.
>
> So then is the answer is that the C standard, in 6.10.1p6, does not
> specify whether or not the #elif expression is checked when its
> corresponding #if directive is true ?
>
> This seems a defect in the C standard,

I think Larry's comment of "oops" clearly indicates that he thinks it's
a defect, and given that he's the editor for the standard, I give his
opinion a lot of weight.

> ... or is it the intention of the
> standard then to imply that since the C standard does not specify this,
> it is therefore implementation defined what is done ?

There's certainly nothing saying that it's implementation-defined.
Either it's parsed normally, just like the corresponding #if, or it's
unspecified, but it would be implementation-defined only if the standard
explicitly said that it was, and it doesn't.

> I also asked about this in comp.std.c++, only to be told that the C++
> standard directly follows the C standard and I should ask here. ...

That's not entirely appropriate. It would be for questions about, for
instance, the C standard library. That library's description from the C
standard is included only by reference in the C++ standard, with
modifications, and it's necessary to go to the C standard to find
answers to questions about that library. However, the C++ standard has
it's only specification of the conditional inclusion preprocessing
directives (it's in section 16.2 of the lastest draft of the next
version of the standard that I have: n3035.pdf). Questions about those
issues in C++ should be resolved by reference to that section, not to
the corresponding section of the C standard. From a quick glance, it
looks to me like the C++ standard says almost exactly the same things
that the C standard says about such things. If so, it suffers from the
same defect. However, if there's any difference that I didn't notice
between C++ 16.2 and C 6.10.1, it's C++ 16.2 which matters for C++ code.

...
> Also I would still like to know what it would mean to "check" the #elif
> expression for valid C ( or C++ ) syntax when its corresponding #if
> expression is true. Does this just mean that the #elif expression
> consisted of valid preprocessing tokens, or does it mean that the #elif
> expression was a valid C ( or C++ ) constant expression ?

If the syntax of the entire directive does indeed need to be checked,
everything between the directive name and the following newline would
have to be checked for validity as a C or C++ constant expression
respectively(subject to the special rules that apply to #if directives),
because that's what both standards specify. They do NOT specify
arbitrary valid pre-processing tokens.
--
James Kuyper

Edward Diener

unread,
Sep 18, 2011, 6:55:29 AM9/18/11
to
On 9/17/2011 2:57 PM, James Kuyper wrote:
> On 09/17/2011 09:40 AM, Edward Diener wrote:
>> On 9/17/2011 8:51 AM, James Kuyper wrote:
>>> On 09/16/2011 11:05 PM, Edward Diener wrote:
> ...
>>> 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.
>>
>> So then is the answer is that the C standard, in 6.10.1p6, does not
>> specify whether or not the #elif expression is checked when its
>> corresponding #if directive is true ?
>>
>> This seems a defect in the C standard,
>
> I think Larry's comment of "oops" clearly indicates that he thinks it's
> a defect, and given that he's the editor for the standard, I give his
> opinion a lot of weight.

Should I write a defect report and, if so, how do I go about doing so ?
Or is Larry ( I assume this means Larry Jones who is mentioned in
another post of this thread ) addressing this issue ?

>
>> ... or is it the intention of the
>> standard then to imply that since the C standard does not specify this,
>> it is therefore implementation defined what is done ?
>
> There's certainly nothing saying that it's implementation-defined.
> Either it's parsed normally, just like the corresponding #if, or it's
> unspecified, but it would be implementation-defined only if the standard
> explicitly said that it was, and it doesn't.

Understood.
Thanks for the clarification.

James Kuyper

unread,
Sep 18, 2011, 7:23:06 AM9/18/11
to
On 09/18/2011 06:55 AM, Edward Diener wrote:
> On 9/17/2011 2:57 PM, James Kuyper wrote:
>> On 09/17/2011 09:40 AM, Edward Diener wrote:
>>> On 9/17/2011 8:51 AM, James Kuyper wrote:
>>>> On 09/16/2011 11:05 PM, Edward Diener wrote:
>> ...
>>>> directives when the condition is true. I believe that Larry Jone's comment:
>>>>
>>>>> Oops. It appears that I let that slip through the cracks.
...
>> I think Larry's comment of "oops" clearly indicates that he thinks it's
>> a defect, and given that he's the editor for the standard, I give his
>> opinion a lot of weight.
>
> Should I write a defect report and, if so, how do I go about doing so ?
> Or is Larry ( I assume this means Larry Jones who is mentioned in
> another post of this thread ) addressing this issue ?

"I let that slip through the cracks" suggests to me that he will be
addressing it, now that he's been reminded of the issue.
--
James Kuyper

lawrenc...@siemens.com

unread,
Sep 18, 2011, 2:47:29 PM9/18/11
to
Edward Diener <eldi...@tropicsoft.invalid> wrote:
>
> 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 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

Edward Diener

unread,
Sep 19, 2011, 7:20:00 PM9/19/11
to
On 9/18/2011 2:47 PM, lawrenc...@siemens.com wrote:
> Edward Diener<eldi...@tropicsoft.invalid> wrote:
>>
>> 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 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.

If that is the ruling I acknowledge it. I do not think, however, that it
corresponds to the way that the vast majority of programmers, even the
experts, think about the correspondence between #if - #elif - #endif and
#if - #else - #if - #endif - #endif. How many would actually realize
that they are not equivalent, given that the first always evaluates the
#elif expression, even when the first #if is true, while the latter
never evaluates the equivalent code between the second #if and its
#endif, when the first #if is true ? I think this difference needs to be
reconsidered by the C standard, since I do not think it should occur; if
its corresponding #if is true, the #elif expression should not need to
be a valid constant expression.

Forcing the #elif to be a valid constant expression, even when its
corresponding #if is true and therefore immediately ruling out the #elif
path, seems to be to be not only totally unnecessary but detrimental to
the writing/using of correct preprocessor code. One could design a pair
of macros where when the first evaluates to true, the second becomes
expands to invalid C++, whereas when the first evaluates to false, the
second expands to a valid constant expression. In this scenario having
one end-user successfully use those macros in this way:

#if FIRST_MACRO(some_param)
// some C++ code
#else
#if SECOND_MACRO(some_other_param)
// some other C++ code
#endif
#endif

while a second user unsuccessfully uses those macros in this way:

#if FIRST_MACRO(some_param)
// some C++ code
#elif SECOND_MACRO(some_other_param)
// some other C++ code
#endif

is not what I would call a good situation in C++.

While you may inveigh against such a design, Paul Mensonides, the author
of the Boost Preprocessor Library and surely an expert on preprocessor
programming, did just that in a situation in his preprocessor library (
he has since changed his code to make it more foolproof in an update on
which I worked with him on other functionality ) and I see nothing
really wrong in his original situation. But C ( and C++ ), by forcing
the #elif expression to be evaluated when its corresponding #if is true,
caused the type of problem for him as I have illustrated above.

I hope this situation is changed. I can not see the purpose for
evaluating the #elif expression in this situation and I do see a purpose
in making #elif equivalent if #else - #if in all respects, since that is
probably the common assumption of nearly all C/C++ programmers.

Eddie Diener

James Kuyper

unread,
Sep 19, 2011, 10:49:00 PM9/19/11
to
On 09/19/2011 07:20 PM, Edward Diener wrote:
> On 9/18/2011 2:47 PM, lawrenc...@siemens.com wrote:
>> Edward Diener<eldi...@tropicsoft.invalid> wrote:
>>>
>>> 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 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.
>
> If that is the ruling I acknowledge it.

While Larry Jones is on the committee, his statements about such matters
do not constitute official rulings, only the committee itself can issue
such rulings. He has indicated that, as editor, he's empowered to make
purely editorial corrections without requiring the committee's approval,
but I'm not sure that this qualifies as editorial.

> ... I do not think, however, that it
> corresponds to the way that the vast majority of programmers, even the
> experts, think about the correspondence between #if - #elif - #endif and
> #if - #else - #if - #endif - #endif. How many would actually realize
> that they are not equivalent, given that the first always evaluates the
> #elif expression, even when the first #if is true, while the latter
> never evaluates the equivalent code between the second #if and its
> #endif, when the first #if is true ? I think this difference needs to be
> reconsidered by the C standard, since I do not think it should occur; if
> its corresponding #if is true, the #elif expression should not need to
> be a valid constant expression.

He said "I don't think that matches the committee's intent", which
strongly suggests that he thinks this issue would be resolved, if
brought before the committee, in pretty much the way you want it to be:
with new wording in the next version of the standard that says clearly
that unused #elif directives are not parsed past the directive name.

> Forcing the #elif to be a valid constant expression, even when its
> corresponding #if is true and therefore immediately ruling out the #elif
> path, seems to be to be not only totally unnecessary but detrimental to
> the writing/using of correct preprocessor code. One could design a pair
> of macros where when the first evaluates to true, the second becomes
> expands to invalid C++, whereas when the first evaluates to false, the

This is comp.std.c, not comp.std.c++, so "invalid C" would constitute a
more relevant issue.

The C++ standard has it's own section describing conditional inclusion.
It's very similar to the corresponding section of the C standard, but it
doesn't incorporate the C standard's wording by reference; therefore,
correcting the C standard's wording wouldn't have any effect on C++ code.

If you're really primarily concerned about C++, rather than C, you'll
have to bring up the issue with the C++ committee; that's somewhat
easier to do than for C. As I remember it, a message posted to
comp.std.c++ with a Subject: header containing "Defect Report" is passed
on to the appropriate people and converted into a formal defect report.
--
James Kuyper

lawrenc...@siemens.com

unread,
Sep 20, 2011, 11:32:22 AM9/20/11
to
Edward Diener <eldi...@tropicsoft.invalid> wrote:
>
> If that is the ruling I acknowledge it.

It's not an official ruling, just my interpretation. But I think the
words are pretty clear.

> I do not think, however, that it
> corresponds to the way that the vast majority of programmers, even the
> experts, think about the correspondence between #if - #elif - #endif and
> #if - #else - #if - #endif - #endif.

I agree, which is why I said I didn't think it matched the committee's
intent.
--
Larry Jones

I think your train of thought is a runaway. -- Calvin's Mom

Edward Diener

unread,
Sep 24, 2011, 9:17:14 AM9/24/11
to
Leaving aside C++ right now, how does one get C to change so that the
#elif expression is not evaluated when the corresponding #if is true ?
Is there a way to file a defect report which gets to the C standard
committee ?

Phil Carmody

unread,
Sep 24, 2011, 12:53:34 PM9/24/11
to
If you embed the condition as a #if/endif pair inside a #else section,
then would it just be skipped over?

Phil
--
"Religion is what keeps the poor from murdering the rich."
-- Napoleon

Edward Diener

unread,
Sep 24, 2011, 6:49:38 PM9/24/11
to
Doing:

#if 1
#else
#if gobbledygook
#endif
#endif

is perfectly valid

but:

#if 1
#elif gobbledygook
#endif

will give a compiler error if 'gobbledygook' is not a valid constant
expression, according to the C standard.

I am arguing that this is wrong and the second case should be perfectly
valid C no matter what 'gobbledygook' is.

So far I have been told that this is probably an oversight in the C
standard and now I am asking if there is a way to suggest that the C
standard eventually change in this respect by filing some sort of defect
report.

Eric Sosman

unread,
Sep 24, 2011, 8:04:37 PM9/24/11
to
Let's recast this in a more concrete form:

#if N <= 0
...
#elif 65536 / N < 42
...
#else
...
#endif

Clearly, the constant-expression `65536 / N' elicits a diagnostic
if `N' is zero. The hope is that the initial #if disposes of this
case, and that the #elif does not even attempt the evaluation.

I think the hope is justified, but it seems a majority cannot
find conclusive justification in the Standard. That being the case,
I think the Standard would be improved if it described the nature of
a conditional inclusion's "group" in more detail.

--
Eric Sosman
eso...@ieee-dot-org.invalid

James Kuyper

unread,
Sep 25, 2011, 6:59:25 AM9/25/11
to
On 09/24/2011 08:04 PM, Eric Sosman wrote:
> On 9/24/2011 6:49 PM, Edward Diener wrote:
...

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

lawrenc...@siemens.com

unread,
Sep 25, 2011, 1:44:43 PM9/25/11
to
Eric Sosman <eso...@ieee-dot-org.invalid> wrote:
>
> I think the Standard would be improved if it described the nature of
> a conditional inclusion's "group" in more detail.

It's a non-terminal in the grammar; what more description do you need?

--
Larry Jones

Mr. Subtlety drives home another point. -- Calvin

Edward Diener

unread,
Sep 25, 2011, 10:53:27 PM9/25/11
to
On 9/25/2011 6:59 AM, James Kuyper wrote:
snipped...

>
> 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.

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

0 new messages