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

#elif <unused> always evaluated?

5 views
Skip to first unread message

Hallvard B Furuseth

unread,
Nov 18, 2008, 12:05:47 PM11/18/08
to
Is #elif supposed to be equivalent to #else - #if ... #endif?

It doesn't seem to be, according to the wording of the standard:
#define FOO sizeof(void *)
#ifdef FOO
#elif FOO /* expanded and evaluated - compile error? */
#endif
C99 6.10.1p2 indicate that #if and #elif evaluate their controlling
integer constant expressions. Nothing in 6.10.1p3 or elsewhere
seems to exclude #elif expressions whose values will not be used.

On the other hand, FOO in "#if FOO" is not evaluated here:
#define FOO sizeof(void *)
#ifdef FOO
#else
# if FOO /* not expanded */
# endif
#endif
but the reasons don't help #elif FOO:
6.10p7 says macros are not expanded unless stated, but 6.10.1p2 does
state it. 6.10p4/6.10.1p5 relax the rules for skipped groups, but
a "group" in the syntax are the text lines between #if/#elif/#endif,
not those statements themselves.

Encountered in the upcoming gcc 4.4. The #else-#if-#endif workaround
is easy enough, but I wonder if that's intented.

--
Hallvard

Charlie Gordon

unread,
Nov 18, 2008, 12:19:06 PM11/18/08
to
"Hallvard B Furuseth" <h.b.fu...@usit.uio.no> a écrit dans le message de
news: hbf.2008...@bombur.uio.no...

> Is #elif supposed to be equivalent to #else - #if ... #endif?
>
> It doesn't seem to be, according to the wording of the standard:
> #define FOO sizeof(void *)
> #ifdef FOO
> #elif FOO /* expanded and evaluated - compile error? */
> #endif

I understand your question, but how much sense does it make to test #if FOO
in the #else or #elif block where you know FOO is not defined ? I guess the
example is made up for illustration of the issue.

--
Chqrlie.


Derek M. Jones

unread,
Nov 18, 2008, 12:39:44 PM11/18/08
to
Hallvard,

> Is #elif supposed to be equivalent to #else - #if ... #endif?

It is and you're right that the standard is completely silent
on this issue. Now that you have pointed it out I cannot
believe I did not notice years ago.

Hallvard B Furuseth

unread,
Nov 18, 2008, 1:23:00 PM11/18/08
to
Charlie Gordon writes:
>> It doesn't seem to be, according to the wording of the standard:
>> #define FOO sizeof(void *)
>> #ifdef FOO
>> #elif FOO /* expanded and evaluated - compile error? */
>> #endif
>
> I understand your question, but how much sense does it make to test
> #if FOO in the #else or #elif block where you know FOO is not defined
> ? I guess the example is made up for illustration of the issue.

Yup. It started out differently, then everything irrelevant
disappeared as I wrote. Here is another:

#undef FOO
#ifndef FOO
#define FOO sizeof(void *)
#elif FOO
#endif

--
Hallvard

jacob navia

unread,
Nov 18, 2008, 1:39:17 PM11/18/08
to

lcc-win reports an error in that example (line 4). It should be:
1 #undef FOO
2 #ifndef FOO
3 #define FOO sizeof(void *)
4 #elif defined(FOO)
5 #endif

With that change lcc-win reports nothing, as I think it should be.
Ignoring the standard, common sense dictates that

#ifndef FOO
// Since FOO is not defined this branch of the if will be
// passed through
#elif
This will never pass through since the if branch has already succeeded
#endif
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32

Keith Thompson

unread,
Nov 18, 2008, 2:25:01 PM11/18/08
to
jacob navia <ja...@nospam.com> writes:
> Hallvard B Furuseth wrote:
>> Charlie Gordon writes:
>>>> It doesn't seem to be, according to the wording of the standard:
>>>> #define FOO sizeof(void *)
>>>> #ifdef FOO
>>>> #elif FOO /* expanded and evaluated - compile error? */
>>>> #endif
>>> I understand your question, but how much sense does it make to test
>>> #if FOO in the #else or #elif block where you know FOO is not defined
>>> ? I guess the example is made up for illustration of the issue.
>> Yup. It started out differently, then everything irrelevant
>> disappeared as I wrote. Here is another:
>> #undef FOO
>> #ifndef FOO
>> #define FOO sizeof(void *)
>> #elif FOO
>> #endif
>>
>
> lcc-win reports an error in that example (line 4). It should be:
> 1 #undef FOO
> 2 #ifndef FOO
> 3 #define FOO sizeof(void *)
> 4 #elif defined(FOO)
> 5 #endif

No, it should be "#elif FOO". Your modified version doesn't
illustrate the issue, which is the whole point here. We're not trying
to write useful code, we're trying to write code that explores how the
preprocessor behaves in this particular case.

> With that change lcc-win reports nothing, as I think it should be.

Agreed, but not particularly relevant.

> Ignoring the standard, common sense dictates that
>
> #ifndef FOO
> // Since FOO is not defined this branch of the if will be
> // passed through
> #elif
> This will never pass through since the if branch has already succeeded
> #endif

It's a bit odd to use the phrase "Ignoring the standard" in
comp.std.c. If your point is that the standard should be revised to
reflect common sense, I agree (at least in this case).

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

jacob navia

unread,
Nov 18, 2008, 5:12:45 PM11/18/08
to


Excuse me but #if (and #elif) need a constant expression isn't it?
Not just a naked identifier.

Or are you confusing it with #ifdef ???

>> With that change lcc-win reports nothing, as I think it should be.
>
> Agreed, but not particularly relevant.
>
>> Ignoring the standard, common sense dictates that
>>
>> #ifndef FOO
>> // Since FOO is not defined this branch of the if will be
>> // passed through
>> #elif
>> This will never pass through since the if branch has already succeeded
>> #endif
>
> It's a bit odd to use the phrase "Ignoring the standard" in
> comp.std.c. If your point is that the standard should be revised to
> reflect common sense, I agree (at least in this case).
>


Obviously common sense is a higher standard, and the C standard should
follow THAT one :-)

Hallvard B Furuseth

unread,
Nov 18, 2008, 5:19:04 PM11/18/08
to
jacob navia writes:
> Excuse me but #if (and #elif) need a constant expression isn't it?

Yes.

> Not just a naked identifier.

A "naked identifier" - an undefined macro - evaluates to 0 in #if/#elif.

--
Hallvard

jacob navia

unread,
Nov 18, 2008, 5:29:07 PM11/18/08
to

Mmmm lcc-win's preprocessor doesn't treat FOO as an
identifier but as "sizeof(void)" or whatever... Hence the
error.

I see the problem now, it was unclear before.

Thanks

lawrenc...@siemens.com

unread,
Nov 19, 2008, 9:26:42 AM11/19/08
to
jacob navia <ja...@nospam.com> wrote:
>
> Mmmm lcc-win's preprocessor doesn't treat FOO as an
> identifier but as "sizeof(void)" or whatever... Hence the
> error.

The example under discussion is:

#undef FOO
#ifndef FOO
#define FOO sizeof(void *)
#elif FOO
#endif

If the controlling expression of the #elif is evaluated, FOO will be
macro replaced with sizeof(void *) which will then be expanded by the
"all remaining identifiers are replaced with 0" rule to 0(0 *), which
is, of course, a syntax error. However, I am reasonably sure the intent
was that the controlling expression *not* be evaluated in this case
(i.e., once a group is processed, all remaing groups are skipped). I've
noted that we need to add semantics for #elif to the standard (and am
amazed that no one has noticed the oversight until now).
--
Larry Jones

You know how Einstein got bad grades as a kid? Well MINE are even WORSE!
-- Calvin

kyuupi

unread,
Nov 23, 2008, 11:53:48 PM11/23/08
to
On Nov 19, 11:26 pm, lawrence.jo...@siemens.com wrote:

> The example under discussion is:
>
> #undef  FOO
> #ifndef FOO
> #define FOO sizeof(void *)
> #elif   FOO
> #endif
>
> If the controlling expression of the #elif is evaluated, FOO will be
> macro replaced with sizeof(void *) which will then be expanded by the
> "all remaining identifiers are replaced with 0" rule to 0(0 *), which
> is, of course, a syntax error.  However, I am reasonably sure the intent
> was that the controlling expression *not* be evaluated in this case
> (i.e., once a group is processed, all remaing groups are skipped).  I've
> noted that we need to add semantics for #elif to the standard (and am
> amazed that no one has noticed the oversight until now).

I agree with thi analysis, but disagree with you and Derek that the
semantics
of the #elif are not defined in the standard. The normative text of
the standard
mentions #elif everywhere it mentions #if, so they are just as defined
as each
other.

The preprocessor syntax is given in 6.10, the violation of which
requires a
diagnostic. 6.10.1p6 gives circumstances under which the syntax
is relaxed, and the case under discussion here does not fall under
them because the #elif is not part of a group controlled by a false
condition, again referring to the grammar in 6.10 for what is a
controlled group.

Indeed, the reason GCC behaviour changed here is my writing grammar
and semantic tests for my own front end. I noticed GCC failed this
one
and submitted a bug report.

Now whether these semantics are desirable or intended is a different
question, but I believe the standard as-written is unambigous that the
example here requires a diagnostic.

Neil.

0 new messages