Can I jump to a case inside a switch using goto?

Discussion in 'C Programming' started by rivkaumiller, Apr 3, 2014.

  1. rivkaumiller

    rivkaumiller Guest

    while((c=getchar())!=EOF){

    switch(flower){
    case rose:
    switch(color){
    case white:
    // do something 1
    case pink:
    // do something 2
    ...
    }
    case lily:
    switch(color){
    case white:
    // do something 1
    case pink:
    // do something 2

    ...
    }
    ...
    case unique:
    // do something 3
    ...
    }
    }


    basically, I can write the above statement completely using
    if(flower==rose) goto
    if(color==white) goto

    type statements.

    unfortunately, some of the flowers have strange names such as the ascii value of '/' or other characters like '%' and so on so switch-case gives me brevity.

    However, inside switch-case I want to jump to certain cases before breaking to the end.

    for example from (rose,pink) I may want to goto unique: . Can I do that by a

    goto unique: ?

    Note its a unique label. It is also an alias for another case where I want to do something unique before going into the while cycle which will read a char and then break down to the end.

    I have a few choices.

    One is that I have that label outside both of the switch-cases and its not a switch case label. There, if I want to fall through the cases below, I will have to use goto end: for all of them.

    However, I can also put some dummy labels with break in the outermost switch-case and use them as labels.

    In crux, the question is if I can use a switch-case's case-colon as a label for goto or not?

    If so, then can I use a case like '%'-colon as a case for goto using

    goto '%' ?

    Thanks
     
    rivkaumiller, Apr 3, 2014
    #1
    1. Advertisements

  2. [snip]

    No, you can't. The target of a goto must be a the name of a label
    defined with the "identifer ": syntax; a case label doesn't qualify.

    You can always add labels as needed:

    switch (...) {
    case 0:
    L0:
    /* ... */
    break;
    case 1:
    L1:
    /* ... */
    break;
    /* ... */
    default:
    Default:
    /* ... */
    break;
    }
    /* ... */
    goto L1;
    goto L2;
    goto Default;

    But I'd really advise you to rethink your design. Careful use of goto
    statements, usually to a pointer *later* in the code, can be useful for
    error handling and for breaking out of nested loops, but heavy use of
    gotos can easily result in spaghetti code.

    If you're implementing a finite state machine, I suggest either a switch
    statement in a loop, where the switch executes some chunk of code
    depending on the current state, *or* a sequence of labelled blocks with
    gotos. (I personally prefer the former; for one thing, encoding the
    current state in a variable rather than having it be implicit in the
    current location in the program can be helpful). Mixing case labels and
    gotos could easily get out of control.
     
    Keith Thompson, Apr 3, 2014
    #2
    1. Advertisements

  3. rivkaumiller

    rivkaumiller Guest

    Wil... , you seem to cover a number of topics rapidly in your reply. Unfortunately, google does not give an option to email you either.

    What is computed goto and which languages have it?
    I wanted to see some examples.
    Again some concrete examples would clarify the vision in your mind.
    specific macros and the example?
    Again, more writing is needed to clarify your point and generate benefit.
     
    rivkaumiller, Apr 3, 2014
    #3
  4. rivkaumiller

    rivkaumiller Guest

    Thanks. I understood all your points except this one.

    "for one thing, encoding the
    How can it be helpful? what are the comparative limitations of each approach?

    Second, can you try to make sense of the points made by wil... , the next poster?
     
    rivkaumiller, Apr 3, 2014
    #4
  5. rivkaumiller

    Stefan Ram Guest

    #include <stdio.h>

    int main()
    { int pc = 3;
    #define GOTO(x) pc=x;break
    while( 1 )switch( pc )
    { case 2: puts( "2:" ); goto out;
    case 3: puts( "3:" ); GOTO( 2 ); }
    out:; }
     
    Stefan Ram, Apr 3, 2014
    #5
  6. rivkaumiller

    JohnF Guest

    Yeah, that's for sure. But just curious -- if one
    of those goto's takes execution from outside the
    switch's {...} to inside it, will the subsequent
    break understand the scope, i.e., where the program
    counter should go next? And is that behavior mandated
    by standard?
     
    JohnF, Apr 3, 2014
    #6
  7. rivkaumiller

    Stefan Ram Guest

    #include <stdio.h>

    int main()
    { for( int pc = 3; pc; )switch( pc )
    { case 2: puts( "2:" ); pc = 0; break;
    case 3: puts( "3:" ); pc = 2; break; }}
     
    Stefan Ram, Apr 3, 2014
    #7
  8. rivkaumiller

    rivkaumiller Guest

    but you are going through the while loop head to do the GOTO.
    In my case, there is a getchar() there so an input stream has been consumed. You are not allowed to go through the loop head.
     
    rivkaumiller, Apr 3, 2014
    #8
  9. As far as I know, it started with Fortran I in 1956.

    GOTO (10, 20, 30, 40, 50, 60), J

    Goes to the first statement number if J is 1, the second if J is 2,
    and so on. In early Fortran (before 1977) it was undefined if J
    was less than 1 or greater than the number of labels. Many as an
    extension, and added in Fortran 77, if J is out of range, it goes
    to the following statement.

    Many BASIC systems implement computed GOTO as

    100 ON J GOTO 10, 20, 30, 40, 50, 60

    PL/I has LABEL variable arrays, which can either be initialized
    with the appropriate labels on the DECLARE, or by specifying an
    array element as a statement label. The latter doesn't look so
    different from switch/case.

    DCL X(5) LABEL INITIAL(ONE, TWO, THREE);

    or:

    DCL Y(5) LABEL;

    then label statements such as:

    Y(3): PUT LIST('Three');


    Then GOTO X(I); or GOTO Y(J); will go to the appropriate statement.

    I think ALGOL-68 has one, but I am not sure. The description is
    in its own language, and not so easy to figure out.

    As I happen to have a COBOL manual nearby, though haven't actually
    written any programs, it seems to have:

    GOTO labels DEPENDING ON variable.


    -- glen
     
    glen herrmannsfeldt, Apr 3, 2014
    #9
  10. rivkaumiller

    Stefan Ram Guest

    »ON J GOSUB 10, 20« in BASIC becomes »gosub[ j ]();« in C,
    where »gosub« is an array of function pointers.
     
    Stefan Ram, Apr 3, 2014
    #10
  11. Fortran has it.
    Minibasic http://sourceforge.net/directory/?q=minibasic also has it.

    You use integers for lablels, then goto x; is allowed, where x is an integer
    variable. In Minibasic, is was a simply a case of writing the parser as
    goto (expression) rather than goto (number). But I rather regret allowing it,
    because it made writing the optimised version of the interpreter a lot more
    difficult.

    Switch is a bit slow in a deeply nested loop. For example, when you're
    emulating a processor in C, you need to switch on the instruction. That's
    often the rate-limiting step in the program. A computed goto can often
    prove faster (shift the instruction up four bits, add to the base, jump,
    and make sure all your ops are exactly 16 instructions long).
     
    Malcolm McLean, Apr 3, 2014
    #11
  12. rivkaumiller

    BartC Guest

    So what's the difference between that, and:

    switch (J) {
    case 1:
    case 2:
    ....
    case 6:
    ?
    More than likely; you'd just have a row of labels, and perhaps use it
    directly as in goto (L1,L2,L3)[J].

    But it also has case in... out.
     
    BartC, Apr 3, 2014
    #12
  13. rivkaumiller

    BartC Guest

    Another way to share code between cases is to put it in functions.

    So if the code for unique is in dosomething3(), then from rose,pink you just
    call dosomething3(). No need for a goto.
     
    BartC, Apr 3, 2014
    #13
  14. Not exactly. A label evaluates to a procedure (of mode PROC VOID) so
    you can make a row of them, but you have to "call" the procedure, rather
    than use goto directly.

    [] PROC VOID labels = (L1, L2, L3);
    ...
    labels[j];
    or rather "case in ... out ... esac".
     
    Ben Bacarisse, Apr 3, 2014
    #14
  15. rivkaumiller

    Paul N Guest

    In BCPL, labels were numbers just like any other variable. So you could do:

    GOTO val -> lab1 , lab2

    to choose one of two targets ( -> is the BCPL equivalent of ? : )

    or you could use an array; or you could even do

    GOTO lab + 4

    if jumping to slightly after a label is your idea of fun.
     
    Paul N, Apr 3, 2014
    #15
  16. Note, incidentally, that you *can* implement computed goto in C - in fact,
    in entirely standard (on topic) C. The details of how to do it escape me
    at the moment, but it involves setjmp and longjmp. Basically, you set up
    an array of jmpbufs and then longjmp to the one you want. Somebody figured
    this out and explained it to me sometime back in the 80s.

    Perhaps someone here will take it on as a challenge...
     
    Kenny McCormack, Apr 3, 2014
    #16
  17. rivkaumiller

    BartC Guest

    I've just tried it, and you're right. But like this, it's not quite as
    succinct. (I base my own syntaxes on A68; with a dynamic language, I can
    actually write goto (L1,L2,L3)[J], but will also need goto labels[j] for a
    static one. In both cases though I insist on 'goto' to make it clear what
    this is.)

    But, the fact that A68 treats such a label as a kind of local proc name
    gives me an idea for an idea for a language feature that might help the OP
    (if it could somehow be implemented today in C).

    This is a lightweight call that would pass control to a labelled block
    somewhere in this function, just like goto, but then returns at the end of
    the block. Access to all local variables is maintained as normal.
    Encountering the block also executes it as normal:

    rose:
    dosomething2();
    gosub dosomething3; // use gosub rather than goto or ()
    ....
    unique:
    dosomething3:{
    .....
    }

    Well, it's an idea ...
     
    BartC, Apr 3, 2014
    #17
  18. rivkaumiller

    James Kuyper Guest

    "A break statement terminates execution of the smallest enclosing switch
    or iteration statement." (6.8.6.3p2) It doesn't matter how execution of
    the program reached the break statement, the only thing that matters is
    the location of the break statement.
     
    James Kuyper, Apr 3, 2014
    #18
  19. rivkaumiller

    JohnF Guest

    Thanks, James. I hadn't been aware of that before.
    But after posting, I realized I hadn't exactly asked
    the complete question that bothered me. Consider the
    following snippet,
    char label[100] = "printed during loop";
    int nloop = 0;
    while ( 1 ) {
    int i = 0;
    entry_pt:
    i++;
    printf("%s: i=%d\n",label,i);
    if ( i >= 10 ) break;
    } /* --- continue --- */
    if ( ++nloop < 2 ) {
    strcpy(label,"printed after goto");
    goto entry_pt; }
    Okay, so you know the question: what's the
    value of i "printed after goto"? And what's the
    general rule about that? And how portable is it?
    Thanks,
     
    JohnF, Apr 3, 2014
    #19
  20. rivkaumiller

    James Kuyper Guest

    The goto statement enters the block containing the definition of 'i', so
    a new instance of i is created with an indeterminate value. The goto
    skips the initialization of i, which therefore doesn't occur. At least,
    that's how I interpret 6.2.4p6. If the indeterminate value of i is
    either a trap representation or INT_MAX, the i++ expression renders the
    behavior of the entire program undefined. Otherwise, the value of 'i' is
    unspecified, but valid, after the jump. In that case, the increment
    occurs normally, and INT_MIN < i && i <= INT_MAX at the time of the
    printf() call.

    If you want i to have a well-defined value after the goto, move the
    label before the declaration of i, or make i static.
     
    James Kuyper, Apr 3, 2014
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.