24

I want to declare an array of "jumplabels".

Then I want to jump to a "jumplabel" in this array.

But I have not any idea how to do this.

It should look like the following code:

function()
{
    "gotolabel" s[3];
    s[0] = s0;
    s[1] = s1;
    s[2] = s2;

    s0:
    ....
    goto s[v];

    s1:
    ....
    goto s[v];

    s2:
    ....
    goto s[v];
}

Does anyone have a idea how to perform this?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 3
    If it is a homework I don't recommend you to go this way - your professor wouldn't like it. – qrdl Jun 02 '09 at 08:52
  • 2
    no it isn't, I'm seventeen and trying to write a simple, fast tokenizer. I thought about speeding it up this way. –  Jun 02 '09 at 10:37
  • 2
    You mention in comments below that there may be 2**16 cases. Will this be the norm? If so, it changes the problem dramatically. –  Jun 02 '09 at 12:16
  • 4
    @youllknow: Are you sure this is what needs speeding up? Have you profiled your code? – Greg D Jun 02 '09 at 12:59
  • 3
    2^16 cases and you want to maintain this as a single straight block of code... You will get into trouble earlier than later when you want to modify anything. The code will be unmaintainable, and with just a couple of lines per case plus label and goto, you are talking of a 250 KLOC function. Start with code that works and then measure and optimize if needed. – David Rodríguez - dribeas Jun 02 '09 at 13:25
  • i don't need need to modify the code... a programm will compute it! The switch statement would have 2^16 cases, but a lot of them will do the same. It's no problem to implement with function pointer, but I wanted to TRY something faster! I really like experimenting! –  Jun 02 '09 at 17:33
  • 1
    Function pointers aren't slow. – Greg D Jun 04 '09 at 14:25

11 Answers11

44

It is possible with GCC feature known as "labels as values".

void *s[3] = {&&s0, &&s1, &&s2};

if (n >= 0 && n <=2)
    goto *s[n];

s0:
...
s1:
...
s2:
...

It works only with GCC!

qrdl
  • 34,062
  • 14
  • 56
  • 86
17

goto needs a compile-time label.

From this example it seems that you are implementing some kind of state machine. Most commonly they are implemented as a switch-case construct:

while (!finished) switch (state) {
  case s0:
  /* ... */
  state = newstate;
  break;

  /* ... */
}

If you need it to be more dynamic, use an array of function pointers.

laalto
  • 150,114
  • 66
  • 286
  • 303
  • 1
    Worth noting that `switch` is for compact case expressions is implemented with a jump table which is basically the same as an array or labels: http://stackoverflow.com/questions/14067547/how-switch-case-statement-implemented-or-works-internally – Ciro Santilli OurBigBook.com Jun 24 '15 at 10:30
  • +1 for "use an array of function pointers". or nowadays, an array of `std::function` storing lambdas could provide much more compact syntax. – underscore_d Jul 02 '16 at 18:50
12

There's no direct way to store code addresses to jump to in C. How about using switch.

#define jump(x)  do{ label=x; goto jump_target; }while(0)
int label=START;
jump_target:
switch(label)
{
    case START:
        /* ... */
    case LABEL_A:
        /* ... */
}

You can find similar code produced by every stack-less parser / state machine generator. Such code is not easy to follow so unless it is generated code or your problem is most easily described by state machine I would recommend not do this.

lispmachine
  • 4,407
  • 1
  • 22
  • 31
8

could you use function pointers instead of goto?

That way you can create an array of functions to call and call the appropriate one.

Rik Heywood
  • 13,816
  • 9
  • 61
  • 81
  • 1
    I know that it can me made with function pointers. But this would be slow, because I would have to call a function to often. I think the call-overhead would be to big! –  Jun 02 '09 at 10:29
  • 7
    @youllknow: The words "I think" in the above comment tell me that you're in real danger of falling for "premature optimization". The first goal should be to start with a clear "working" solution and then optimize it as necessary. Consider this: only 1 compiler has this feature as an extension, however, every C/C++ compiler uses state machines. If this is the best way to go about solving this problem, why doesn't every compiler have this feature? – Richard Corden Jun 02 '09 at 12:40
  • @Richard Corden: So you think the speed improvment is very low? I thought about the function pointer array as well. The problem is the functions would be called very often, but they do only little things. So I thought that calling the funtion might be more expensive than what the function does. I am able to implement my problem with function pointers, but I thought that I can speed it up with the "goto-method". What's your opionion? –  Jun 02 '09 at 13:48
  • 2
    @youllknow: A function call is very cheap: it's not much more expensive than a goto and has far fewer problems. Remember that the compiler is always better than you at optimizing. – greyfade Jun 03 '09 at 02:53
  • 2
    @youllknow: There is going to be a performance difference, but you need to keep in mind the trade off between "clarity" and "performance". If it were me, my first "performance" tweak would be to see can I use some combination of templates + inline functions and so allow the compiler to optimize as much as possible. BTW, this may already exist in the boost spirit library: http://www.boost.org/doc/libs/1_39_0/libs/statechart/doc/index.html. – Richard Corden Jun 03 '09 at 07:52
6

In plain standard C, this not possible as far as I know. There is however an extension in the GCC compiler, documented here, that makes this possible.

The extension introduces the new operator &&, to take the address of a label, which can then be used with the goto statement.

unwind
  • 391,730
  • 64
  • 469
  • 606
5

That's what switch statements are for.

switch (var)
{
case 0:
    /* ... */
    break;
case 1:
    /* ... */
    break;
default:
    /* ... */
    break;  /* not necessary here */
}

Note that it's not necessarily translated into a jump table by the compiler.

If you really want to build the jump table yourself, you could use a function pointers array.

Bastien Léonard
  • 60,478
  • 20
  • 78
  • 95
  • It was only an simple example... In my option switch is to slow if I have 2^16 cases? Isn't it? –  Jun 02 '09 at 10:27
  • 4
    @youllknow: often good compilers will optimize a dense switch into a jump table for you. So no, switches aren't necessarily slow. – user83255 Jun 07 '09 at 12:28
4

You might want to look at setjmp/longjmp.

Paul Mitchell
  • 3,241
  • 1
  • 19
  • 22
2

You can't do it with a goto - the labels have to be identifiers, not variables or constants. I can't see why you would not want to use a switch here - it will likely be just as efficient, if that is what is concerning you.

  • Yes, it's all about speed! Is it even likely just as fast if there are 2^16 cases? –  Jun 02 '09 at 10:30
  • 3
    @youllknow: a switch should be as fast as a computed goto, as the compiler should create a jump table as well – Christoph Jun 02 '09 at 11:53
  • If youllknow really wants to have 65K jump targets I wouldn't be surprised if most compilers would fall over trying to compile a switch with that many cases. – Michael Burr Jun 03 '09 at 06:01
1

Optimizing compilers (including GCC) will compile a switch statement into a jump table (making a switch statement exactly as fast as the thing you're trying to construct) IF the following conditions are met:

Your switch cases (state numbers) start at zero.

Your switch cases are strictly increasing.

You don't skip any integers in your switch cases.

There are enough cases that a jump table is actually faster (a couple dozen compare-and-gotos in the checking-each-case method of dealing with switch statements is actually faster than a jump table.)

This has the advantage of allowing you to write your code in standard C instead of relying on a compiler extension. It will work just as fast in GCC. It will also work just as fast in most optimizing compilers (I know the Intel compiler does it; not sure about Microsoft stuff). And it will work, although slower, on any compiler.

1

For a simple answer, instead of forcing compilers to do real stupid stuff, learn good programming practices.

BubbaT
  • 1,810
  • 4
  • 21
  • 24
  • 12
    Without knowing the context how can you judge this as "real stupid stuff"? Blindly following rules (such as "goto is evil") is good for beginners. Experienced programmers know where to make an exception. – lispmachine Jun 02 '09 at 09:02
  • 1
    After consideration it's unlikely that experienced programmer would ask such question but this is impolite to prejudge. – lispmachine Jun 02 '09 at 09:08
1

Tokenizer? This looks like what gperf was made for. No really, take a look at it.

Thomas
  • 4,208
  • 2
  • 29
  • 31