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

K

Keith Thompson

BartC said:
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 ...

gcc supports nested functions as an extension, which strike me as a
cleaner way to do the same thing. The only difference would be that a
goto can't (as far as I know) jump from one function to another, even if
one is nested in the other, but I don't think that's a disadvantage.
 
K

Keith Thompson

(e-mail address removed) writes: [...]
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.

Thanks. I understood all your points except this one.
"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)"

How can it be helpful? what are the comparative limitations of each
approach?

It can make debugging easier. You can print the value of the state
variable on each iteration of the loop, either by setting a single
breakpoint or by adding a single printf() call. If you want to trace
every state transition in an FSM implemented with gotos, you have to add
code to every state.
 
K

Keith Thompson

James Kuyper said:
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.

Though C has permitted mixed declarations and statements since C99, it
still doesn't permit labels on declarations. This:

label: int i = 0;

is a syntax error. (I just ran into this the other day.)

You can just add a null statement:

label:; int i = 0;
 
G

glen herrmannsfeldt

Keith Thompson said:
(snip on Algol-68 feature)
gcc supports nested functions as an extension, which strike me as a
cleaner way to do the same thing. The only difference would be that a
goto can't (as far as I know) jump from one function to another, even if
one is nested in the other, but I don't think that's a disadvantage.

Pascal and PL/I allow GOTO out of internal functions, but not in.
In PL/I, you can do it with label variables.

C has longjmp() if you really want to do it.

-- glen
 
J

James Kuyper

Though C has permitted mixed declarations and statements since C99, it
still doesn't permit labels on declarations. This:

label: int i = 0;

is a syntax error. (I just ran into this the other day.)

You can just add a null statement:

label:; int i = 0;

That's what I actually meant, though I didn't say it quite right.
 
L

Lowell Gilbert

Ben Bacarisse said:
BartC said:
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.

More than likely; you'd just have a row of labels, and perhaps use it
directly as in goto (L1,L2,L3)[J].

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];

But that's just a funtion table, which is
even more common in these types of languages...
 
R

rivkaumiller

Keith Thompson said:
(e-mail address removed) writes:
In crux, the question is if I can use a switch-case's case-colon as a
label for goto or not?

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:

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.

There is a phenomenal amount of context in this thread, could you just
give a 10 sentence summary of the consensus - if one exists?
It's a shame the committee never took up computed gotos. For complex state

machines you often need to jump around. Sure, you can set the next state and

break out of the switch statement. But often times code will be nested

inside loops, so you need to use a goto, anyhow, to break out. And that goto

often takes you back to the _top_ of some outer loop.



Plus, if you care about performance, you want to try to thread your

instructions to avoid the loop conditional. I suppose it's possible with

switch statements, as long as your compiler is smart enough, but computed

gotos make it so much easier.



I've had some success with macro solutions which hide two

implementations--one using switch and another computed gotos.

Could you or someone else give a real example?
With GCC and

clang computed goto machines are always significantly faster. (And I never

use GCC's recommendation of storing label offsets, because that's a gigantic

pain in the butt--impossible if you generate cases or labels with

__LINE__--and in the age of C++ nobody will notice the insignicant link-time

costs.)

Again, could you or someone else give a real example?
 
R

rivkaumiller

Keith Thompson said:
(e-mail address removed) writes:
In crux, the question is if I can use a switch-case's case-colon as a
label for goto or not?

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:

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.

There is a phenomenal amount of content in this thread, could you just give a 10 sentence summary of the consensus - if one exists?

Could you reword and expand claims in your post below by real examples where I indicate a need for clarity?
It's a shame the committee never took up computed gotos. For complex state

machines you often need to jump around. Sure, you can set the next state and

break out of the switch statement. But often times code will be nested

inside loops, so you need to use a goto, anyhow, to break out. And that goto

often takes you back to the _top_ of some outer loop.



Plus, if you care about performance, you want to try to thread your

instructions to avoid the loop conditional. I suppose it's possible with

switch statements, as long as your compiler is smart enough, but computed

gotos make it so much easier.



I've had some success with macro solutions which hide two

implementations--one using switch and another computed gotos.

Could you or someone else give a real example?
With GCC and

clang computed goto machines are always significantly faster. (And I never

use GCC's recommendation of storing label offsets, because that's a gigantic

pain in the butt--impossible if you generate cases or labels with

__LINE__--and in the age of C++ nobody will notice the insignicant link-time

costs.)

Again, could you or someone else give a real example?
 
J

JohnF

James Kuyper said:
"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.

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,

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.

Thanks for additional clarification, James (and for not
pointing out how my i++ was pretty darned useless:).
That seems to just emphasize the earlier judgement that
this kind of branch is more than likely a bad thing.
 
B

Ben Bacarisse

Lowell Gilbert said:
Ben Bacarisse said:
BartC said:
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.

More than likely; you'd just have a row of labels, and perhaps use it
directly as in goto (L1,L2,L3)[J].

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];

But that's just a funtion table, which is
even more common in these types of languages...

Yes, it looks like a function table but it's not quite the same as one.
For one thing, the values don't actually derive from functions, and they
also become invalid if the table is returned form the function that
contains the labels.
 
B

Ben Bacarisse

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.

There's two kinds of "computed" here: the index into a list of labels
and the label list itself. In Fortran, the list was static --
effectively a literal array -- and only the index is "computed". That
kind of computed goto can be done in C:

switch (J) { case 1: goto L1; case 2: goto L2; ... }

It's clumsy to write, but the functionality is there (though I'm blessed
never to have see it used!).

In BCPL and in Algol 68 (and C with gcc's extensions) you can compute
with the labels themselves, though there may be very severe
restrictions on exactly what you can do. Once you can play with the
value of a label in some way (however limited) you get more
opportunities for "fun".
 
T

Tim Rentsch

James Kuyper said:
"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.

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,

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.

This analysis is right for C90 and C99. In C11, the access
is i is simply undefined behavior, under 6.3.2.1 p2.
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top