Topic: Encountering else without having executed an if, was: 'if' statement to control switch case


Author: "James Kanze" <james.kanze@gmail.com>
Date: Fri, 13 Apr 2007 09:04:35 CST
Raw View
On Apr 12, 5:11 pm, com...@panix.com (Greg Comeau) wrote:
> In article <1176380229.125484.70...@y5g2000hsa.googlegroups.com>,

> James Kanze <james.ka...@gmail.com> wrote:
> >... the actual wording in
> >C++ standard seems to require the test a second time: it says
> >quite clearly that "If the else part of the selection statement
> >is present and the condition yields false, the second
> >substatement is executed."  I suspect that this is not
> >intentional (nor the intent); this would require that the
> >compiler implement "if (x) a ; else b;" as "if (x) a; if(!x) b;"
> >(I'm pretty sure that no compiler does this, and that if the if
> >statement is not entered via the if, execution will continue
> >until the end of whichever part is entered, and then skip the
> >other part.)

> We're probably OT from the OPs question,

Very.  I've cross-posted to comp.std.c++, and set follow-ups
there, since that's really where the discussion belongs.  (It's
something the standard should probably address, so that
implementors know what is required, but that no reasonable
programmer should be concerned with, since such cases won't
appear in his code.)

> but I'm
> unclear what you mean.  Do you mean the words should have
> used "otherwise" or something like that (myself, now that
> I read the words, I'd have preferred "only" or something like
> that too probably as well as otherwise).

To tell the truth, I'm not too sure myself.  The problem is
trying to figure out what should happen, according to the
standard, if you enter the if statement by jumping over the
evaluation of the condition.  The words I quoted could be taken
to suggest that on encountering the else, the condition must be
evaluated in order to determine whether the else part is to be
executed or not.  (Note that I'm quite sure that this is not
the intent.)  Something should be said to make it clear that 1)
the condition is only evaluated when the statement is entered
from the top, and 2) EITHER when the execution encounters the
else part (because it is executing in the if part), it skips it,
OR entering an if statement other than from the top is undefined
behavior.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <james.kanze@gmail.com>
Date: Sun, 15 Apr 2007 18:51:54 CST
Raw View
On Apr 15, 6:48 pm, Robert Mabee <rma...@comcast.net> wrote:
> James Kanze wrote:
> > The problem is
> > trying to figure out what should happen, according to the
> > standard, if you enter the if statement by jumping over the
> > evaluation of the condition.  The words I quoted could be taken
> > to suggest that on encountering the else, the condition must be
> > evaluated in order to determine whether the else part is to be
> > executed or not.

> It should be sufficient to notice that the condition expression can
> not in general be evaluated again, both because it may not be idempotent
> and because (in the case that the if-true statement was executed) the
> values referenced in the condition may have changed.

And most of all, of course, because it might have observable
behavior.  Good point.  The conditional may not be evaluated
twice.  But that still doesn't answer the question.  The
standard says that the else part is executed if the condition is
false.  If I write something like:

    bool c = false ;
    goto toto ;
    if ( c ) {
toto:
        stmt1 ;
    } else {
        stmt2 ;
    }

what should happen?  The condition is false; should the else
part be executed.

> Therefore the
> only possible interpretation is that the condition result is effectively
> preserved.

How do you preserve it in the above.  It hasn't ever been
evaluated.

> Is the issue whether a compiler could use an actual variable for the
> condition result, and neglect to set the variable on jumping into the
> if, and still claim conformance because this is undefined behavior?

The original issue was in code something like (from memory):

    void
    foo( bool b )
    {
        switch (1) {
            if ( b ) {
        case 1:
                std::cout << "1 " ;
            } else {
        case 2:
                std::cout << "2 " ;
            }
        }
    }

    int
    main()
    {
        foo( false ) ;
        foo( true ) ;
        std::cout << '\n' ;
        return 0 ;
    }

Different compilers (and different versions of the same
compiler) were doing different things.  One compiler, in
particular, output "1 2 1 2" (whereas most others output "1 1").

Given the language in the standard, I not sure I can say that
this compiler wrong.

--
James Kanze (Gabi Software)            email: james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <james.kanze@gmail.com>
Date: Mon, 16 Apr 2007 03:39:02 CST
Raw View
On Apr 16, 10:00 am, gre...@pacbell.net (Greg Herlihy) wrote:
> On Apr 15, 5:51 pm, "James Kanze" <james.ka...@gmail.com> wrote:

> >  If I write something like:

> >     bool c = false ;
> >     goto toto ;
> >     if ( c ) {
> > toto:
> >         stmt1 ;
> >     } else {
> >         stmt2 ;
> >     }

> > what should happen?  The condition is false; should the else
> > part be executed.

> No. The program above would have to execute the if-statement with a
> condition that yields false in order to transfer control to the
> if-statement's associated "else" clause.

There's no "transfer" of control to the else part.  It's what
comes after the if part.  The standard says that it shouldn't be
executed if the condition is true.  The standard doesn't say
anything else.

> But a goto statement in the above program bypasses the
> if-statement - thereby preventing the if-statement from
> executing at all.

The problem is not that it bypassed the if-statement.  The
problem is that it jumped into the middle of the if-statement.
And that the standard doesn't seem to say anything about this
case.

> So the if-statement has no opportunity to evaluate its
> condition - or to to transfer control to its associated else sub-statement -
> simply by virtue of the fact that the if-statement itself is never executed.

Where in the standard does it say anything about the else
statement in the case where the condition is not evaluated?
That's what I'm looking for.

> > > Therefore the
> > > only possible interpretation is that the condition result is effectively
> > > preserved.

> > How do you preserve it in the above.  It hasn't ever been
> > evaluated.

> Exactly. Since the if-statement is not executed, the if-statement selects
> neither of its sub-statements for execution.

So both get executed?  Or neither?  Or...?

> In fact, it follows that the
> only way for a C++ program to execute either sub-statment associate with an
> unexecuted if-statement, is for the program to execute a goto statement that
> transfers control into one of the sub-statement blocks directly.

> > The original issue was in code something like (from memory):

> >     void
> >     foo( bool b )
> >     {
> >         switch (1) {
> >             if ( b ) {
> >         case 1:
> >                 std::cout << "1 " ;
> >             } else {
> >         case 2:
> >                 std::cout << "2 " ;
> >             }
> >         }
> >     }

> >     int
> >     main()
> >     {
> >         foo( false ) ;
> >         foo( true ) ;
> >         std::cout << '\n' ;
> >         return 0 ;
> >     }

> > Different compilers (and different versions of the same
> > compiler) were doing different things.  One compiler, in
> > particular, output "1 2 1 2" (whereas most others output "1 1").

> "1 1" is the expected output.

That's what I would expect, too.  Based on what I know (or
thought I knew) about how if statements were implemented.  When
I tried to find support for this in the standard, I failed.

One could argue undefined behavior, because the standard doesn't
specify what the behavior should be.  If this is what was
intended, however, I'd really prefer that the standard say it
explicitly.  I'd also be interested in hearing from someone who
actually knows what was intended; who was present when the
current wording was formulated, and can state whether the case
was considered or not, and what the feeling was at the time.

Actually, I think I have an answer there.  The C99 standard
states explicitly that "If the first substatement is reached via
a label, the second substatement is not executed."  From memory,
I don't think that this was present in C90; I think that C++
simply adopted the C90 wording literally here.  If so, this
statement in C99 is probably the result of a clarification, and
is meant to express the original intent.  And the C++ standard
should follow suite.  (Should I repost in the form of a defect
report.  Or could this just be considered editorial, a
clarification based on the current C standard?)

> It is not possible for the program to execute
> the else clause (that would output "2") because a) the case 2 branch of the
> switch statement is never equal to the value that the switch-statement's
> condition yields, and b) no label is present within the else clause that
> would permit a goto statement to transfer control into the else block
> directly.

That's what I would have thought (that it is not possible).
Until I actually encountered a compiler which did so.

> > Given the language in the standard, I not sure I can say that
> > this compiler wrong.

> I think that the current language in the Standard is enough to define the
> correct behavior.

If one accepts that there is no defect, then the only possible
interpretation is undefined behavior, since the standard doesn't
say what the behavior should be.  Given the clarification in the
C standard, this would seem a gratuous difference between C and
C++.

> And to avoid making a change to the (normative) text that
> may be interpreted as a change in the Standard that could affect the
> behavior of existing C++ programs, I would recommend adding an example
> instead. In particular, I would suggest an example that illustrates a goto
> statement that transfers control into the first substatement of an
> if-statement. The purpose of this example would be to show that the
> else-clause is not executed under such circumstances:

>    [Example:
>         int x(1);

>         goto label1:
>         if (x == 0) {
>         label1:
>             x = 2;
>         }
>         else {
>             x = 3;
>         }
>         ... // x has the value 2
>     --end example]

So you think that adding 10 lines of non-normative text is
better than a single line of normative text, lifted directly
from the C standard.

Had I seen the text in C99 before posting, I would simply have
posted it as a defect report.  Without the text in C99, some
discussion seemed in order, as the most obvious interpretation
of the current standard is undefined behavior, and I had my
doubts as to whether that was really the intent.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]